server-ts: Convert routes/api/revisions

This commit is contained in:
Elian Doran 2024-04-06 22:32:03 +03:00
parent 4ab6f159e5
commit 6265aa99d3
No known key found for this signature in database
4 changed files with 75 additions and 39 deletions

View File

@ -164,6 +164,14 @@ export default class Becca {
return row ? new BRevision(row) : null; return row ? new BRevision(row) : null;
} }
getRevisionOrThrow(revisionId: string): BRevision {
const revision = this.getRevision(revisionId);
if (!revision) {
throw new NotFoundError(`Revision '${revisionId}' has not been found.`);
}
return revision;
}
getAttachment(attachmentId: string, opts: AttachmentOpts = {}): BAttachment | null { getAttachment(attachmentId: string, opts: AttachmentOpts = {}): BAttachment | null {
opts.includeContentLength = !!opts.includeContentLength; opts.includeContentLength = !!opts.includeContentLength;
@ -249,7 +257,7 @@ export default class Becca {
return rows.map(row => new BRecentNote(row)); return rows.map(row => new BRecentNote(row));
} }
getRevisionsFromQuery(query: string, params = []): BRevision[] { getRevisionsFromQuery(query: string, params: string[] = []): BRevision[] {
const rows = sql.getRows<RevisionRow>(query, params); const rows = sql.getRows<RevisionRow>(query, params);
const BRevision = require('./entities/brevision'); // avoiding circular dependency problems const BRevision = require('./entities/brevision'); // avoiding circular dependency problems
@ -292,3 +300,17 @@ export interface ConstructorData<T extends AbstractBeccaEntity<T>> {
entityName: string; entityName: string;
hashedProperties: (keyof T)[]; hashedProperties: (keyof T)[];
} }
export interface NotePojo {
noteId: string;
title?: string;
isProtected?: boolean;
type: string;
mime: string;
blobId?: string;
isDeleted: boolean;
dateCreated?: string;
dateModified?: string;
utcDateCreated: string;
utcDateModified?: string;
}

View File

@ -15,6 +15,7 @@ import eventService = require('../../services/events');
import { AttachmentRow, NoteRow, NoteType, RevisionRow } from './rows'; import { AttachmentRow, NoteRow, NoteType, RevisionRow } from './rows';
import BBranch = require('./bbranch'); import BBranch = require('./bbranch');
import BAttribute = require('./battribute'); import BAttribute = require('./battribute');
import { NotePojo } from '../becca-interface';
dayjs.extend(utc); dayjs.extend(utc);
const LABEL = 'label'; const LABEL = 'label';
@ -1679,7 +1680,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
this.utcDateModified = dateUtils.utcNowDateTime(); this.utcDateModified = dateUtils.utcNowDateTime();
} }
getPojo() { getPojo(): NotePojo {
return { return {
noteId: this.noteId, noteId: this.noteId,
title: this.title || undefined, title: this.title || undefined,

View File

@ -40,7 +40,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
utcDateLastEdited?: string; utcDateLastEdited?: string;
utcDateCreated!: string; utcDateCreated!: string;
contentLength?: number; contentLength?: number;
content?: string; content?: string | Buffer;
constructor(row: RevisionRow, titleDecrypted = false) { constructor(row: RevisionRow, titleDecrypted = false) {
super(); super();
@ -91,9 +91,8 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
* *
* This is the same approach as is used for Note's content. * This is the same approach as is used for Note's content.
*/ */
// TODO: initial declaration included Buffer, but everywhere it's treated as a string. getContent(): string | Buffer {
getContent(): string { return this._getContent();
return this._getContent() as string;
} }
/** /**
@ -101,7 +100,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
getJsonContent(): {} | null { getJsonContent(): {} | null {
const content = this.getContent(); const content = this.getContent();
if (!content || !content.trim()) { if (!content || typeof content !== "string" || !content.trim()) {
return null; return null;
} }

View File

@ -1,22 +1,38 @@
"use strict"; "use strict";
const beccaService = require('../../becca/becca_service'); import beccaService = require('../../becca/becca_service');
const revisionService = require('../../services/revisions'); import revisionService = require('../../services/revisions');
const utils = require('../../services/utils'); import utils = require('../../services/utils');
const sql = require('../../services/sql'); import sql = require('../../services/sql');
const cls = require('../../services/cls'); import cls = require('../../services/cls');
const path = require('path'); import path = require('path');
const becca = require('../../becca/becca'); import becca = require('../../becca/becca');
const blobService = require('../../services/blob'); import blobService = require('../../services/blob');
const eraseService = require("../../services/erase"); import eraseService = require("../../services/erase");
import { Request, Response } from 'express';
import BRevision = require('../../becca/entities/brevision');
import BNote = require('../../becca/entities/bnote');
import { NotePojo } from '../../becca/becca-interface';
function getRevisionBlob(req) { interface NotePath {
noteId: string;
branchId?: string;
title: string;
notePath: string[];
path: string;
}
interface NotePojoWithNotePath extends NotePojo {
notePath?: string[] | null;
}
function getRevisionBlob(req: Request) {
const preview = req.query.preview === 'true'; const preview = req.query.preview === 'true';
return blobService.getBlobPojo('revisions', req.params.revisionId, { preview }); return blobService.getBlobPojo('revisions', req.params.revisionId, { preview });
} }
function getRevisions(req) { function getRevisions(req: Request) {
return becca.getRevisionsFromQuery(` return becca.getRevisionsFromQuery(`
SELECT revisions.*, SELECT revisions.*,
LENGTH(blobs.content) AS contentLength LENGTH(blobs.content) AS contentLength
@ -26,12 +42,12 @@ function getRevisions(req) {
ORDER BY revisions.utcDateCreated DESC`, [req.params.noteId]); ORDER BY revisions.utcDateCreated DESC`, [req.params.noteId]);
} }
function getRevision(req) { function getRevision(req: Request) {
const revision = becca.getRevision(req.params.revisionId); const revision = becca.getRevisionOrThrow(req.params.revisionId);
if (revision.type === 'file') { if (revision.type === 'file') {
if (revision.hasStringContent()) { if (revision.hasStringContent()) {
revision.content = revision.getContent().substr(0, 10000); revision.content = (revision.getContent() as string).substr(0, 10000);
} }
} }
else { else {
@ -45,11 +61,7 @@ function getRevision(req) {
return revision; return revision;
} }
/** function getRevisionFilename(revision: BRevision) {
* @param {BRevision} revision
* @returns {string}
*/
function getRevisionFilename(revision) {
let filename = utils.formatDownloadTitle(revision.title, revision.type, revision.mime); let filename = utils.formatDownloadTitle(revision.title, revision.type, revision.mime);
const extension = path.extname(filename); const extension = path.extname(filename);
@ -68,8 +80,8 @@ function getRevisionFilename(revision) {
return filename; return filename;
} }
function downloadRevision(req, res) { function downloadRevision(req: Request, res: Response) {
const revision = becca.getRevision(req.params.revisionId); const revision = becca.getRevisionOrThrow(req.params.revisionId);
if (!revision.isContentAvailable()) { if (!revision.isContentAvailable()) {
return res.setHeader("Content-Type", "text/plain") return res.setHeader("Content-Type", "text/plain")
@ -85,18 +97,18 @@ function downloadRevision(req, res) {
res.send(revision.getContent()); res.send(revision.getContent());
} }
function eraseAllRevisions(req) { function eraseAllRevisions(req: Request) {
const revisionIdsToErase = sql.getColumn('SELECT revisionId FROM revisions WHERE noteId = ?', const revisionIdsToErase = sql.getColumn<string>('SELECT revisionId FROM revisions WHERE noteId = ?',
[req.params.noteId]); [req.params.noteId]);
eraseService.eraseRevisions(revisionIdsToErase); eraseService.eraseRevisions(revisionIdsToErase);
} }
function eraseRevision(req) { function eraseRevision(req: Request) {
eraseService.eraseRevisions([req.params.revisionId]); eraseService.eraseRevisions([req.params.revisionId]);
} }
function restoreRevision(req) { function restoreRevision(req: Request) {
const revision = becca.getRevision(req.params.revisionId); const revision = becca.getRevision(req.params.revisionId);
if (revision) { if (revision) {
@ -117,8 +129,10 @@ function restoreRevision(req) {
noteAttachment.setContent(revisionAttachment.getContent(), { forceSave: true }); noteAttachment.setContent(revisionAttachment.getContent(), { forceSave: true });
// content is rewritten to point to the restored revision attachments // content is rewritten to point to the restored revision attachments
if (typeof revisionContent === "string") {
revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`); revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`);
} }
}
note.title = revision.title; note.title = revision.title;
note.setContent(revisionContent, { forceSave: true }); note.setContent(revisionContent, { forceSave: true });
@ -126,8 +140,8 @@ function restoreRevision(req) {
} }
} }
function getEditedNotesOnDate(req) { function getEditedNotesOnDate(req: Request) {
const noteIds = sql.getColumn(` const noteIds = sql.getColumn<string>(`
SELECT notes.* SELECT notes.*
FROM notes FROM notes
WHERE noteId IN ( WHERE noteId IN (
@ -152,7 +166,7 @@ function getEditedNotesOnDate(req) {
return notes.map(note => { return notes.map(note => {
const notePath = getNotePathData(note); const notePath = getNotePathData(note);
const notePojo = note.getPojo(); const notePojo: NotePojoWithNotePath = note.getPojo();
notePojo.notePath = notePath ? notePath.notePath : null; notePojo.notePath = notePath ? notePath.notePath : null;
return notePojo; return notePojo;
@ -160,7 +174,7 @@ function getEditedNotesOnDate(req) {
} }
function getNotePathData(note) { function getNotePathData(note: BNote): NotePath | undefined {
const retPath = note.getBestNotePath(); const retPath = note.getBestNotePath();
if (retPath) { if (retPath) {
@ -173,7 +187,7 @@ function getNotePathData(note) {
} }
else { else {
const parentNote = note.parents[0]; const parentNote = note.parents[0];
branchId = becca.getBranchFromChildAndParent(note.noteId, parentNote.noteId).branchId; branchId = becca.getBranchFromChildAndParent(note.noteId, parentNote.noteId)?.branchId;
} }
return { return {
@ -186,7 +200,7 @@ function getNotePathData(note) {
} }
} }
module.exports = { export = {
getRevisionBlob, getRevisionBlob,
getRevisions, getRevisions,
getRevision, getRevision,