mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
Merge pull request #43 from TriliumNext/feature/typescript_backend_7
Convert backend to TypeScript (71% -> 80%)
This commit is contained in:
commit
98d12901a5
@ -161,6 +161,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;
|
||||||
|
|
||||||
@ -246,7 +254,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
|
||||||
@ -289,3 +297,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;
|
||||||
|
}
|
@ -26,8 +26,8 @@ interface ContentOpts {
|
|||||||
abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> {
|
abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> {
|
||||||
|
|
||||||
utcDateModified?: string;
|
utcDateModified?: string;
|
||||||
protected dateCreated?: string;
|
dateCreated?: string;
|
||||||
protected dateModified?: string;
|
dateModified?: string;
|
||||||
|
|
||||||
utcDateCreated!: string;
|
utcDateCreated!: string;
|
||||||
|
|
||||||
|
@ -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';
|
||||||
@ -222,7 +223,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Error in case of invalid JSON */
|
* @throws Error in case of invalid JSON */
|
||||||
getJsonContent(): {} | null {
|
getJsonContent(): any | null {
|
||||||
const content = this.getContent();
|
const content = this.getContent();
|
||||||
|
|
||||||
if (typeof content !== "string" || !content || !content.trim()) {
|
if (typeof content !== "string" || !content || !content.trim()) {
|
||||||
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,26 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const imageService = require('../../services/image');
|
import imageService = require('../../services/image');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
|
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
|
||||||
const fs = require('fs');
|
import fs = require('fs');
|
||||||
|
import { Request, Response } from 'express';
|
||||||
|
import BNote = require('../../becca/entities/bnote');
|
||||||
|
import BRevision = require('../../becca/entities/brevision');
|
||||||
|
|
||||||
function returnImageFromNote(req, res) {
|
function returnImageFromNote(req: Request, res: Response) {
|
||||||
const image = becca.getNote(req.params.noteId);
|
const image = becca.getNote(req.params.noteId);
|
||||||
|
|
||||||
return returnImageInt(image, res);
|
return returnImageInt(image, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
function returnImageFromRevision(req, res) {
|
function returnImageFromRevision(req: Request, res: Response) {
|
||||||
const image = becca.getRevision(req.params.revisionId);
|
const image = becca.getRevision(req.params.revisionId);
|
||||||
|
|
||||||
return returnImageInt(image, res);
|
return returnImageInt(image, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function returnImageInt(image: BNote | BRevision | null, res: Response) {
|
||||||
* @param {BNote|BRevision} image
|
|
||||||
* @param res
|
|
||||||
*/
|
|
||||||
function returnImageInt(image, res) {
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
res.set('Content-Type', 'image/png');
|
res.set('Content-Type', 'image/png');
|
||||||
return res.send(fs.readFileSync(`${RESOURCE_DIR}/db/image-deleted.png`));
|
return res.send(fs.readFileSync(`${RESOURCE_DIR}/db/image-deleted.png`));
|
||||||
@ -40,12 +39,13 @@ function returnImageInt(image, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSvgAttachment(image, res, attachmentName) {
|
function renderSvgAttachment(image: BNote | BRevision, res: Response, attachmentName: string) {
|
||||||
let svgString = '<svg/>'
|
let svgString = '<svg/>'
|
||||||
const attachment = image.getAttachmentByTitle(attachmentName);
|
const attachment = image.getAttachmentByTitle(attachmentName);
|
||||||
|
|
||||||
if (attachment) {
|
const content = attachment.getContent();
|
||||||
svgString = attachment.getContent();
|
if (attachment && typeof content === "string") {
|
||||||
|
svgString = content;
|
||||||
} else {
|
} else {
|
||||||
// backwards compatibility, before attachments, the SVG was stored in the main note content as a separate key
|
// backwards compatibility, before attachments, the SVG was stored in the main note content as a separate key
|
||||||
const contentSvg = image.getJsonContentSafely()?.svg;
|
const contentSvg = image.getJsonContentSafely()?.svg;
|
||||||
@ -62,7 +62,7 @@ function renderSvgAttachment(image, res, attachmentName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function returnAttachedImage(req, res) {
|
function returnAttachedImage(req: Request, res: Response) {
|
||||||
const attachment = becca.getAttachment(req.params.attachmentId);
|
const attachment = becca.getAttachment(req.params.attachmentId);
|
||||||
|
|
||||||
if (!attachment) {
|
if (!attachment) {
|
||||||
@ -81,9 +81,9 @@ function returnAttachedImage(req, res) {
|
|||||||
res.send(attachment.getContent());
|
res.send(attachment.getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateImage(req) {
|
function updateImage(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const {file} = req;
|
const {file} = (req as any);
|
||||||
|
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ function updateImage(req) {
|
|||||||
return { uploaded: true };
|
return { uploaded: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
returnImageFromNote,
|
returnImageFromNote,
|
||||||
returnImageFromRevision,
|
returnImageFromRevision,
|
||||||
returnAttachedImage,
|
returnAttachedImage,
|
@ -1,18 +1,20 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const enexImportService = require('../../services/import/enex');
|
import enexImportService = require('../../services/import/enex');
|
||||||
const opmlImportService = require('../../services/import/opml');
|
import opmlImportService = require('../../services/import/opml');
|
||||||
const zipImportService = require('../../services/import/zip');
|
import zipImportService = require('../../services/import/zip');
|
||||||
const singleImportService = require('../../services/import/single');
|
import singleImportService = require('../../services/import/single');
|
||||||
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 beccaLoader = require('../../becca/becca_loader');
|
import beccaLoader = require('../../becca/becca_loader');
|
||||||
const log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
const TaskContext = require('../../services/task_context');
|
import TaskContext = require('../../services/task_context');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import BNote = require('../../becca/entities/bnote');
|
||||||
|
|
||||||
async function importNotesToBranch(req) {
|
async function importNotesToBranch(req: Request) {
|
||||||
const { parentNoteId } = req.params;
|
const { parentNoteId } = req.params;
|
||||||
const { taskId, last } = req.body;
|
const { taskId, last } = req.body;
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ async function importNotesToBranch(req) {
|
|||||||
replaceUnderscoresWithSpaces: req.body.replaceUnderscoresWithSpaces !== 'false'
|
replaceUnderscoresWithSpaces: req.body.replaceUnderscoresWithSpaces !== 'false'
|
||||||
};
|
};
|
||||||
|
|
||||||
const file = req.file;
|
const file = (req as any).file;
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new ValidationError("No file has been uploaded");
|
throw new ValidationError("No file has been uploaded");
|
||||||
@ -42,7 +44,7 @@ async function importNotesToBranch(req) {
|
|||||||
// eliminate flickering during import
|
// eliminate flickering during import
|
||||||
cls.ignoreEntityChangeIds();
|
cls.ignoreEntityChangeIds();
|
||||||
|
|
||||||
let note; // typically root of the import - client can show it after finishing the import
|
let note: BNote | null; // typically root of the import - client can show it after finishing the import
|
||||||
|
|
||||||
const taskContext = TaskContext.getInstance(taskId, 'importNotes', options);
|
const taskContext = TaskContext.getInstance(taskId, 'importNotes', options);
|
||||||
|
|
||||||
@ -50,14 +52,24 @@ async function importNotesToBranch(req) {
|
|||||||
if (extension === '.zip' && options.explodeArchives) {
|
if (extension === '.zip' && options.explodeArchives) {
|
||||||
note = await zipImportService.importZip(taskContext, file.buffer, parentNote);
|
note = await zipImportService.importZip(taskContext, file.buffer, parentNote);
|
||||||
} else if (extension === '.opml' && options.explodeArchives) {
|
} else if (extension === '.opml' && options.explodeArchives) {
|
||||||
note = await opmlImportService.importOpml(taskContext, file.buffer, parentNote);
|
const importResult = await opmlImportService.importOpml(taskContext, file.buffer, parentNote);
|
||||||
|
if (!Array.isArray(importResult)) {
|
||||||
|
note = importResult;
|
||||||
|
} else {
|
||||||
|
return importResult;
|
||||||
|
}
|
||||||
} else if (extension === '.enex' && options.explodeArchives) {
|
} else if (extension === '.enex' && options.explodeArchives) {
|
||||||
note = await enexImportService.importEnex(taskContext, file, parentNote);
|
const importResult = await enexImportService.importEnex(taskContext, file, parentNote);
|
||||||
|
if (!Array.isArray(importResult)) {
|
||||||
|
note = importResult;
|
||||||
|
} else {
|
||||||
|
return importResult;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
note = await singleImportService.importSingleFile(taskContext, file, parentNote);
|
note = await singleImportService.importSingleFile(taskContext, file, parentNote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
const message = `Import failed with following error: '${e.message}'. More details might be in the logs.`;
|
const message = `Import failed with following error: '${e.message}'. More details might be in the logs.`;
|
||||||
taskContext.reportError(message);
|
taskContext.reportError(message);
|
||||||
|
|
||||||
@ -66,11 +78,15 @@ async function importNotesToBranch(req) {
|
|||||||
return [500, message];
|
return [500, message];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
return [500, "No note was generated as a result of the import."];
|
||||||
|
}
|
||||||
|
|
||||||
if (last === "true") {
|
if (last === "true") {
|
||||||
// small timeout to avoid race condition (the message is received before the transaction is committed)
|
// small timeout to avoid race condition (the message is received before the transaction is committed)
|
||||||
setTimeout(() => taskContext.taskSucceeded({
|
setTimeout(() => taskContext.taskSucceeded({
|
||||||
parentNoteId: parentNoteId,
|
parentNoteId: parentNoteId,
|
||||||
importedNoteId: note.noteId
|
importedNoteId: note?.noteId
|
||||||
}), 1000);
|
}), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +96,7 @@ async function importNotesToBranch(req) {
|
|||||||
return note.getPojo();
|
return note.getPojo();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importAttachmentsToNote(req) {
|
async function importAttachmentsToNote(req: Request) {
|
||||||
const { parentNoteId } = req.params;
|
const { parentNoteId } = req.params;
|
||||||
const { taskId, last } = req.body;
|
const { taskId, last } = req.body;
|
||||||
|
|
||||||
@ -88,7 +104,7 @@ async function importAttachmentsToNote(req) {
|
|||||||
shrinkImages: req.body.shrinkImages !== 'false',
|
shrinkImages: req.body.shrinkImages !== 'false',
|
||||||
};
|
};
|
||||||
|
|
||||||
const file = req.file;
|
const file = (req as any).file;
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new ValidationError("No file has been uploaded");
|
throw new ValidationError("No file has been uploaded");
|
||||||
@ -102,7 +118,7 @@ async function importAttachmentsToNote(req) {
|
|||||||
try {
|
try {
|
||||||
await singleImportService.importAttachment(taskContext, file, parentNote);
|
await singleImportService.importAttachment(taskContext, file, parentNote);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
const message = `Import failed with following error: '${e.message}'. More details might be in the logs.`;
|
const message = `Import failed with following error: '${e.message}'. More details might be in the logs.`;
|
||||||
taskContext.reportError(message);
|
taskContext.reportError(message);
|
||||||
|
|
||||||
@ -119,7 +135,7 @@ async function importAttachmentsToNote(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
importNotesToBranch,
|
importNotesToBranch,
|
||||||
importAttachmentsToNote
|
importAttachmentsToNote
|
||||||
};
|
};
|
@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const keyboardActions = require('../../services/keyboard_actions');
|
import keyboardActions = require('../../services/keyboard_actions');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
|
|
||||||
function getKeyboardActions() {
|
function getKeyboardActions() {
|
||||||
return keyboardActions.getKeyboardActions();
|
return keyboardActions.getKeyboardActions();
|
||||||
@ -14,7 +14,7 @@ function getShortcutsForNotes() {
|
|||||||
return labels.filter(attr => becca.getNote(attr.noteId)?.type !== 'launcher');
|
return labels.filter(attr => becca.getNote(attr.noteId)?.type !== 'launcher');
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getKeyboardActions,
|
getKeyboardActions,
|
||||||
getShortcutsForNotes
|
getShortcutsForNotes
|
||||||
};
|
};
|
@ -1,19 +1,20 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const options = require('../../services/options');
|
import options = require('../../services/options');
|
||||||
const utils = require('../../services/utils');
|
import utils = require('../../services/utils');
|
||||||
const dateUtils = require('../../services/date_utils');
|
import dateUtils = require('../../services/date_utils');
|
||||||
const instanceId = require('../../services/instance_id');
|
import instanceId = require('../../services/instance_id');
|
||||||
const passwordEncryptionService = require('../../services/encryption/password_encryption');
|
import passwordEncryptionService = require('../../services/encryption/password_encryption');
|
||||||
const protectedSessionService = require('../../services/protected_session');
|
import protectedSessionService = require('../../services/protected_session');
|
||||||
const appInfo = require('../../services/app_info');
|
import appInfo = require('../../services/app_info');
|
||||||
const eventService = require('../../services/events');
|
import eventService = require('../../services/events');
|
||||||
const sqlInit = require('../../services/sql_init');
|
import sqlInit = require('../../services/sql_init');
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const ws = require('../../services/ws');
|
import ws = require('../../services/ws');
|
||||||
const etapiTokenService = require('../../services/etapi_tokens');
|
import etapiTokenService = require('../../services/etapi_tokens');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
function loginSync(req) {
|
function loginSync(req: Request) {
|
||||||
if (!sqlInit.schemaExists()) {
|
if (!sqlInit.schemaExists()) {
|
||||||
return [500, { message: "DB schema does not exist, can't sync." }];
|
return [500, { message: "DB schema does not exist, can't sync." }];
|
||||||
}
|
}
|
||||||
@ -44,7 +45,7 @@ function loginSync(req) {
|
|||||||
return [400, { message: "Sync login credentials are incorrect. It looks like you're trying to sync two different initialized documents which is not possible." }];
|
return [400, { message: "Sync login credentials are incorrect. It looks like you're trying to sync two different initialized documents which is not possible." }];
|
||||||
}
|
}
|
||||||
|
|
||||||
req.session.loggedIn = true;
|
(req as any).session.loggedIn = true;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
@ -52,7 +53,7 @@ function loginSync(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function loginToProtectedSession(req) {
|
function loginToProtectedSession(req: Request) {
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
if (!passwordEncryptionService.verifyPassword(password)) {
|
if (!passwordEncryptionService.verifyPassword(password)) {
|
||||||
@ -63,6 +64,12 @@ function loginToProtectedSession(req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decryptedDataKey = passwordEncryptionService.getDataKey(password);
|
const decryptedDataKey = passwordEncryptionService.getDataKey(password);
|
||||||
|
if (!decryptedDataKey) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Unable to obtain data key."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protectedSessionService.setDataKey(decryptedDataKey);
|
protectedSessionService.setDataKey(decryptedDataKey);
|
||||||
|
|
||||||
@ -87,7 +94,7 @@ function touchProtectedSession() {
|
|||||||
protectedSessionService.touchProtectedSession();
|
protectedSessionService.touchProtectedSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
function token(req) {
|
function token(req: Request) {
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
if (!passwordEncryptionService.verifyPassword(password)) {
|
if (!passwordEncryptionService.verifyPassword(password)) {
|
||||||
@ -102,7 +109,7 @@ function token(req) {
|
|||||||
return { token: authToken };
|
return { token: authToken };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
loginSync,
|
loginSync,
|
||||||
loginToProtectedSession,
|
loginToProtectedSession,
|
||||||
logoutFromProtectedSession,
|
logoutFromProtectedSession,
|
@ -1,18 +1,25 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
const { JSDOM } = require("jsdom");
|
import { JSDOM } from "jsdom";
|
||||||
|
import BNote = require('../../becca/entities/bnote');
|
||||||
|
import BAttribute = require('../../becca/entities/battribute');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
|
||||||
function buildDescendantCountMap(noteIdsToCount) {
|
function buildDescendantCountMap(noteIdsToCount: string[]) {
|
||||||
if (!Array.isArray(noteIdsToCount)) {
|
if (!Array.isArray(noteIdsToCount)) {
|
||||||
throw new Error('noteIdsToCount: type error');
|
throw new Error('noteIdsToCount: type error');
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteIdToCountMap = Object.create(null);
|
const noteIdToCountMap = Object.create(null);
|
||||||
|
|
||||||
function getCount(noteId) {
|
function getCount(noteId: string) {
|
||||||
if (!(noteId in noteIdToCountMap)) {
|
if (!(noteId in noteIdToCountMap)) {
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNote(noteId);
|
||||||
|
if (!note) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const hiddenImageNoteIds = note.getRelations('imageLink').map(rel => rel.value);
|
const hiddenImageNoteIds = note.getRelations('imageLink').map(rel => rel.value);
|
||||||
const childNoteIds = note.children.map(child => child.noteId);
|
const childNoteIds = note.children.map(child => child.noteId);
|
||||||
@ -33,19 +40,14 @@ function buildDescendantCountMap(noteIdsToCount) {
|
|||||||
|
|
||||||
return noteIdToCountMap;
|
return noteIdToCountMap;
|
||||||
}
|
}
|
||||||
/**
|
function getNeighbors(note: BNote, depth: number): string[] {
|
||||||
* @param {BNote} note
|
|
||||||
* @param {int} depth
|
|
||||||
* @returns {string[]} noteIds
|
|
||||||
*/
|
|
||||||
function getNeighbors(note, depth) {
|
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const retNoteIds = [];
|
const retNoteIds = [];
|
||||||
|
|
||||||
function isIgnoredRelation(relation) {
|
function isIgnoredRelation(relation: BAttribute) {
|
||||||
return ['relationMapLink', 'template', 'inherit', 'image', 'ancestor'].includes(relation.name);
|
return ['relationMapLink', 'template', 'inherit', 'image', 'ancestor'].includes(relation.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +92,9 @@ function getNeighbors(note, depth) {
|
|||||||
return retNoteIds;
|
return retNoteIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLinkMap(req) {
|
function getLinkMap(req: Request) {
|
||||||
const mapRootNote = becca.getNote(req.params.noteId);
|
const mapRootNote = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
// if the map root itself has "excludeFromNoteMap" attribute (journal typically) then there wouldn't be anything
|
// if the map root itself has "excludeFromNoteMap" attribute (journal typically) then there wouldn't be anything
|
||||||
// to display, so we'll just ignore it
|
// to display, so we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
||||||
@ -125,7 +128,7 @@ function getLinkMap(req) {
|
|||||||
const noteIdsArray = Array.from(noteIds)
|
const noteIdsArray = Array.from(noteIds)
|
||||||
|
|
||||||
const notes = noteIdsArray.map(noteId => {
|
const notes = noteIdsArray.map(noteId => {
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
note.noteId,
|
note.noteId,
|
||||||
@ -144,6 +147,9 @@ function getLinkMap(req) {
|
|||||||
}
|
}
|
||||||
else if (rel.name === 'imageLink') {
|
else if (rel.name === 'imageLink') {
|
||||||
const parentNote = becca.getNote(rel.noteId);
|
const parentNote = becca.getNote(rel.noteId);
|
||||||
|
if (!parentNote) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return !parentNote.getChildNotes().find(childNote => childNote.noteId === rel.value);
|
return !parentNote.getChildNotes().find(childNote => childNote.noteId === rel.value);
|
||||||
}
|
}
|
||||||
@ -165,8 +171,8 @@ function getLinkMap(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTreeMap(req) {
|
function getTreeMap(req: Request) {
|
||||||
const mapRootNote = becca.getNote(req.params.noteId);
|
const mapRootNote = becca.getNoteOrThrow(req.params.noteId);
|
||||||
// if the map root itself has "excludeFromNoteMap" (journal typically) then there wouldn't be anything to display,
|
// if the map root itself has "excludeFromNoteMap" (journal typically) then there wouldn't be anything to display,
|
||||||
// so we'll just ignore it
|
// so we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.isLabelTruthy('excludeFromNoteMap');
|
||||||
@ -198,8 +204,8 @@ function getTreeMap(req) {
|
|||||||
note.getLabelValue('color')
|
note.getLabelValue('color')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const noteIds = new Set();
|
const noteIds = new Set<string>();
|
||||||
notes.forEach(([noteId]) => noteIds.add(noteId));
|
notes.forEach(([noteId]) => noteId && noteIds.add(noteId));
|
||||||
|
|
||||||
const links = [];
|
const links = [];
|
||||||
|
|
||||||
@ -225,7 +231,7 @@ function getTreeMap(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDescendantCountMapForSearch(noteIdToDescendantCountMap, relationships) {
|
function updateDescendantCountMapForSearch(noteIdToDescendantCountMap: Record<string, number>, relationships: { parentNoteId: string, childNoteId: string }[]) {
|
||||||
for (const {parentNoteId, childNoteId} of relationships) {
|
for (const {parentNoteId, childNoteId} of relationships) {
|
||||||
const parentNote = becca.notes[parentNoteId];
|
const parentNote = becca.notes[parentNoteId];
|
||||||
if (!parentNote || parentNote.type !== 'search') {
|
if (!parentNote || parentNote.type !== 'search') {
|
||||||
@ -237,16 +243,17 @@ function updateDescendantCountMapForSearch(noteIdToDescendantCountMap, relations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeImages(document) {
|
function removeImages(document: Document) {
|
||||||
const images = document.getElementsByTagName('img');
|
const images = document.getElementsByTagName('img');
|
||||||
while (images.length > 0) {
|
while (images && images.length > 0) {
|
||||||
images[0].parentNode.removeChild(images[0]);
|
images[0]?.parentNode?.removeChild(images[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXCERPT_CHAR_LIMIT = 200;
|
const EXCERPT_CHAR_LIMIT = 200;
|
||||||
|
type ElementOrText = (Element | Text);
|
||||||
|
|
||||||
function findExcerpts(sourceNote, referencedNoteId) {
|
function findExcerpts(sourceNote: BNote, referencedNoteId: string) {
|
||||||
const html = sourceNote.getContent();
|
const html = sourceNote.getContent();
|
||||||
const document = new JSDOM(html).window.document;
|
const document = new JSDOM(html).window.document;
|
||||||
|
|
||||||
@ -263,25 +270,24 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
|
|
||||||
linkEl.classList.add("backlink-link");
|
linkEl.classList.add("backlink-link");
|
||||||
|
|
||||||
let centerEl = linkEl;
|
let centerEl: HTMLElement = linkEl;
|
||||||
|
|
||||||
while (centerEl.tagName !== 'BODY' && centerEl.parentElement?.textContent?.length <= EXCERPT_CHAR_LIMIT) {
|
while (centerEl.tagName !== 'BODY' && centerEl.parentElement && (centerEl.parentElement?.textContent?.length || 0) <= EXCERPT_CHAR_LIMIT) {
|
||||||
centerEl = centerEl.parentElement;
|
centerEl = centerEl.parentElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var {HTMLElement[]} */
|
const excerptEls: ElementOrText[] = [centerEl];
|
||||||
const excerptEls = [centerEl];
|
let excerptLength = centerEl.textContent?.length || 0;
|
||||||
let excerptLength = centerEl.textContent.length;
|
let left: ElementOrText = centerEl;
|
||||||
let left = centerEl;
|
let right: ElementOrText = centerEl;
|
||||||
let right = centerEl;
|
|
||||||
|
|
||||||
while (excerptLength < EXCERPT_CHAR_LIMIT) {
|
while (excerptLength < EXCERPT_CHAR_LIMIT) {
|
||||||
let added = false;
|
let added = false;
|
||||||
|
|
||||||
const prev = left.previousElementSibling;
|
const prev: Element | null = left.previousElementSibling;
|
||||||
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
const prevText = prev.textContent;
|
const prevText = prev.textContent || "";
|
||||||
|
|
||||||
if (prevText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
if (prevText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
||||||
const prefix = prevText.substr(prevText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
const prefix = prevText.substr(prevText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
||||||
@ -298,12 +304,12 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const next = right.nextElementSibling;
|
const next: Element | null = right.nextElementSibling;
|
||||||
|
|
||||||
if (next) {
|
if (next) {
|
||||||
const nextText = next.textContent;
|
const nextText = next.textContent;
|
||||||
|
|
||||||
if (nextText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
if (nextText && nextText.length + excerptLength > EXCERPT_CHAR_LIMIT) {
|
||||||
const suffix = nextText.substr(nextText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
const suffix = nextText.substr(nextText.length - (EXCERPT_CHAR_LIMIT - excerptLength));
|
||||||
|
|
||||||
const textNode = document.createTextNode(`${suffix}…`);
|
const textNode = document.createTextNode(`${suffix}…`);
|
||||||
@ -314,7 +320,7 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
|
|
||||||
right = next;
|
right = next;
|
||||||
excerptEls.push(right);
|
excerptEls.push(right);
|
||||||
excerptLength += nextText.length;
|
excerptLength += nextText?.length || 0;
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,13 +342,13 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
return excerpts;
|
return excerpts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFilteredBacklinks(note) {
|
function getFilteredBacklinks(note: BNote) {
|
||||||
return note.getTargetRelations()
|
return note.getTargetRelations()
|
||||||
// search notes have "ancestor" relations which are not interesting
|
// search notes have "ancestor" relations which are not interesting
|
||||||
.filter(relation => !!relation.getNote() && relation.getNote().type !== 'search');
|
.filter(relation => !!relation.getNote() && relation.getNote().type !== 'search');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBacklinkCount(req) {
|
function getBacklinkCount(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
|
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
@ -352,7 +358,7 @@ function getBacklinkCount(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBacklinks(req) {
|
function getBacklinks(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
@ -379,7 +385,7 @@ function getBacklinks(req) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getLinkMap,
|
getLinkMap,
|
||||||
getTreeMap,
|
getTreeMap,
|
||||||
getBacklinkCount,
|
getBacklinkCount,
|
@ -1,25 +1,28 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteService = require('../../services/notes');
|
import noteService = require('../../services/notes');
|
||||||
const eraseService = require('../../services/erase');
|
import eraseService = require('../../services/erase');
|
||||||
const treeService = require('../../services/tree');
|
import treeService = require('../../services/tree');
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const utils = require('../../services/utils');
|
import utils = require('../../services/utils');
|
||||||
const log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
const TaskContext = require('../../services/task_context');
|
import TaskContext = require('../../services/task_context');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
import ValidationError = require('../../errors/validation_error');
|
||||||
const blobService = require('../../services/blob');
|
import blobService = require('../../services/blob');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import BBranch = require('../../becca/entities/bbranch');
|
||||||
|
import { AttributeRow } from '../../becca/entities/rows';
|
||||||
|
|
||||||
function getNote(req) {
|
function getNote(req: Request) {
|
||||||
return becca.getNoteOrThrow(req.params.noteId);
|
return becca.getNoteOrThrow(req.params.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteBlob(req) {
|
function getNoteBlob(req: Request) {
|
||||||
return blobService.getBlobPojo('notes', req.params.noteId);
|
return blobService.getBlobPojo('notes', req.params.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteMetadata(req) {
|
function getNoteMetadata(req: Request) {
|
||||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -30,12 +33,20 @@ function getNoteMetadata(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNote(req) {
|
function createNote(req: Request) {
|
||||||
const params = Object.assign({}, req.body); // clone
|
const params = Object.assign({}, req.body); // clone
|
||||||
params.parentNoteId = req.params.parentNoteId;
|
params.parentNoteId = req.params.parentNoteId;
|
||||||
|
|
||||||
const { target, targetBranchId } = req.query;
|
const { target, targetBranchId } = req.query;
|
||||||
|
|
||||||
|
if (target !== "into" && target !== "after") {
|
||||||
|
throw new ValidationError("Invalid target type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetBranchId && typeof targetBranchId !== "string") {
|
||||||
|
throw new ValidationError("Missing or incorrect type for target branch ID.");
|
||||||
|
}
|
||||||
|
|
||||||
const { note, branch } = noteService.createNewNoteWithTarget(target, targetBranchId, params);
|
const { note, branch } = noteService.createNewNoteWithTarget(target, targetBranchId, params);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -44,14 +55,14 @@ function createNote(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNoteData(req) {
|
function updateNoteData(req: Request) {
|
||||||
const {content, attachments} = req.body;
|
const {content, attachments} = req.body;
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
|
|
||||||
return noteService.updateNoteData(noteId, content, attachments);
|
return noteService.updateNoteData(noteId, content, attachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteNote(req) {
|
function deleteNote(req: Request) {
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
const taskId = req.query.taskId;
|
const taskId = req.query.taskId;
|
||||||
const eraseNotes = req.query.eraseNotes === 'true';
|
const eraseNotes = req.query.eraseNotes === 'true';
|
||||||
@ -60,8 +71,11 @@ function deleteNote(req) {
|
|||||||
// note how deleteId is separate from taskId - single taskId produces separate deleteId for each "top level" deleted note
|
// note how deleteId is separate from taskId - single taskId produces separate deleteId for each "top level" deleted note
|
||||||
const deleteId = utils.randomString(10);
|
const deleteId = utils.randomString(10);
|
||||||
|
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
|
if (typeof taskId !== "string") {
|
||||||
|
throw new ValidationError("Missing or incorrect type for task ID.");
|
||||||
|
}
|
||||||
const taskContext = TaskContext.getInstance(taskId, 'deleteNotes');
|
const taskContext = TaskContext.getInstance(taskId, 'deleteNotes');
|
||||||
|
|
||||||
note.deleteNote(deleteId, taskContext);
|
note.deleteNote(deleteId, taskContext);
|
||||||
@ -75,7 +89,7 @@ function deleteNote(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undeleteNote(req) {
|
function undeleteNote(req: Request) {
|
||||||
const taskContext = TaskContext.getInstance(utils.randomString(10), 'undeleteNotes');
|
const taskContext = TaskContext.getInstance(utils.randomString(10), 'undeleteNotes');
|
||||||
|
|
||||||
noteService.undeleteNote(req.params.noteId, taskContext);
|
noteService.undeleteNote(req.params.noteId, taskContext);
|
||||||
@ -83,7 +97,7 @@ function undeleteNote(req) {
|
|||||||
taskContext.taskSucceeded();
|
taskContext.taskSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortChildNotes(req) {
|
function sortChildNotes(req: Request) {
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
const {sortBy, sortDirection, foldersFirst, sortNatural, sortLocale} = req.body;
|
const {sortBy, sortDirection, foldersFirst, sortNatural, sortLocale} = req.body;
|
||||||
|
|
||||||
@ -94,11 +108,11 @@ function sortChildNotes(req) {
|
|||||||
treeService.sortNotes(noteId, sortBy, reverse, foldersFirst, sortNatural, sortLocale);
|
treeService.sortNotes(noteId, sortBy, reverse, foldersFirst, sortNatural, sortLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
function protectNote(req) {
|
function protectNote(req: Request) {
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
const note = becca.notes[noteId];
|
const note = becca.notes[noteId];
|
||||||
const protect = !!parseInt(req.params.isProtected);
|
const protect = !!parseInt(req.params.isProtected);
|
||||||
const includingSubTree = !!parseInt(req.query.subtree);
|
const includingSubTree = !!parseInt(req.query?.subtree as string);
|
||||||
|
|
||||||
const taskContext = new TaskContext(utils.randomString(10), 'protectNotes', {protect});
|
const taskContext = new TaskContext(utils.randomString(10), 'protectNotes', {protect});
|
||||||
|
|
||||||
@ -107,18 +121,18 @@ function protectNote(req) {
|
|||||||
taskContext.taskSucceeded();
|
taskContext.taskSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNoteTypeMime(req) {
|
function setNoteTypeMime(req: Request) {
|
||||||
// can't use [] destructuring because req.params is not iterable
|
// can't use [] destructuring because req.params is not iterable
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const {type, mime} = req.body;
|
const {type, mime} = req.body;
|
||||||
|
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
note.type = type;
|
note.type = type;
|
||||||
note.mime = mime;
|
note.mime = mime;
|
||||||
note.save();
|
note.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTitle(req) {
|
function changeTitle(req: Request) {
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
const title = req.body.title;
|
const title = req.body.title;
|
||||||
|
|
||||||
@ -145,7 +159,7 @@ function changeTitle(req) {
|
|||||||
return note;
|
return note;
|
||||||
}
|
}
|
||||||
|
|
||||||
function duplicateSubtree(req) {
|
function duplicateSubtree(req: Request) {
|
||||||
const {noteId, parentNoteId} = req.params;
|
const {noteId, parentNoteId} = req.params;
|
||||||
|
|
||||||
return noteService.duplicateSubtree(noteId, parentNoteId);
|
return noteService.duplicateSubtree(noteId, parentNoteId);
|
||||||
@ -159,14 +173,14 @@ function eraseUnusedAttachmentsNow() {
|
|||||||
eraseService.eraseUnusedAttachmentsNow();
|
eraseService.eraseUnusedAttachmentsNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeleteNotesPreview(req) {
|
function getDeleteNotesPreview(req: Request) {
|
||||||
const {branchIdsToDelete, deleteAllClones} = req.body;
|
const {branchIdsToDelete, deleteAllClones} = req.body;
|
||||||
|
|
||||||
const noteIdsToBeDeleted = new Set();
|
const noteIdsToBeDeleted = new Set<string>();
|
||||||
const strongBranchCountToDelete = {}; // noteId => count (integer)
|
const strongBranchCountToDelete: Record<string, number> = {}; // noteId => count
|
||||||
|
|
||||||
function branchPreviewDeletion(branch) {
|
function branchPreviewDeletion(branch: BBranch) {
|
||||||
if (branch.isWeak) {
|
if (branch.isWeak || !branch.branchId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,18 +210,18 @@ function getDeleteNotesPreview(req) {
|
|||||||
branchPreviewDeletion(branch);
|
branchPreviewDeletion(branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
let brokenRelations = [];
|
let brokenRelations: AttributeRow[] = [];
|
||||||
|
|
||||||
if (noteIdsToBeDeleted.size > 0) {
|
if (noteIdsToBeDeleted.size > 0) {
|
||||||
sql.fillParamList(noteIdsToBeDeleted);
|
sql.fillParamList(noteIdsToBeDeleted);
|
||||||
|
|
||||||
// FIXME: No need to do this in database, can be done with becca data
|
// FIXME: No need to do this in database, can be done with becca data
|
||||||
brokenRelations = sql.getRows(`
|
brokenRelations = sql.getRows<AttributeRow>(`
|
||||||
SELECT attr.noteId, attr.name, attr.value
|
SELECT attr.noteId, attr.name, attr.value
|
||||||
FROM attributes attr
|
FROM attributes attr
|
||||||
JOIN param_list ON param_list.paramId = attr.value
|
JOIN param_list ON param_list.paramId = attr.value
|
||||||
WHERE attr.isDeleted = 0
|
WHERE attr.isDeleted = 0
|
||||||
AND attr.type = 'relation'`).filter(attr => !noteIdsToBeDeleted.has(attr.noteId));
|
AND attr.type = 'relation'`).filter(attr => attr.noteId && !noteIdsToBeDeleted.has(attr.noteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -216,7 +230,7 @@ function getDeleteNotesPreview(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function forceSaveRevision(req) {
|
function forceSaveRevision(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
@ -227,7 +241,7 @@ function forceSaveRevision(req) {
|
|||||||
note.saveRevision();
|
note.saveRevision();
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertNoteToAttachment(req) {
|
function convertNoteToAttachment(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
@ -236,7 +250,7 @@ function convertNoteToAttachment(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getNote,
|
getNote,
|
||||||
getNoteBlob,
|
getNoteBlob,
|
||||||
getNoteMetadata,
|
getNoteMetadata,
|
@ -1,9 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const optionService = require('../../services/options');
|
import optionService = require('../../services/options');
|
||||||
const log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
const searchService = require('../../services/search/services/search');
|
import searchService = require('../../services/search/services/search');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
// options allowed to be updated directly in the Options dialog
|
// options allowed to be updated directly in the Options dialog
|
||||||
const ALLOWED_OPTIONS = new Set([
|
const ALLOWED_OPTIONS = new Set([
|
||||||
@ -62,7 +63,7 @@ const ALLOWED_OPTIONS = new Set([
|
|||||||
|
|
||||||
function getOptions() {
|
function getOptions() {
|
||||||
const optionMap = optionService.getOptionMap();
|
const optionMap = optionService.getOptionMap();
|
||||||
const resultMap = {};
|
const resultMap: Record<string, string> = {};
|
||||||
|
|
||||||
for (const optionName in optionMap) {
|
for (const optionName in optionMap) {
|
||||||
if (isAllowed(optionName)) {
|
if (isAllowed(optionName)) {
|
||||||
@ -75,7 +76,7 @@ function getOptions() {
|
|||||||
return resultMap;
|
return resultMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateOption(req) {
|
function updateOption(req: Request) {
|
||||||
const {name, value} = req.params;
|
const {name, value} = req.params;
|
||||||
|
|
||||||
if (!update(name, value)) {
|
if (!update(name, value)) {
|
||||||
@ -83,7 +84,7 @@ function updateOption(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateOptions(req) {
|
function updateOptions(req: Request) {
|
||||||
for (const optionName in req.body) {
|
for (const optionName in req.body) {
|
||||||
if (!update(optionName, req.body[optionName])) {
|
if (!update(optionName, req.body[optionName])) {
|
||||||
// this should be improved
|
// this should be improved
|
||||||
@ -93,7 +94,7 @@ function updateOptions(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(name, value) {
|
function update(name: string, value: string) {
|
||||||
if (!isAllowed(name)) {
|
if (!isAllowed(name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -128,14 +129,14 @@ function getUserThemes() {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAllowed(name) {
|
function isAllowed(name: string) {
|
||||||
return ALLOWED_OPTIONS.has(name)
|
return ALLOWED_OPTIONS.has(name)
|
||||||
|| name.startsWith("keyboardShortcuts")
|
|| name.startsWith("keyboardShortcuts")
|
||||||
|| name.endsWith("Collapsed")
|
|| name.endsWith("Collapsed")
|
||||||
|| name.startsWith("hideArchivedNotes");
|
|| name.startsWith("hideArchivedNotes");
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getOptions,
|
getOptions,
|
||||||
updateOption,
|
updateOption,
|
||||||
updateOptions,
|
updateOptions,
|
@ -1,8 +1,10 @@
|
|||||||
const becca = require('../../becca/becca');
|
import { Request } from "express";
|
||||||
const markdownService = require('../../services/import/markdown');
|
|
||||||
|
import becca = require('../../becca/becca');
|
||||||
|
import markdownService = require('../../services/import/markdown');
|
||||||
|
|
||||||
function getIconUsage() {
|
function getIconUsage() {
|
||||||
const iconClassToCountMap = {};
|
const iconClassToCountMap: Record<string, number> = {};
|
||||||
|
|
||||||
for (const {value: iconClass, noteId} of becca.findAttributes('label', 'iconClass')) {
|
for (const {value: iconClass, noteId} of becca.findAttributes('label', 'iconClass')) {
|
||||||
if (noteId.startsWith("_")) {
|
if (noteId.startsWith("_")) {
|
||||||
@ -25,7 +27,7 @@ function getIconUsage() {
|
|||||||
return { iconClassToCountMap };
|
return { iconClassToCountMap };
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMarkdown(req) {
|
function renderMarkdown(req: Request) {
|
||||||
const { markdownContent } = req.body;
|
const { markdownContent } = req.body;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -33,7 +35,7 @@ function renderMarkdown(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getIconUsage,
|
getIconUsage,
|
||||||
renderMarkdown
|
renderMarkdown
|
||||||
};
|
};
|
@ -1,9 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const passwordService = require('../../services/encryption/password');
|
import passwordService = require('../../services/encryption/password');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
function changePassword(req) {
|
function changePassword(req: Request) {
|
||||||
if (passwordService.isPasswordSet()) {
|
if (passwordService.isPasswordSet()) {
|
||||||
return passwordService.changePassword(req.body.current_password, req.body.new_password);
|
return passwordService.changePassword(req.body.current_password, req.body.new_password);
|
||||||
}
|
}
|
||||||
@ -12,7 +13,7 @@ function changePassword(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetPassword(req) {
|
function resetPassword(req: Request) {
|
||||||
// protection against accidental call (not a security measure)
|
// protection against accidental call (not a security measure)
|
||||||
if (req.query.really !== "yesIReallyWantToResetPasswordAndLoseAccessToMyProtectedNotes") {
|
if (req.query.really !== "yesIReallyWantToResetPasswordAndLoseAccessToMyProtectedNotes") {
|
||||||
throw new ValidationError("Incorrect password reset confirmation");
|
throw new ValidationError("Incorrect password reset confirmation");
|
||||||
@ -21,7 +22,7 @@ function resetPassword(req) {
|
|||||||
return passwordService.resetPassword();
|
return passwordService.resetPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
changePassword,
|
changePassword,
|
||||||
resetPassword
|
resetPassword
|
||||||
};
|
};
|
@ -1,16 +1,30 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const protectedSessionService = require('../../services/protected_session');
|
import protectedSessionService = require('../../services/protected_session');
|
||||||
const noteService = require('../../services/notes');
|
import noteService = require('../../services/notes');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { RevisionRow } from '../../becca/entities/rows';
|
||||||
|
|
||||||
function getRecentChanges(req) {
|
interface RecentChangeRow {
|
||||||
|
noteId: string;
|
||||||
|
current_isDeleted: boolean;
|
||||||
|
current_deleteId: string;
|
||||||
|
current_title: string;
|
||||||
|
current_isProtected: boolean,
|
||||||
|
title: string;
|
||||||
|
utcDate: string;
|
||||||
|
date: string;
|
||||||
|
canBeUndeleted?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecentChanges(req: Request) {
|
||||||
const {ancestorNoteId} = req.params;
|
const {ancestorNoteId} = req.params;
|
||||||
|
|
||||||
let recentChanges = [];
|
let recentChanges = [];
|
||||||
|
|
||||||
const revisionRows = sql.getRows(`
|
const revisionRows = sql.getRows<RecentChangeRow>(`
|
||||||
SELECT
|
SELECT
|
||||||
notes.noteId,
|
notes.noteId,
|
||||||
notes.isDeleted AS current_isDeleted,
|
notes.isDeleted AS current_isDeleted,
|
||||||
@ -36,7 +50,7 @@ function getRecentChanges(req) {
|
|||||||
// now we need to also collect date points not represented in note revisions:
|
// now we need to also collect date points not represented in note revisions:
|
||||||
// 1. creation for all notes (dateCreated)
|
// 1. creation for all notes (dateCreated)
|
||||||
// 2. deletion for deleted notes (dateModified)
|
// 2. deletion for deleted notes (dateModified)
|
||||||
const noteRows = sql.getRows(`
|
const noteRows = sql.getRows<RecentChangeRow>(`
|
||||||
SELECT
|
SELECT
|
||||||
notes.noteId,
|
notes.noteId,
|
||||||
notes.isDeleted AS current_isDeleted,
|
notes.isDeleted AS current_isDeleted,
|
||||||
@ -76,8 +90,8 @@ function getRecentChanges(req) {
|
|||||||
for (const change of recentChanges) {
|
for (const change of recentChanges) {
|
||||||
if (change.current_isProtected) {
|
if (change.current_isProtected) {
|
||||||
if (protectedSessionService.isProtectedSessionAvailable()) {
|
if (protectedSessionService.isProtectedSessionAvailable()) {
|
||||||
change.title = protectedSessionService.decryptString(change.title);
|
change.title = protectedSessionService.decryptString(change.title) || "[protected]";
|
||||||
change.current_title = protectedSessionService.decryptString(change.current_title);
|
change.current_title = protectedSessionService.decryptString(change.current_title) || "[protected]";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
change.title = change.current_title = "[protected]";
|
change.title = change.current_title = "[protected]";
|
||||||
@ -97,6 +111,6 @@ function getRecentChanges(req) {
|
|||||||
return recentChanges;
|
return recentChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getRecentChanges
|
getRecentChanges
|
||||||
};
|
};
|
@ -1,10 +1,11 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const BRecentNote = require('../../becca/entities/brecent_note');
|
import BRecentNote = require('../../becca/entities/brecent_note');
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const dateUtils = require('../../services/date_utils');
|
import dateUtils = require('../../services/date_utils');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
function addRecentNote(req) {
|
function addRecentNote(req: Request) {
|
||||||
new BRecentNote({
|
new BRecentNote({
|
||||||
noteId: req.body.noteId,
|
noteId: req.body.noteId,
|
||||||
notePath: req.body.notePath
|
notePath: req.body.notePath
|
||||||
@ -18,6 +19,6 @@ function addRecentNote(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
addRecentNote
|
addRecentNote
|
||||||
};
|
};
|
@ -1,10 +1,22 @@
|
|||||||
const becca = require('../../becca/becca');
|
import { Request } from 'express';
|
||||||
const sql = require('../../services/sql');
|
import becca = require('../../becca/becca');
|
||||||
|
import sql = require('../../services/sql');
|
||||||
|
|
||||||
function getRelationMap(req) {
|
interface ResponseData {
|
||||||
|
noteTitles: Record<string, string>;
|
||||||
|
relations: {
|
||||||
|
attributeId: string,
|
||||||
|
sourceNoteId: string,
|
||||||
|
targetNoteId: string,
|
||||||
|
name: string
|
||||||
|
}[];
|
||||||
|
inverseRelations: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRelationMap(req: Request) {
|
||||||
const {relationMapNoteId, noteIds} = req.body;
|
const {relationMapNoteId, noteIds} = req.body;
|
||||||
|
|
||||||
const resp = {
|
const resp: ResponseData = {
|
||||||
// noteId => title
|
// noteId => title
|
||||||
noteTitles: {},
|
noteTitles: {},
|
||||||
relations: [],
|
relations: [],
|
||||||
@ -14,13 +26,13 @@ function getRelationMap(req) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (noteIds.length === 0) {
|
if (!Array.isArray(noteIds) || noteIds.length === 0) {
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const questionMarks = noteIds.map(noteId => '?').join(',');
|
const questionMarks = noteIds.map(noteId => '?').join(',');
|
||||||
|
|
||||||
const relationMapNote = becca.getNote(relationMapNoteId);
|
const relationMapNote = becca.getNoteOrThrow(relationMapNoteId);
|
||||||
|
|
||||||
const displayRelationsVal = relationMapNote.getLabelValue('displayRelations');
|
const displayRelationsVal = relationMapNote.getLabelValue('displayRelations');
|
||||||
const displayRelations = !displayRelationsVal ? [] : displayRelationsVal
|
const displayRelations = !displayRelationsVal ? [] : displayRelationsVal
|
||||||
@ -32,7 +44,7 @@ function getRelationMap(req) {
|
|||||||
.split(",")
|
.split(",")
|
||||||
.map(token => token.trim());
|
.map(token => token.trim());
|
||||||
|
|
||||||
const foundNoteIds = sql.getColumn(`SELECT noteId FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
|
const foundNoteIds = sql.getColumn<string>(`SELECT noteId FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
|
||||||
const notes = becca.getNotes(foundNoteIds);
|
const notes = becca.getNotes(foundNoteIds);
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
@ -64,6 +76,6 @@ function getRelationMap(req) {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getRelationMap
|
getRelationMap
|
||||||
};
|
};
|
@ -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,7 +129,9 @@ 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
|
||||||
revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`);
|
if (typeof revisionContent === "string") {
|
||||||
|
revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
note.title = revision.title;
|
note.title = revision.title;
|
||||||
@ -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,
|
@ -1,19 +1,30 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const scriptService = require('../../services/script');
|
import scriptService = require('../../services/script');
|
||||||
const attributeService = require('../../services/attributes');
|
import attributeService = require('../../services/attributes');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
const syncService = require('../../services/sync');
|
import syncService = require('../../services/sync');
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
|
interface ScriptBody {
|
||||||
|
script: string;
|
||||||
|
params: any[];
|
||||||
|
startNoteId: string;
|
||||||
|
currentNoteId: string;
|
||||||
|
originEntityName: string;
|
||||||
|
originEntityId: string;
|
||||||
|
transactional: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
// The async/await here is very confusing, because the body.script may, but may not be async. If it is async, then we
|
// The async/await here is very confusing, because the body.script may, but may not be async. If it is async, then we
|
||||||
// need to await it and make the complete response including metadata available in a Promise, so that the route detects
|
// need to await it and make the complete response including metadata available in a Promise, so that the route detects
|
||||||
// this and does result.then().
|
// this and does result.then().
|
||||||
async function exec(req) {
|
async function exec(req: Request) {
|
||||||
try {
|
try {
|
||||||
const { body } = req;
|
const body = (req.body as ScriptBody);
|
||||||
|
|
||||||
const execute = body => scriptService.executeScript(
|
const execute = (body: ScriptBody) => scriptService.executeScript(
|
||||||
body.script,
|
body.script,
|
||||||
body.params,
|
body.params,
|
||||||
body.startNoteId,
|
body.startNoteId,
|
||||||
@ -32,20 +43,20 @@ async function exec(req) {
|
|||||||
maxEntityChangeId: syncService.getMaxEntityChangeId()
|
maxEntityChangeId: syncService.getMaxEntityChangeId()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
return { success: false, error: e.message };
|
return { success: false, error: e.message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function run(req) {
|
function run(req: Request) {
|
||||||
const note = becca.getNote(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
const result = scriptService.executeNote(note, { originEntity: note });
|
const result = scriptService.executeNote(note, { originEntity: note });
|
||||||
|
|
||||||
return { executionResult: result };
|
return { executionResult: result };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBundlesWithLabel(label, value) {
|
function getBundlesWithLabel(label: string, value?: string) {
|
||||||
const notes = attributeService.getNotesWithLabel(label, value);
|
const notes = attributeService.getNotesWithLabel(label, value);
|
||||||
|
|
||||||
const bundles = [];
|
const bundles = [];
|
||||||
@ -61,7 +72,7 @@ function getBundlesWithLabel(label, value) {
|
|||||||
return bundles;
|
return bundles;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStartupBundles(req) {
|
function getStartupBundles(req: Request) {
|
||||||
if (!process.env.TRILIUM_SAFE_MODE) {
|
if (!process.env.TRILIUM_SAFE_MODE) {
|
||||||
if (req.query.mobile === "true") {
|
if (req.query.mobile === "true") {
|
||||||
return getBundlesWithLabel("run", "mobileStartup");
|
return getBundlesWithLabel("run", "mobileStartup");
|
||||||
@ -84,9 +95,9 @@ function getWidgetBundles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRelationBundles(req) {
|
function getRelationBundles(req: Request) {
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
const relationName = req.params.relationName;
|
const relationName = req.params.relationName;
|
||||||
|
|
||||||
const attributes = note.getAttributes();
|
const attributes = note.getAttributes();
|
||||||
@ -97,7 +108,7 @@ function getRelationBundles(req) {
|
|||||||
const bundles = [];
|
const bundles = [];
|
||||||
|
|
||||||
for (const noteId of uniqueNoteIds) {
|
for (const noteId of uniqueNoteIds) {
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
if (!note.isJavaScript() || note.getScriptEnv() !== 'frontend') {
|
if (!note.isJavaScript() || note.getScriptEnv() !== 'frontend') {
|
||||||
continue;
|
continue;
|
||||||
@ -113,14 +124,14 @@ function getRelationBundles(req) {
|
|||||||
return bundles;
|
return bundles;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBundle(req) {
|
function getBundle(req: Request) {
|
||||||
const note = becca.getNote(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
const { script, params } = req.body;
|
const { script, params } = req.body;
|
||||||
|
|
||||||
return scriptService.getScriptBundleForFrontend(note, script, params);
|
return scriptService.getScriptBundleForFrontend(note, script, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
exec,
|
exec,
|
||||||
run,
|
run,
|
||||||
getStartupBundles,
|
getStartupBundles,
|
@ -1,14 +1,17 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const becca = require('../../becca/becca');
|
import { Request } from "express";
|
||||||
const SearchContext = require('../../services/search/search_context');
|
|
||||||
const searchService = require('../../services/search/services/search');
|
|
||||||
const bulkActionService = require('../../services/bulk_actions');
|
|
||||||
const cls = require('../../services/cls');
|
|
||||||
const {formatAttrForSearch} = require('../../services/attribute_formatter');
|
|
||||||
const ValidationError = require('../../errors/validation_error');
|
|
||||||
|
|
||||||
function searchFromNote(req) {
|
import becca = require('../../becca/becca');
|
||||||
|
import SearchContext = require('../../services/search/search_context');
|
||||||
|
import searchService = require('../../services/search/services/search');
|
||||||
|
import bulkActionService = require('../../services/bulk_actions');
|
||||||
|
import cls = require('../../services/cls');
|
||||||
|
import attributeFormatter = require('../../services/attribute_formatter');
|
||||||
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
import SearchResult = require("../../services/search/search_result");
|
||||||
|
|
||||||
|
function searchFromNote(req: Request) {
|
||||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
if (!note) {
|
if (!note) {
|
||||||
@ -23,7 +26,7 @@ function searchFromNote(req) {
|
|||||||
return searchService.searchFromNote(note);
|
return searchService.searchFromNote(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchAndExecute(req) {
|
function searchAndExecute(req: Request) {
|
||||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
if (!note) {
|
if (!note) {
|
||||||
@ -40,7 +43,7 @@ function searchAndExecute(req) {
|
|||||||
bulkActionService.executeActions(note, searchResultNoteIds);
|
bulkActionService.executeActions(note, searchResultNoteIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
function quickSearch(req) {
|
function quickSearch(req: Request) {
|
||||||
const {searchString} = req.params;
|
const {searchString} = req.params;
|
||||||
|
|
||||||
const searchContext = new SearchContext({
|
const searchContext = new SearchContext({
|
||||||
@ -58,7 +61,7 @@ function quickSearch(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function search(req) {
|
function search(req: Request) {
|
||||||
const {searchString} = req.params;
|
const {searchString} = req.params;
|
||||||
|
|
||||||
const searchContext = new SearchContext({
|
const searchContext = new SearchContext({
|
||||||
@ -72,7 +75,7 @@ function search(req) {
|
|||||||
.map(sr => sr.noteId);
|
.map(sr => sr.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRelatedNotes(req) {
|
function getRelatedNotes(req: Request) {
|
||||||
const attr = req.body;
|
const attr = req.body;
|
||||||
|
|
||||||
const searchSettings = {
|
const searchSettings = {
|
||||||
@ -81,10 +84,10 @@ function getRelatedNotes(req) {
|
|||||||
fuzzyAttributeSearch: false
|
fuzzyAttributeSearch: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const matchingNameAndValue = searchService.findResultsWithQuery(formatAttrForSearch(attr, true), new SearchContext(searchSettings));
|
const matchingNameAndValue = searchService.findResultsWithQuery(attributeFormatter.formatAttrForSearch(attr, true), new SearchContext(searchSettings));
|
||||||
const matchingName = searchService.findResultsWithQuery(formatAttrForSearch(attr, false), new SearchContext(searchSettings));
|
const matchingName = searchService.findResultsWithQuery(attributeFormatter.formatAttrForSearch(attr, false), new SearchContext(searchSettings));
|
||||||
|
|
||||||
const results = [];
|
const results: SearchResult[] = [];
|
||||||
|
|
||||||
const allResults = matchingNameAndValue.concat(matchingName);
|
const allResults = matchingNameAndValue.concat(matchingName);
|
||||||
|
|
||||||
@ -123,7 +126,7 @@ function searchTemplates() {
|
|||||||
}).map(note => note.noteId);
|
}).map(note => note.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
searchFromNote,
|
searchFromNote,
|
||||||
searchAndExecute,
|
searchAndExecute,
|
||||||
getRelatedNotes,
|
getRelatedNotes,
|
@ -1,66 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const imageType = require('image-type');
|
|
||||||
const imageService = require('../../services/image');
|
|
||||||
const noteService = require('../../services/notes');
|
|
||||||
const { sanitizeAttributeName } = require('../../services/sanitize_attribute_name');
|
|
||||||
const specialNotesService = require('../../services/special_notes');
|
|
||||||
|
|
||||||
function uploadImage(req) {
|
|
||||||
const file = req.file;
|
|
||||||
|
|
||||||
if (!["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"].includes(file.mimetype)) {
|
|
||||||
return [400, `Unknown image type: ${file.mimetype}`];
|
|
||||||
}
|
|
||||||
|
|
||||||
const originalName = `Sender image.${imageType(file.buffer).ext}`;
|
|
||||||
|
|
||||||
const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']);
|
|
||||||
|
|
||||||
const { note, noteId } = imageService.saveImage(parentNote.noteId, file.buffer, originalName, true);
|
|
||||||
|
|
||||||
const labelsStr = req.headers['x-labels'];
|
|
||||||
|
|
||||||
if (labelsStr?.trim()) {
|
|
||||||
const labels = JSON.parse(labelsStr);
|
|
||||||
|
|
||||||
for (const { name, value } of labels) {
|
|
||||||
note.setLabel(sanitizeAttributeName(name), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
note.setLabel("sentFromSender");
|
|
||||||
|
|
||||||
return {
|
|
||||||
noteId: noteId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveNote(req) {
|
|
||||||
const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']);
|
|
||||||
|
|
||||||
const { note, branch } = noteService.createNewNote({
|
|
||||||
parentNoteId: parentNote.noteId,
|
|
||||||
title: req.body.title,
|
|
||||||
content: req.body.content,
|
|
||||||
isProtected: false,
|
|
||||||
type: 'text',
|
|
||||||
mime: 'text/html'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (req.body.labels) {
|
|
||||||
for (const { name, value } of req.body.labels) {
|
|
||||||
note.setLabel(sanitizeAttributeName(name), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
noteId: note.noteId,
|
|
||||||
branchId: branch.branchId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
uploadImage,
|
|
||||||
saveNote
|
|
||||||
};
|
|
83
src/routes/api/sender.ts
Normal file
83
src/routes/api/sender.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import imageType = require('image-type');
|
||||||
|
import imageService = require('../../services/image');
|
||||||
|
import noteService = require('../../services/notes');
|
||||||
|
import sanitize_attribute_name = require('../../services/sanitize_attribute_name');
|
||||||
|
import specialNotesService = require('../../services/special_notes');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
|
function uploadImage(req: Request) {
|
||||||
|
const file = (req as any).file;
|
||||||
|
|
||||||
|
if (!["image/png", "image/jpeg", "image/gif", "image/webp", "image/svg+xml"].includes(file.mimetype)) {
|
||||||
|
return [400, `Unknown image type: ${file.mimetype}`];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadedImageType = imageType(file.buffer);
|
||||||
|
if (!uploadedImageType) {
|
||||||
|
return [400, "Unable to determine image type."];
|
||||||
|
}
|
||||||
|
const originalName = `Sender image.${uploadedImageType.ext}`;
|
||||||
|
|
||||||
|
if (!req.headers["x-local-date"] || Array.isArray(req.headers["x-local-date"])) {
|
||||||
|
return [400, "Invalid local date"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(req.headers["x-labels"])) {
|
||||||
|
return [400, "Invalid value type."];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']);
|
||||||
|
|
||||||
|
const { note, noteId } = imageService.saveImage(parentNote.noteId, file.buffer, originalName, true);
|
||||||
|
|
||||||
|
const labelsStr = req.headers['x-labels'];
|
||||||
|
|
||||||
|
if (labelsStr?.trim()) {
|
||||||
|
const labels = JSON.parse(labelsStr);
|
||||||
|
|
||||||
|
for (const { name, value } of labels) {
|
||||||
|
note.setLabel(sanitize_attribute_name.sanitizeAttributeName(name), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
note.setLabel("sentFromSender");
|
||||||
|
|
||||||
|
return {
|
||||||
|
noteId: noteId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveNote(req: Request) {
|
||||||
|
if (!req.headers["x-local-date"] || Array.isArray(req.headers["x-local-date"])) {
|
||||||
|
return [400, "Invalid local date"];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']);
|
||||||
|
|
||||||
|
const { note, branch } = noteService.createNewNote({
|
||||||
|
parentNoteId: parentNote.noteId,
|
||||||
|
title: req.body.title,
|
||||||
|
content: req.body.content,
|
||||||
|
isProtected: false,
|
||||||
|
type: 'text',
|
||||||
|
mime: 'text/html'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.body.labels) {
|
||||||
|
for (const { name, value } of req.body.labels) {
|
||||||
|
note.setLabel(sanitize_attribute_name.sanitizeAttributeName(name), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
noteId: note.noteId,
|
||||||
|
branchId: branch.branchId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export = {
|
||||||
|
uploadImage,
|
||||||
|
saveNote
|
||||||
|
};
|
@ -1,9 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sqlInit = require('../../services/sql_init');
|
import sqlInit = require('../../services/sql_init');
|
||||||
const setupService = require('../../services/setup');
|
import setupService = require('../../services/setup');
|
||||||
const log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
const appInfo = require('../../services/app_info');
|
import appInfo = require('../../services/app_info');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
function getStatus() {
|
function getStatus() {
|
||||||
return {
|
return {
|
||||||
@ -17,13 +18,13 @@ async function setupNewDocument() {
|
|||||||
await sqlInit.createInitialDatabase();
|
await sqlInit.createInitialDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupSyncFromServer(req) {
|
function setupSyncFromServer(req: Request) {
|
||||||
const { syncServerHost, syncProxy, password } = req.body;
|
const { syncServerHost, syncProxy, password } = req.body;
|
||||||
|
|
||||||
return setupService.setupSyncFromSyncServer(syncServerHost, syncProxy, password);
|
return setupService.setupSyncFromSyncServer(syncServerHost, syncProxy, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSyncSeed(req) {
|
function saveSyncSeed(req: Request) {
|
||||||
const { options, syncVersion } = req.body;
|
const { options, syncVersion } = req.body;
|
||||||
|
|
||||||
if (appInfo.syncVersion !== syncVersion) {
|
if (appInfo.syncVersion !== syncVersion) {
|
||||||
@ -50,7 +51,7 @@ function getSyncSeed() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getStatus,
|
getStatus,
|
||||||
setupNewDocument,
|
setupNewDocument,
|
||||||
setupSyncFromServer,
|
setupSyncFromServer,
|
@ -1,16 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const similarityService = require('../../becca/similarity');
|
|
||||||
const becca = require('../../becca/becca');
|
|
||||||
|
|
||||||
async function getSimilarNotes(req) {
|
|
||||||
const noteId = req.params.noteId;
|
|
||||||
|
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
|
||||||
|
|
||||||
return await similarityService.findSimilarNotes(noteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getSimilarNotes
|
|
||||||
};
|
|
18
src/routes/api/similar_notes.ts
Normal file
18
src/routes/api/similar_notes.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { Request } from "express";
|
||||||
|
|
||||||
|
import similarityService = require('../../becca/similarity');
|
||||||
|
import becca = require('../../becca/becca');
|
||||||
|
|
||||||
|
async function getSimilarNotes(req: Request) {
|
||||||
|
const noteId = req.params.noteId;
|
||||||
|
|
||||||
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
|
|
||||||
|
return await similarityService.findSimilarNotes(noteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export = {
|
||||||
|
getSimilarNotes
|
||||||
|
};
|
@ -1,32 +1,33 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const dateNoteService = require('../../services/date_notes');
|
import dateNoteService = require('../../services/date_notes');
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const cls = require('../../services/cls');
|
import cls = require('../../services/cls');
|
||||||
const specialNotesService = require('../../services/special_notes');
|
import specialNotesService = require('../../services/special_notes');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
function getInboxNote(req) {
|
function getInboxNote(req: Request) {
|
||||||
return specialNotesService.getInboxNote(req.params.date);
|
return specialNotesService.getInboxNote(req.params.date);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDayNote(req) {
|
function getDayNote(req: Request) {
|
||||||
return dateNoteService.getDayNote(req.params.date);
|
return dateNoteService.getDayNote(req.params.date);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWeekNote(req) {
|
function getWeekNote(req: Request) {
|
||||||
return dateNoteService.getWeekNote(req.params.date);
|
return dateNoteService.getWeekNote(req.params.date);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMonthNote(req) {
|
function getMonthNote(req: Request) {
|
||||||
return dateNoteService.getMonthNote(req.params.month);
|
return dateNoteService.getMonthNote(req.params.month);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getYearNote(req) {
|
function getYearNote(req: Request) {
|
||||||
return dateNoteService.getYearNote(req.params.year);
|
return dateNoteService.getYearNote(req.params.year);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDayNotesForMonth(req) {
|
function getDayNotesForMonth(req: Request) {
|
||||||
const month = req.params.month;
|
const month = req.params.month;
|
||||||
|
|
||||||
return sql.getMap(`
|
return sql.getMap(`
|
||||||
@ -42,7 +43,7 @@ function getDayNotesForMonth(req) {
|
|||||||
AND attr.value LIKE '${month}%'`);
|
AND attr.value LIKE '${month}%'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSqlConsole(req) {
|
function saveSqlConsole(req: Request) {
|
||||||
return specialNotesService.saveSqlConsole(req.body.sqlConsoleNoteId);
|
return specialNotesService.saveSqlConsole(req.body.sqlConsoleNoteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,14 +51,14 @@ function createSqlConsole() {
|
|||||||
return specialNotesService.createSqlConsole();
|
return specialNotesService.createSqlConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSearchNote(req) {
|
function saveSearchNote(req: Request) {
|
||||||
return specialNotesService.saveSearchNote(req.body.searchNoteId);
|
return specialNotesService.saveSearchNote(req.body.searchNoteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSearchNote(req) {
|
function createSearchNote(req: Request) {
|
||||||
const hoistedNote = getHoistedNote();
|
const hoistedNote = getHoistedNote();
|
||||||
const searchString = req.body.searchString || "";
|
const searchString = req.body.searchString || "";
|
||||||
const ancestorNoteId = req.body.ancestorNoteId || hoistedNote.noteId;
|
const ancestorNoteId = req.body.ancestorNoteId || hoistedNote?.noteId;
|
||||||
|
|
||||||
return specialNotesService.createSearchNote(searchString, ancestorNoteId);
|
return specialNotesService.createSearchNote(searchString, ancestorNoteId);
|
||||||
}
|
}
|
||||||
@ -66,22 +67,22 @@ function getHoistedNote() {
|
|||||||
return becca.getNote(cls.getHoistedNoteId());
|
return becca.getNote(cls.getHoistedNoteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLauncher(req) {
|
function createLauncher(req: Request) {
|
||||||
return specialNotesService.createLauncher({
|
return specialNotesService.createLauncher({
|
||||||
parentNoteId: req.params.parentNoteId,
|
parentNoteId: req.params.parentNoteId,
|
||||||
launcherType: req.params.launcherType
|
launcherType: req.params.launcherType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetLauncher(req) {
|
function resetLauncher(req: Request) {
|
||||||
return specialNotesService.resetLauncher(req.params.noteId);
|
return specialNotesService.resetLauncher(req.params.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createOrUpdateScriptLauncherFromApi(req) {
|
function createOrUpdateScriptLauncherFromApi(req: Request) {
|
||||||
return specialNotesService.createOrUpdateScriptLauncherFromApi(req.body);
|
return specialNotesService.createOrUpdateScriptLauncherFromApi(req.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getInboxNote,
|
getInboxNote,
|
||||||
getDayNote,
|
getDayNote,
|
||||||
getWeekNote,
|
getWeekNote,
|
@ -1,7 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
|
||||||
function getSchema() {
|
function getSchema() {
|
||||||
const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
||||||
@ -17,10 +19,15 @@ function getSchema() {
|
|||||||
return tables;
|
return tables;
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(req) {
|
function execute(req: Request) {
|
||||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
const queries = note.getContent().split("\n---");
|
const content = note.getContent();
|
||||||
|
if (typeof content !== "string") {
|
||||||
|
throw new ValidationError("Invalid note type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const queries = content.split("\n---");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = [];
|
const results = [];
|
||||||
@ -51,7 +58,7 @@ function execute(req) {
|
|||||||
results
|
results
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: e.message
|
error: e.message
|
||||||
@ -59,7 +66,7 @@ function execute(req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getSchema,
|
getSchema,
|
||||||
execute
|
execute
|
||||||
};
|
};
|
@ -1,10 +1,11 @@
|
|||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
|
import { Request } from 'express';
|
||||||
|
|
||||||
function getNoteSize(req) {
|
function getNoteSize(req: Request) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
|
|
||||||
const blobSizes = sql.getMap(`
|
const blobSizes = sql.getMap<string, number>(`
|
||||||
SELECT blobs.blobId, LENGTH(content)
|
SELECT blobs.blobId, LENGTH(content)
|
||||||
FROM blobs
|
FROM blobs
|
||||||
LEFT JOIN notes ON notes.blobId = blobs.blobId AND notes.noteId = ? AND notes.isDeleted = 0
|
LEFT JOIN notes ON notes.blobId = blobs.blobId AND notes.noteId = ? AND notes.isDeleted = 0
|
||||||
@ -21,14 +22,14 @@ function getNoteSize(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSubtreeSize(req) {
|
function getSubtreeSize(req: Request) {
|
||||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||||
|
|
||||||
const subTreeNoteIds = note.getSubtreeNoteIds();
|
const subTreeNoteIds = note.getSubtreeNoteIds();
|
||||||
|
|
||||||
sql.fillParamList(subTreeNoteIds);
|
sql.fillParamList(subTreeNoteIds);
|
||||||
|
|
||||||
const blobSizes = sql.getMap(`
|
const blobSizes = sql.getMap<string, number>(`
|
||||||
SELECT blobs.blobId, LENGTH(content)
|
SELECT blobs.blobId, LENGTH(content)
|
||||||
FROM param_list
|
FROM param_list
|
||||||
JOIN notes ON notes.noteId = param_list.paramId AND notes.isDeleted = 0
|
JOIN notes ON notes.noteId = param_list.paramId AND notes.isDeleted = 0
|
||||||
@ -44,7 +45,7 @@ function getSubtreeSize(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getNoteSize,
|
getNoteSize,
|
||||||
getSubtreeSize
|
getSubtreeSize
|
||||||
};
|
};
|
@ -1,16 +1,19 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const syncService = require('../../services/sync');
|
import syncService = require('../../services/sync');
|
||||||
const syncUpdateService = require('../../services/sync_update');
|
import syncUpdateService = require('../../services/sync_update');
|
||||||
const entityChangesService = require('../../services/entity_changes');
|
import entityChangesService = require('../../services/entity_changes');
|
||||||
const sql = require('../../services/sql');
|
import sql = require('../../services/sql');
|
||||||
const sqlInit = require('../../services/sql_init');
|
import sqlInit = require('../../services/sql_init');
|
||||||
const optionService = require('../../services/options');
|
import optionService = require('../../services/options');
|
||||||
const contentHashService = require('../../services/content_hash');
|
import contentHashService = require('../../services/content_hash');
|
||||||
const log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
const syncOptions = require('../../services/sync_options');
|
import syncOptions = require('../../services/sync_options');
|
||||||
const utils = require('../../services/utils');
|
import utils = require('../../services/utils');
|
||||||
const ws = require('../../services/ws');
|
import ws = require('../../services/ws');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { EntityChange, EntityChangeRecord } from '../../services/entity_changes_interface';
|
||||||
|
import ValidationError = require('../../errors/validation_error');
|
||||||
|
|
||||||
async function testSync() {
|
async function testSync() {
|
||||||
try {
|
try {
|
||||||
@ -26,7 +29,7 @@ async function testSync() {
|
|||||||
|
|
||||||
return { success: true, message: "Sync server handshake has been successful, sync has been started." };
|
return { success: true, message: "Sync server handshake has been successful, sync has been started." };
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: e.message
|
message: e.message
|
||||||
@ -82,15 +85,19 @@ function forceFullSync() {
|
|||||||
syncService.sync();
|
syncService.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChanged(req) {
|
function getChanged(req: Request) {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
let lastEntityChangeId = parseInt(req.query.lastEntityChangeId);
|
if (typeof req.query.lastEntityChangeId !== "string") {
|
||||||
|
throw new ValidationError("Missing or invalid last entity change ID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastEntityChangeId: number | null | undefined = parseInt(req.query.lastEntityChangeId);
|
||||||
const clientInstanceId = req.query.instanceId;
|
const clientInstanceId = req.query.instanceId;
|
||||||
let filteredEntityChanges = [];
|
let filteredEntityChanges: EntityChange[] = [];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const entityChanges = sql.getRows(`
|
const entityChanges: EntityChange[] = sql.getRows<EntityChange>(`
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM entity_changes
|
FROM entity_changes
|
||||||
WHERE isSynced = 1
|
WHERE isSynced = 1
|
||||||
@ -129,16 +136,22 @@ function getChanged(req) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const partialRequests = {};
|
const partialRequests: Record<string, {
|
||||||
|
createdAt: number,
|
||||||
|
payload: string
|
||||||
|
}> = {};
|
||||||
|
|
||||||
function update(req) {
|
function update(req: Request) {
|
||||||
let { body } = req;
|
let { body } = req;
|
||||||
|
|
||||||
const pageCount = parseInt(req.get('pageCount'));
|
const pageCount = parseInt(req.get('pageCount') as string);
|
||||||
const pageIndex = parseInt(req.get('pageIndex'));
|
const pageIndex = parseInt(req.get('pageIndex') as string);
|
||||||
|
|
||||||
if (pageCount !== 1) {
|
if (pageCount !== 1) {
|
||||||
const requestId = req.get('requestId');
|
const requestId = req.get('requestId');
|
||||||
|
if (!requestId) {
|
||||||
|
throw new Error("Missing request ID.");
|
||||||
|
}
|
||||||
|
|
||||||
if (pageIndex === 0) {
|
if (pageIndex === 0) {
|
||||||
partialRequests[requestId] = {
|
partialRequests[requestId] = {
|
||||||
@ -185,7 +198,7 @@ function syncFinished() {
|
|||||||
sqlInit.setDbAsInitialized();
|
sqlInit.setDbAsInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
function queueSector(req) {
|
function queueSector(req: Request) {
|
||||||
const entityName = utils.sanitizeSqlIdentifier(req.params.entityName);
|
const entityName = utils.sanitizeSqlIdentifier(req.params.entityName);
|
||||||
const sector = utils.sanitizeSqlIdentifier(req.params.sector);
|
const sector = utils.sanitizeSqlIdentifier(req.params.sector);
|
||||||
|
|
||||||
@ -196,7 +209,7 @@ function checkEntityChanges() {
|
|||||||
require('../../services/consistency_checks').runEntityChangesChecks();
|
require('../../services/consistency_checks').runEntityChangesChecks();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
testSync,
|
testSync,
|
||||||
checkSync,
|
checkSync,
|
||||||
syncNow,
|
syncNow,
|
@ -1,16 +1,18 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const becca = require('../../becca/becca');
|
import becca = require('../../becca/becca');
|
||||||
const log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
const NotFoundError = require('../../errors/not_found_error');
|
import NotFoundError = require('../../errors/not_found_error');
|
||||||
|
import { Request } from 'express';
|
||||||
|
import BNote = require('../../becca/entities/bnote');
|
||||||
|
|
||||||
function getNotesAndBranchesAndAttributes(noteIds) {
|
function getNotesAndBranchesAndAttributes(_noteIds: string[] | Set<string>) {
|
||||||
noteIds = new Set(noteIds);
|
const noteIds = new Set(_noteIds);
|
||||||
const collectedNoteIds = new Set();
|
const collectedNoteIds = new Set<string>();
|
||||||
const collectedAttributeIds = new Set();
|
const collectedAttributeIds = new Set<string>();
|
||||||
const collectedBranchIds = new Set();
|
const collectedBranchIds = new Set<string>();
|
||||||
|
|
||||||
function collectEntityIds(note) {
|
function collectEntityIds(note?: BNote) {
|
||||||
if (!note || collectedNoteIds.has(note.noteId)) {
|
if (!note || collectedNoteIds.has(note.noteId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -18,15 +20,18 @@ function getNotesAndBranchesAndAttributes(noteIds) {
|
|||||||
collectedNoteIds.add(note.noteId);
|
collectedNoteIds.add(note.noteId);
|
||||||
|
|
||||||
for (const branch of note.getParentBranches()) {
|
for (const branch of note.getParentBranches()) {
|
||||||
collectedBranchIds.add(branch.branchId);
|
if (branch.branchId) {
|
||||||
|
collectedBranchIds.add(branch.branchId);
|
||||||
|
}
|
||||||
|
|
||||||
collectEntityIds(branch.parentNote);
|
collectEntityIds(branch.parentNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const childNote of note.children) {
|
for (const childNote of note.children) {
|
||||||
const childBranch = becca.getBranchFromChildAndParent(childNote.noteId, note.noteId);
|
const childBranch = becca.getBranchFromChildAndParent(childNote.noteId, note.noteId);
|
||||||
|
if (childBranch && childBranch.branchId) {
|
||||||
collectedBranchIds.add(childBranch.branchId);
|
collectedBranchIds.add(childBranch.branchId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const attr of note.ownedAttributes) {
|
for (const attr of note.ownedAttributes) {
|
||||||
@ -122,11 +127,11 @@ function getNotesAndBranchesAndAttributes(noteIds) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTree(req) {
|
function getTree(req: Request) {
|
||||||
const subTreeNoteId = req.query.subTreeNoteId || 'root';
|
const subTreeNoteId = typeof req.query.subTreeNoteId === "string" ? req.query.subTreeNoteId : 'root';
|
||||||
const collectedNoteIds = new Set([subTreeNoteId]);
|
const collectedNoteIds = new Set<string>([subTreeNoteId]);
|
||||||
|
|
||||||
function collect(parentNote) {
|
function collect(parentNote: BNote) {
|
||||||
if (!parentNote) {
|
if (!parentNote) {
|
||||||
console.trace(parentNote);
|
console.trace(parentNote);
|
||||||
}
|
}
|
||||||
@ -136,7 +141,7 @@ function getTree(req) {
|
|||||||
|
|
||||||
const childBranch = becca.getBranchFromChildAndParent(childNote.noteId, parentNote.noteId);
|
const childBranch = becca.getBranchFromChildAndParent(childNote.noteId, parentNote.noteId);
|
||||||
|
|
||||||
if (childBranch.isExpanded) {
|
if (childBranch?.isExpanded) {
|
||||||
collect(childBranch.childNote);
|
collect(childBranch.childNote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,11 +156,11 @@ function getTree(req) {
|
|||||||
return getNotesAndBranchesAndAttributes(collectedNoteIds);
|
return getNotesAndBranchesAndAttributes(collectedNoteIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
function load(req) {
|
function load(req: Request) {
|
||||||
return getNotesAndBranchesAndAttributes(req.body.noteIds);
|
return getNotesAndBranchesAndAttributes(req.body.noteIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getTree,
|
getTree,
|
||||||
load
|
load
|
||||||
};
|
};
|
@ -17,48 +17,48 @@ const NotFoundError = require('../errors/not_found_error');
|
|||||||
const ValidationError = require('../errors/validation_error');
|
const ValidationError = require('../errors/validation_error');
|
||||||
|
|
||||||
// page routes
|
// page routes
|
||||||
const setupRoute = require('./setup.js');
|
const setupRoute = require('./setup');
|
||||||
const loginRoute = require('./login.js');
|
const loginRoute = require('./login.js');
|
||||||
const indexRoute = require('./index.js');
|
const indexRoute = require('./index.js');
|
||||||
|
|
||||||
// API routes
|
// API routes
|
||||||
const treeApiRoute = require('./api/tree.js');
|
const treeApiRoute = require('./api/tree');
|
||||||
const notesApiRoute = require('./api/notes.js');
|
const notesApiRoute = require('./api/notes');
|
||||||
const branchesApiRoute = require('./api/branches');
|
const branchesApiRoute = require('./api/branches');
|
||||||
const attachmentsApiRoute = require('./api/attachments');
|
const attachmentsApiRoute = require('./api/attachments');
|
||||||
const autocompleteApiRoute = require('./api/autocomplete');
|
const autocompleteApiRoute = require('./api/autocomplete');
|
||||||
const cloningApiRoute = require('./api/cloning');
|
const cloningApiRoute = require('./api/cloning');
|
||||||
const revisionsApiRoute = require('./api/revisions');
|
const revisionsApiRoute = require('./api/revisions');
|
||||||
const recentChangesApiRoute = require('./api/recent_changes.js');
|
const recentChangesApiRoute = require('./api/recent_changes');
|
||||||
const optionsApiRoute = require('./api/options.js');
|
const optionsApiRoute = require('./api/options');
|
||||||
const passwordApiRoute = require('./api/password');
|
const passwordApiRoute = require('./api/password');
|
||||||
const syncApiRoute = require('./api/sync');
|
const syncApiRoute = require('./api/sync');
|
||||||
const loginApiRoute = require('./api/login.js');
|
const loginApiRoute = require('./api/login');
|
||||||
const recentNotesRoute = require('./api/recent_notes.js');
|
const recentNotesRoute = require('./api/recent_notes');
|
||||||
const appInfoRoute = require('./api/app_info');
|
const appInfoRoute = require('./api/app_info');
|
||||||
const exportRoute = require('./api/export');
|
const exportRoute = require('./api/export');
|
||||||
const importRoute = require('./api/import.js');
|
const importRoute = require('./api/import');
|
||||||
const setupApiRoute = require('./api/setup.js');
|
const setupApiRoute = require('./api/setup');
|
||||||
const sqlRoute = require('./api/sql');
|
const sqlRoute = require('./api/sql');
|
||||||
const databaseRoute = require('./api/database');
|
const databaseRoute = require('./api/database');
|
||||||
const imageRoute = require('./api/image');
|
const imageRoute = require('./api/image');
|
||||||
const attributesRoute = require('./api/attributes');
|
const attributesRoute = require('./api/attributes');
|
||||||
const scriptRoute = require('./api/script.js');
|
const scriptRoute = require('./api/script');
|
||||||
const senderRoute = require('./api/sender.js');
|
const senderRoute = require('./api/sender');
|
||||||
const filesRoute = require('./api/files');
|
const filesRoute = require('./api/files');
|
||||||
const searchRoute = require('./api/search');
|
const searchRoute = require('./api/search');
|
||||||
const bulkActionRoute = require('./api/bulk_action');
|
const bulkActionRoute = require('./api/bulk_action');
|
||||||
const specialNotesRoute = require('./api/special_notes');
|
const specialNotesRoute = require('./api/special_notes');
|
||||||
const noteMapRoute = require('./api/note_map.js');
|
const noteMapRoute = require('./api/note_map');
|
||||||
const clipperRoute = require('./api/clipper');
|
const clipperRoute = require('./api/clipper');
|
||||||
const similarNotesRoute = require('./api/similar_notes.js');
|
const similarNotesRoute = require('./api/similar_notes');
|
||||||
const keysRoute = require('./api/keys.js');
|
const keysRoute = require('./api/keys');
|
||||||
const backendLogRoute = require('./api/backend_log');
|
const backendLogRoute = require('./api/backend_log');
|
||||||
const statsRoute = require('./api/stats.js');
|
const statsRoute = require('./api/stats');
|
||||||
const fontsRoute = require('./api/fonts');
|
const fontsRoute = require('./api/fonts');
|
||||||
const etapiTokensApiRoutes = require('./api/etapi_tokens');
|
const etapiTokensApiRoutes = require('./api/etapi_tokens');
|
||||||
const relationMapApiRoute = require('./api/relation-map');
|
const relationMapApiRoute = require('./api/relation-map');
|
||||||
const otherRoute = require('./api/other.js');
|
const otherRoute = require('./api/other');
|
||||||
const shareRoutes = require('../share/routes.js');
|
const shareRoutes = require('../share/routes.js');
|
||||||
|
|
||||||
const etapiAuthRoutes = require('../etapi/auth.js');
|
const etapiAuthRoutes = require('../etapi/auth.js');
|
||||||
|
@ -44,7 +44,7 @@ function subscribeBeccaLoader(eventTypes: EventType, listener: EventListener) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function emit(eventType: string, data: any) {
|
function emit(eventType: string, data?: any) {
|
||||||
const listeners = eventListeners[eventType];
|
const listeners = eventListeners[eventType];
|
||||||
|
|
||||||
if (listeners) {
|
if (listeners) {
|
||||||
|
@ -55,7 +55,7 @@ interface Note {
|
|||||||
let note: Partial<Note> = {};
|
let note: Partial<Note> = {};
|
||||||
let resource: Resource;
|
let resource: Resource;
|
||||||
|
|
||||||
function importEnex(taskContext: TaskContext, file: File, parentNote: BNote) {
|
function importEnex(taskContext: TaskContext, file: File, parentNote: BNote): Promise<BNote> {
|
||||||
const saxStream = sax.createStream(true);
|
const saxStream = sax.createStream(true);
|
||||||
|
|
||||||
const rootNoteTitle = file.originalname.toLowerCase().endsWith(".enex")
|
const rootNoteTitle = file.originalname.toLowerCase().endsWith(".enex")
|
||||||
|
@ -251,7 +251,7 @@ function createNewNote(params: NoteParams): {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewNoteWithTarget(target: ("into" | "after"), targetBranchId: string, params: NoteParams) {
|
function createNewNoteWithTarget(target: ("into" | "after"), targetBranchId: string | undefined, params: NoteParams) {
|
||||||
if (!params.type) {
|
if (!params.type) {
|
||||||
const parentNote = becca.notes[params.parentNoteId];
|
const parentNote = becca.notes[params.parentNoteId];
|
||||||
|
|
||||||
@ -263,7 +263,7 @@ function createNewNoteWithTarget(target: ("into" | "after"), targetBranchId: str
|
|||||||
if (target === 'into') {
|
if (target === 'into') {
|
||||||
return createNewNote(params);
|
return createNewNote(params);
|
||||||
}
|
}
|
||||||
else if (target === 'after') {
|
else if (target === 'after' && targetBranchId) {
|
||||||
const afterBranch = becca.branches[targetBranchId];
|
const afterBranch = becca.branches[targetBranchId];
|
||||||
|
|
||||||
// not updating utcDateModified to avoid having to sync whole rows
|
// not updating utcDateModified to avoid having to sync whole rows
|
||||||
|
@ -106,7 +106,7 @@ function execute(ctx: ScriptContext, script: string) {
|
|||||||
return function () { return eval(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx);
|
return function () { return eval(`const apiContext = this;\r\n(${script}\r\n)()`); }.call(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getParams(params: ScriptParams) {
|
function getParams(params?: ScriptParams) {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ function getParams(params: ScriptParams) {
|
|||||||
}).join(",");
|
}).join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getScriptBundleForFrontend(note: BNote, script: string, params: ScriptParams) {
|
function getScriptBundleForFrontend(note: BNote, script?: string, params?: ScriptParams) {
|
||||||
let overrideContent = null;
|
let overrideContent = null;
|
||||||
|
|
||||||
if (script) {
|
if (script) {
|
||||||
|
@ -110,7 +110,7 @@ function getSyncSeedOptions() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
hasSyncServerSchemaAndSeed,
|
hasSyncServerSchemaAndSeed,
|
||||||
triggerSync,
|
triggerSync,
|
||||||
sendSeedToSyncServer,
|
sendSeedToSyncServer,
|
||||||
|
@ -166,7 +166,7 @@ function createScriptLauncher(parentNoteId: string, forceNoteId?: string) {
|
|||||||
interface LauncherConfig {
|
interface LauncherConfig {
|
||||||
parentNoteId: string;
|
parentNoteId: string;
|
||||||
launcherType: string;
|
launcherType: string;
|
||||||
noteId: string;
|
noteId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLauncher({ parentNoteId, launcherType, noteId }: LauncherConfig) {
|
function createLauncher({ parentNoteId, launcherType, noteId }: LauncherConfig) {
|
||||||
|
@ -269,8 +269,8 @@ function transactional<T>(func: (statement: Statement) => T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillParamList(paramIds: string[], truncate = true) {
|
function fillParamList(paramIds: string[] | Set<string>, truncate = true) {
|
||||||
if (paramIds.length === 0) {
|
if ("length" in paramIds && paramIds.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class TaskContext {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
taskSucceeded(result?: string) {
|
taskSucceeded(result?: string | Record<string, string | undefined>) {
|
||||||
ws.sendMessageToAllClients({
|
ws.sendMessageToAllClients({
|
||||||
type: 'taskSucceeded',
|
type: 'taskSucceeded',
|
||||||
taskId: this.taskId,
|
taskId: this.taskId,
|
||||||
|
@ -41,7 +41,7 @@ interface Message {
|
|||||||
taskType?: string | null;
|
taskType?: string | null;
|
||||||
message?: string;
|
message?: string;
|
||||||
reason?: string;
|
reason?: string;
|
||||||
result?: string;
|
result?: string | Record<string, string | undefined>;
|
||||||
|
|
||||||
script?: string;
|
script?: string;
|
||||||
params?: any[];
|
params?: any[];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user