From 2c5681ba88c422a92737a9c109021aef8deff2f4 Mon Sep 17 00:00:00 2001 From: alexpietsch <54153428+alexpietsch@users.noreply.github.com> Date: Thu, 30 May 2024 17:25:16 +0200 Subject: [PATCH] format some files --- src/becca/becca-interface.ts | 31 ++-- src/routes/assets.ts | 22 +-- src/routes/index.ts | 14 +- src/routes/route-interface.ts | 27 ++-- src/routes/routes.ts | 130 ++++++++------- src/services/anonymization.ts | 27 ++-- src/services/backend_script_api.ts | 251 ++++++++++++++++------------- 7 files changed, 257 insertions(+), 245 deletions(-) diff --git a/src/becca/becca-interface.ts b/src/becca/becca-interface.ts index 21892676d..e02b94bd2 100644 --- a/src/becca/becca-interface.ts +++ b/src/becca/becca-interface.ts @@ -8,7 +8,7 @@ import BAttribute = require('./entities/battribute'); import BBranch = require('./entities/bbranch'); import BRevision = require('./entities/brevision'); import BAttachment = require('./entities/battachment'); -import { AttachmentRow, RevisionRow } from './entities/rows'; +import {AttachmentRow, RevisionRow} from './entities/rows'; import BBlob = require('./entities/bblob'); import BRecentNote = require('./entities/brecent_note'); import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); @@ -44,7 +44,7 @@ export default class Becca { this.notes = {}; this.branches = {}; this.childParentToBranch = {}; - this.attributes = {}; + this.attributes = {}; this.attributeIndex = {}; this.options = {}; this.etapiTokens = {}; @@ -155,7 +155,7 @@ export default class Becca { } getRevision(revisionId: string): BRevision | null { - const row = sql.getRow("SELECT * FROM revisions WHERE revisionId = ?", [revisionId]); + const row = sql.getRow('SELECT * FROM revisions WHERE revisionId = ?', [revisionId]); const BRevision = require('./entities/brevision'); // avoiding circular dependency problems return row ? new BRevision(row) : null; @@ -181,8 +181,7 @@ export default class Becca { const BAttachment = require('./entities/battachment'); // avoiding circular dependency problems - return sql.getRows(query, [attachmentId]) - .map(row => new BAttachment(row))[0]; + return sql.getRows(query, [attachmentId]).map((row) => new BAttachment(row))[0]; } getAttachmentOrThrow(attachmentId: string, opts: AttachmentOpts = {}): BAttachment { @@ -195,16 +194,15 @@ export default class Becca { getAttachments(attachmentIds: string[]): BAttachment[] { const BAttachment = require('./entities/battachment'); // avoiding circular dependency problems - return sql.getManyRows("SELECT * FROM attachments WHERE attachmentId IN (???) AND isDeleted = 0", attachmentIds) - .map(row => new BAttachment(row)); + return sql.getManyRows('SELECT * FROM attachments WHERE attachmentId IN (???) AND isDeleted = 0', attachmentIds).map((row) => new BAttachment(row)); } - getBlob(entity: { blobId?: string }): BBlob | null { + getBlob(entity: {blobId?: string}): BBlob | null { if (!entity.blobId) { return null; } - const row = sql.getRow("SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?", [entity.blobId]); + const row = sql.getRow('SELECT *, LENGTH(content) AS contentLength FROM blobs WHERE blobId = ?', [entity.blobId]); const BBlob = require('./entities/bblob'); // avoiding circular dependency problems return row ? new BBlob(row) : null; @@ -233,12 +231,7 @@ export default class Becca { return this.getAttachment(entityId); } - const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g, - group => - group - .toUpperCase() - .replace('_', '') - ); + const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g, (group) => group.toUpperCase().replace('_', '')); if (!(camelCaseEntityName in this)) { throw new Error(`Unknown entity name '${camelCaseEntityName}' (original argument '${entityName}')`); @@ -251,14 +244,14 @@ export default class Becca { const rows = sql.getRows(query, params); const BRecentNote = require('./entities/brecent_note'); // avoiding circular dependency problems - return rows.map(row => new BRecentNote(row)); + return rows.map((row) => new BRecentNote(row)); } getRevisionsFromQuery(query: string, params: string[] = []): BRevision[] { const rows = sql.getRows(query, params); const BRevision = require('./entities/brevision'); // avoiding circular dependency problems - return rows.map(row => new BRevision(row)); + return rows.map((row) => new BRevision(row)); } /** Should be called when the set of all non-skeleton notes changes (added/removed) */ @@ -290,7 +283,7 @@ export default class Becca { /** * This interface contains the data that is shared across all the objects of a given derived class of {@link AbstractBeccaEntity}. - * For example, all BAttributes will share their content, but all BBranches will have another set of this data. + * For example, all BAttributes will share their content, but all BBranches will have another set of this data. */ export interface ConstructorData> { primaryKeyName: string; @@ -310,4 +303,4 @@ export interface NotePojo { dateModified?: string; utcDateCreated: string; utcDateModified?: string; -} \ No newline at end of file +} diff --git a/src/routes/assets.ts b/src/routes/assets.ts index 6ebfd8313..cc4311df7 100644 --- a/src/routes/assets.ts +++ b/src/routes/assets.ts @@ -1,6 +1,6 @@ import assetPath = require('../services/asset_path'); -import path = require("path"); -import express = require("express"); +import path = require('path'); +import express = require('express'); import env = require('../services/env'); import serveStatic = require('serve-static'); @@ -37,20 +37,12 @@ function register(app: express.Application) { app.use(`/${assetPath}/node_modules/@excalidraw/excalidraw/dist/`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/@excalidraw/excalidraw/dist/'))); // KaTeX - app.use( - `/${assetPath}/node_modules/katex/dist/katex.min.js`, - persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/katex.min.js'))); - app.use( - `/${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js`, - persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/mhchem.min.js'))); - app.use( - `/${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js`, - persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/auto-render.min.js'))); + app.use(`/${assetPath}/node_modules/katex/dist/katex.min.js`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/katex.min.js'))); + app.use(`/${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/mhchem.min.js'))); + app.use(`/${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/auto-render.min.js'))); // expose the whole dist folder - app.use(`/node_modules/katex/dist/`, - express.static(path.join(srcRoot, '..', 'node_modules/katex/dist/'))); - app.use(`/${assetPath}/node_modules/katex/dist/`, - persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/'))); + app.use(`/node_modules/katex/dist/`, express.static(path.join(srcRoot, '..', 'node_modules/katex/dist/'))); + app.use(`/${assetPath}/node_modules/katex/dist/`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/'))); app.use(`/${assetPath}/node_modules/dayjs/`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/dayjs/'))); app.use(`/${assetPath}/node_modules/force-graph/dist/`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/force-graph/dist/'))); diff --git a/src/routes/index.ts b/src/routes/index.ts index 2ede70f42..189371500 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; import sql = require('../services/sql'); import attributeService = require('../services/attributes'); @@ -11,14 +11,12 @@ import protectedSessionService = require('../services/protected_session'); import packageJson = require('../../package.json'); import assetPath = require('../services/asset_path'); import appPath = require('../services/app_path'); -import { Request, Response } from 'express'; +import {Request, Response} from 'express'; function index(req: Request, res: Response) { const options = optionService.getOptionMap(); - const view = (!utils.isElectron() && req.cookies['trilium-device'] === 'mobile') - ? 'mobile' - : 'desktop'; + const view = !utils.isElectron() && req.cookies['trilium-device'] === 'mobile' ? 'mobile' : 'desktop'; const csrfToken = req.csrfToken(); log.info(`Generated CSRF token ${csrfToken} with secret ${res.getHeader('set-cookie')}`); @@ -30,8 +28,8 @@ function index(req: Request, res: Response) { mainFontSize: parseInt(options.mainFontSize), treeFontSize: parseInt(options.treeFontSize), detailFontSize: parseInt(options.detailFontSize), - maxEntityChangeIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes"), - maxEntityChangeSyncIdAtLoad: sql.getValue("SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1"), + maxEntityChangeIdAtLoad: sql.getValue('SELECT COALESCE(MAX(id), 0) FROM entity_changes'), + maxEntityChangeSyncIdAtLoad: sql.getValue('SELECT COALESCE(MAX(id), 0) FROM entity_changes WHERE isSynced = 1'), instanceName: config.General ? config.General.instanceName : null, appCssNoteIds: getAppCssNoteIds(), isDev: env.isDev(), @@ -61,7 +59,7 @@ function getThemeCssUrl(theme: string) { } function getAppCssNoteIds() { - return attributeService.getNotesWithLabel('appCss').map(note => note.noteId); + return attributeService.getNotesWithLabel('appCss').map((note) => note.noteId); } export = { diff --git a/src/routes/route-interface.ts b/src/routes/route-interface.ts index 4510c5de6..5a4701cf7 100644 --- a/src/routes/route-interface.ts +++ b/src/routes/route-interface.ts @@ -1,21 +1,18 @@ -import { NextFunction, Request, Response } from "express"; -import { Session, SessionData } from "express-session"; +import {NextFunction, Request, Response} from 'express'; +import {Session, SessionData} from 'express-session'; export interface AppRequest extends Request { headers: { authorization?: string; - "trilium-cred"?: string; - "x-local-date"?: string; - "x-labels"?: string; - "trilium-local-now-datetime"?: string; - } - session: Session & Partial & { - loggedIn: boolean; - } + 'trilium-cred'?: string; + 'x-local-date'?: string; + 'x-labels'?: string; + 'trilium-local-now-datetime'?: string; + }; + session: Session & + Partial & { + loggedIn: boolean; + }; } -export type AppRequestHandler = ( - req: AppRequest, - res: Response, - next: NextFunction -) => void; \ No newline at end of file +export type AppRequestHandler = (req: AppRequest, res: Response, next: NextFunction) => void; diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 55cad4cd5..a3f2d4af1 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; import utils = require('../services/utils'); import multer = require('multer'); @@ -10,8 +10,8 @@ import cls = require('../services/cls'); import sql = require('../services/sql'); import entityChangesService = require('../services/entity_changes'); import csurf = require('csurf'); -import { createPartialContentHandler } from "express-partial-content"; -import rateLimit = require("express-rate-limit"); +import {createPartialContentHandler} from 'express-partial-content'; +import rateLimit = require('express-rate-limit'); import AbstractBeccaEntity = require('../becca/entities/abstract_becca_entity'); import NotFoundError = require('../errors/not_found_error'); import ValidationError = require('../errors/validation_error'); @@ -70,32 +70,33 @@ import etapiNoteRoutes = require('../etapi/notes'); import etapiSpecialNoteRoutes = require('../etapi/special_notes'); import etapiSpecRoute = require('../etapi/spec'); import etapiBackupRoute = require('../etapi/backup'); -import { AppRequest, AppRequestHandler } from './route-interface'; +import {AppRequest, AppRequestHandler} from './route-interface'; const csrfMiddleware = csurf({ cookie: { - path: "" // empty, so cookie is valid only for the current path + path: '' // empty, so cookie is valid only for the current path } }); const MAX_ALLOWED_FILE_SIZE_MB = 250; -const GET = 'get', PST = 'post', PUT = 'put', PATCH = 'patch', DEL = 'delete'; +const GET = 'get', + PST = 'post', + PUT = 'put', + PATCH = 'patch', + DEL = 'delete'; type ApiResultHandler = (req: express.Request, res: express.Response, result: unknown) => number; // TODO: Deduplicate with etapi_utils.ts afterwards. -type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head"; +type HttpMethod = 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'; const uploadMiddleware = createUploadMiddleware(); const uploadMiddlewareWithErrorHandling = function (req: express.Request, res: express.Response, next: express.NextFunction) { uploadMiddleware(req, res, function (err) { if (err?.code === 'LIMIT_FILE_SIZE') { - res.setHeader("Content-Type", "text/plain") - .status(400) - .send(`Cannot upload file because it excceeded max allowed file size of ${MAX_ALLOWED_FILE_SIZE_MB} MiB`); - } - else { + res.setHeader('Content-Type', 'text/plain').status(400).send(`Cannot upload file because it excceeded max allowed file size of ${MAX_ALLOWED_FILE_SIZE_MB} MiB`); + } else { next(); } }); @@ -137,13 +138,18 @@ function register(app: express.Application) { apiRoute(PUT, '/api/notes/:noteId/toggle-in-parent/:parentNoteId/:present', cloningApiRoute.toggleNoteInParent); apiRoute(PUT, '/api/notes/:noteId/clone-to-note/:parentNoteId', cloningApiRoute.cloneNoteToParentNote); apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter); - route(PUT, '/api/notes/:noteId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], - filesRoute.updateFile, apiResultHandler); + route(PUT, '/api/notes/:noteId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], filesRoute.updateFile, apiResultHandler); route(GET, '/api/notes/:noteId/open', [auth.checkApiAuthOrElectron], filesRoute.openFile); - route(GET, '/api/notes/:noteId/open-partial', [auth.checkApiAuthOrElectron], + route( + GET, + '/api/notes/:noteId/open-partial', + [auth.checkApiAuthOrElectron], createPartialContentHandler(filesRoute.fileContentProvider, { - debug: (string, extra) => { console.log(string, extra); } - })); + debug: (string, extra) => { + console.log(string, extra); + } + }) + ); route(GET, '/api/notes/:noteId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); // this "hacky" path is used for easier referencing of CSS resources route(GET, '/api/notes/download/:noteId', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); @@ -170,17 +176,22 @@ function register(app: express.Application) { apiRoute(GET, '/api/attachments/:attachmentId/blob', attachmentsApiRoute.getAttachmentBlob); route(GET, '/api/attachments/:attachmentId/image/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnAttachedImage); route(GET, '/api/attachments/:attachmentId/open', [auth.checkApiAuthOrElectron], filesRoute.openAttachment); - route(GET, '/api/attachments/:attachmentId/open-partial', [auth.checkApiAuthOrElectron], + route( + GET, + '/api/attachments/:attachmentId/open-partial', + [auth.checkApiAuthOrElectron], createPartialContentHandler(filesRoute.attachmentContentProvider, { - debug: (string, extra) => { console.log(string, extra); } - })); + debug: (string, extra) => { + console.log(string, extra); + } + }) + ); route(GET, '/api/attachments/:attachmentId/download', [auth.checkApiAuthOrElectron], filesRoute.downloadAttachment); // this "hacky" path is used for easier referencing of CSS resources route(GET, '/api/attachments/download/:attachmentId', [auth.checkApiAuthOrElectron], filesRoute.downloadAttachment); apiRoute(PST, '/api/attachments/:attachmentId/save-to-tmp-dir', filesRoute.saveAttachmentToTmpDir); apiRoute(PST, '/api/attachments/:attachmentId/upload-modified-file', filesRoute.uploadModifiedFileToAttachment); - route(PUT, '/api/attachments/:attachmentId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], - filesRoute.updateAttachment, apiResultHandler); + route(PUT, '/api/attachments/:attachmentId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], filesRoute.updateAttachment, apiResultHandler); apiRoute(GET, '/api/notes/:noteId/revisions', revisionsApiRoute.getRevisions); apiRoute(DEL, '/api/notes/:noteId/revisions', revisionsApiRoute.eraseAllRevisions); @@ -192,7 +203,6 @@ function register(app: express.Application) { route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision); - route(GET, '/api/branches/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch); route(PST, '/api/notes/:parentNoteId/notes-import', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importNotesToBranch, apiResultHandler); route(PST, '/api/notes/:parentNoteId/attachments-import', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], importRoute.importAttachmentsToNote, apiResultHandler); @@ -237,7 +247,7 @@ function register(app: express.Application) { apiRoute(GET, '/api/app-info', appInfoRoute.getAppInfo); // docker health check - route(GET, '/api/health-check', [], () => ({ "status": "ok" }), apiResultHandler); + route(GET, '/api/health-check', [], () => ({status: 'ok'}), apiResultHandler); // group of the services below are meant to be executed from the outside route(GET, '/api/setup/status', [], setupApiRoute.getStatus, apiResultHandler); @@ -363,25 +373,24 @@ function register(app: express.Application) { function convertEntitiesToPojo(result: unknown) { if (result instanceof AbstractBeccaEntity) { result = result.getPojo(); - } - else if (Array.isArray(result)) { + } else if (Array.isArray(result)) { for (const idx in result) { if (result[idx] instanceof AbstractBeccaEntity) { result[idx] = result[idx].getPojo(); } } - } - else if (result && typeof result === "object") { - if ("note" in result && result.note instanceof AbstractBeccaEntity) { + } else if (result && typeof result === 'object') { + if ('note' in result && result.note instanceof AbstractBeccaEntity) { result.note = result.note.getPojo(); } - if ("branch" in result && result.branch instanceof AbstractBeccaEntity) { + if ('branch' in result && result.branch instanceof AbstractBeccaEntity) { result.branch = result.branch.getPojo(); } } - if (result && typeof result === "object" && "executionResult" in result) { // from runOnBackend() + if (result && typeof result === 'object' && 'executionResult' in result) { + // from runOnBackend() result.executionResult = convertEntitiesToPojo(result.executionResult); } @@ -402,11 +411,9 @@ function apiResultHandler(req: express.Request, res: express.Response, result: u } return send(res, statusCode, response); - } - else if (result === undefined) { - return send(res, 204, ""); - } - else { + } else if (result === undefined) { + return send(res, 204, ''); + } else { return send(res, 200, result); } } @@ -414,17 +421,16 @@ function apiResultHandler(req: express.Request, res: express.Response, result: u function send(res: express.Response, statusCode: number, response: unknown) { if (typeof response === 'string') { if (statusCode >= 400) { - res.setHeader("Content-Type", "text/plain"); + res.setHeader('Content-Type', 'text/plain'); } res.status(statusCode).send(response); return response.length; - } - else { + } else { const json = JSON.stringify(response); - res.setHeader("Content-Type", "application/json"); + res.setHeader('Content-Type', 'application/json'); res.status(statusCode).send(json); return json.length; @@ -435,7 +441,14 @@ function apiRoute(method: HttpMethod, path: string, routeHandler: express.Handle route(method, path, [auth.checkApiAuth, csrfMiddleware], routeHandler, apiResultHandler); } -function route(method: HttpMethod, path: string, middleware: (express.Handler | AppRequestHandler)[], routeHandler: AppRequestHandler, resultHandler: ApiResultHandler | null = null, transactional = true) { +function route( + method: HttpMethod, + path: string, + middleware: (express.Handler | AppRequestHandler)[], + routeHandler: AppRequestHandler, + resultHandler: ApiResultHandler | null = null, + transactional = true +) { router[method](path, ...(middleware as express.Handler[]), (req: express.Request, res: express.Response, next: express.NextFunction) => { const start = Date.now(); @@ -457,15 +470,13 @@ function route(method: HttpMethod, path: string, middleware: (express.Handler | return; } - if (result?.then) { // promise - result - .then((promiseResult: unknown) => handleResponse(resultHandler, req, res, promiseResult, start)) - .catch((e: any) => handleException(e, method, path, res)); + if (result?.then) { + // promise + result.then((promiseResult: unknown) => handleResponse(resultHandler, req, res, promiseResult, start)).catch((e: any) => handleException(e, method, path, res)); } else { - handleResponse(resultHandler, req, res, result, start) + handleResponse(resultHandler, req, res, result, start); } - } - catch (e) { + } catch (e) { handleException(e, method, path, res); } }); @@ -481,20 +492,17 @@ function handleException(e: any, method: HttpMethod, path: string, res: express. log.error(`${method} ${path} threw exception: '${e.message}', stack: ${e.stack}`); if (e instanceof ValidationError) { - res.status(400) - .json({ - message: e.message - }); + res.status(400).json({ + message: e.message + }); } else if (e instanceof NotFoundError) { - res.status(404) - .json({ - message: e.message - }); + res.status(404).json({ + message: e.message + }); } else { - res.status(500) - .json({ - message: e.message - }); + res.status(500).json({ + message: e.message + }); } } @@ -503,7 +511,7 @@ function createUploadMiddleware() { fileFilter: (req: express.Request, file, cb) => { // UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side. // See https://github.com/expressjs/multer/pull/1102. - file.originalname = Buffer.from(file.originalname, "latin1").toString("utf-8"); + file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf-8'); cb(null, true); } }; diff --git a/src/services/anonymization.ts b/src/services/anonymization.ts index 4e17058a7..8603c37d8 100644 --- a/src/services/anonymization.ts +++ b/src/services/anonymization.ts @@ -1,17 +1,17 @@ import BUILTIN_ATTRIBUTES = require('./builtin_attributes'); -import fs = require("fs-extra"); +import fs = require('fs-extra'); import dataDir = require('./data_dir'); import dateUtils = require('./date_utils'); -import Database = require("better-sqlite3"); +import Database = require('better-sqlite3'); import sql = require('./sql'); -import path = require("path"); +import path = require('path'); function getFullAnonymizationScript() { // we want to delete all non-builtin attributes because they can contain sensitive names and values // on the other hand builtin/system attrs should not contain any sensitive info - const builtinAttrNames = BUILTIN_ATTRIBUTES - .filter(attr => !["shareCredentials", "shareAlias"].includes(attr.name)) - .map(attr => `'${attr.name}'`).join(', '); + const builtinAttrNames = BUILTIN_ATTRIBUTES.filter((attr) => !['shareCredentials', 'shareAlias'].includes(attr.name)) + .map((attr) => `'${attr.name}'`) + .join(', '); const anonymizeScript = ` UPDATE etapi_tokens SET tokenHash = 'API token hash value'; @@ -48,7 +48,7 @@ function getLightAnonymizationScript() { AND value != '';`; } -async function createAnonymizedCopy(type: "full" | "light") { +async function createAnonymizedCopy(type: 'full' | 'light') { if (!['full', 'light'].includes(type)) { throw new Error(`Unrecognized anonymization type '${type}'`); } @@ -63,9 +63,7 @@ async function createAnonymizedCopy(type: "full" | "light") { const db = new Database(anonymizedFile); - const anonymizationScript = type === 'light' - ? getLightAnonymizationScript() - : getFullAnonymizationScript(); + const anonymizationScript = type === 'light' ? getLightAnonymizationScript() : getFullAnonymizationScript(); db.exec(anonymizationScript); @@ -82,9 +80,10 @@ function getExistingAnonymizedDatabases() { return []; } - return fs.readdirSync(dataDir.ANONYMIZED_DB_DIR) - .filter(fileName => fileName.includes("anonymized")) - .map(fileName => ({ + return fs + .readdirSync(dataDir.ANONYMIZED_DB_DIR) + .filter((fileName) => fileName.includes('anonymized')) + .map((fileName) => ({ fileName: fileName, filePath: path.resolve(dataDir.ANONYMIZED_DB_DIR, fileName) })); @@ -94,4 +93,4 @@ export = { getFullAnonymizationScript, createAnonymizedCopy, getExistingAnonymizedDatabases -} +}; diff --git a/src/services/backend_script_api.ts b/src/services/backend_script_api.ts index 9b72929a4..16a45dbd1 100644 --- a/src/services/backend_script_api.ts +++ b/src/services/backend_script_api.ts @@ -30,11 +30,10 @@ import BAttachment = require('../becca/entities/battachment'); import BRevision = require('../becca/entities/brevision'); import BEtapiToken = require('../becca/entities/betapi_token'); import BOption = require('../becca/entities/boption'); -import { AttributeRow, AttributeType, NoteType } from '../becca/entities/rows'; +import {AttributeRow, AttributeType, NoteType} from '../becca/entities/rows'; import Becca from '../becca/becca-interface'; -import { NoteParams } from './note-interface'; -import { ApiParams } from './backend_script_api_interface'; - +import {NoteParams} from './note-interface'; +import {ApiParams} from './backend_script_api_interface'; /** * A whole number @@ -77,7 +76,7 @@ interface Api { * Entity whose event triggered this execution */ originEntity?: AbstractBeccaEntity; - + /** * Axios library for HTTP requests. See {@link https://axios-http.com} for documentation * @deprecated use native (browser compatible) fetch() instead @@ -94,13 +93,13 @@ interface Api { */ xml2js: typeof xml2js; - + /** * Instance name identifies particular Trilium instance. It can be useful for scripts * if some action needs to happen on only one specific instance. */ getInstanceName(): string | null; - + getNote(noteId: string): BNote | null; getBranch(branchId: string): BBranch | null; getAttribute(attachmentId: string): BAttribute | null; @@ -111,19 +110,19 @@ interface Api { getOption(optionName: string): BOption | null; getOptions(): BOption[]; getAttribute(attributeId: string): BAttribute | null; - + /** * This is a powerful search method - you can search by attributes and their values, e.g.: * "#dateModified =* MONTH AND #log". See {@link https://github.com/zadam/trilium/wiki/Search} for full documentation for all options */ searchForNotes(query: string, searchParams: SearchParams): BNote[]; - + /** * This is a powerful search method - you can search by attributes and their values, e.g.: * "#dateModified =* MONTH AND #log". See {@link https://github.com/zadam/trilium/wiki/Search} for full documentation for all options */ searchForNote(query: string, searchParams: SearchParams): BNote | null; - + /** * Retrieves notes with given label name & value * @@ -145,8 +144,12 @@ interface Api { * * @param prefix - if branch is created between note and parent note, set this prefix */ - ensureNoteIsPresentInParent(noteId: string, parentNoteId: string, prefix: string): { - branch: BBranch | null + ensureNoteIsPresentInParent( + noteId: string, + parentNoteId: string, + prefix: string + ): { + branch: BBranch | null; }; /** @@ -183,11 +186,16 @@ interface Api { * @param parentNoteId - create new note under this parent * @returns object contains newly created entities note and branch */ - createNote(parentNoteId: string, title: string, content: string, extraOptions: Omit & { - /** should the note be JSON */ - json?: boolean; - attributes?: AttributeRow[] - }): NoteAndBranch; + createNote( + parentNoteId: string, + title: string, + content: string, + extraOptions: Omit & { + /** should the note be JSON */ + json?: boolean; + attributes?: AttributeRow[]; + } + ): NoteAndBranch; logMessages: Record; logSpacedUpdates: Record; @@ -213,7 +221,7 @@ interface Api { /** * Returns today's day note. If such note doesn't exist, it is created. - * + * * @param rootNote specify calendar root note, normally leave empty to use the default calendar */ getTodayNote(rootNote?: BNote): BNote | null; @@ -224,11 +232,15 @@ interface Api { * @param date in YYYY-MM-DD format * @param rootNote - specify calendar root note, normally leave empty to use the default calendar */ - getWeekNote(date: string, options: { - // TODO: Deduplicate type with date_notes.ts once ES modules are added. - /** either "monday" (default) or "sunday" */ - startOfTheWeek: "monday" | "sunday"; - }, rootNote: BNote): BNote | null; + getWeekNote( + date: string, + options: { + // TODO: Deduplicate type with date_notes.ts once ES modules are added. + /** either "monday" (default) or "sunday" */ + startOfTheWeek: 'monday' | 'sunday'; + }, + rootNote: BNote + ): BNote | null; /** * Returns month note for given date. If such a note doesn't exist, it is created. @@ -249,13 +261,16 @@ interface Api { /** * Sort child notes of a given note. */ - sortNotes(parentNoteId: string, sortConfig: { - /** 'title', 'dateCreated', 'dateModified' or a label name - * See {@link https://github.com/zadam/trilium/wiki/Sorting} for details. */ - sortBy?: string; - reverse?: boolean; - foldersFirst?: boolean; - }): void; + sortNotes( + parentNoteId: string, + sortConfig: { + /** 'title', 'dateCreated', 'dateModified' or a label name + * See {@link https://github.com/zadam/trilium/wiki/Sorting} for details. */ + sortBy?: string; + reverse?: boolean; + foldersFirst?: boolean; + } + ): void; /** * This method finds note by its noteId and prefix and either sets it to the given parentNoteId @@ -315,7 +330,7 @@ interface Api { * - "script" - activating the launcher will execute the script (specified in scriptNoteId param) * - "customWidget" - the launcher will be rendered with a custom widget (specified in widgetNoteId param) */ - type: "note" | "script" | "customWidget"; + type: 'note' | 'script' | 'customWidget'; title: string; /** if true, will be created in the "Visible launchers", otherwise in "Available launchers" */ isVisible: boolean; @@ -329,12 +344,12 @@ interface Api { scriptNoteId: string; /** for type "customWidget" */ widgetNoteId?: string; - }): { note: BNote }; + }): {note: BNote}; /** * @param format - either 'html' or 'markdown' */ - exportSubtreeToZipFile(noteId: string, format: "markdown" | "html", zipFilePath: string): Promise; + exportSubtreeToZipFile(noteId: string, format: 'markdown' | 'html', zipFilePath: string): Promise; /** * Executes given anonymous function on the frontend(s). @@ -367,7 +382,7 @@ interface Api { */ backupNow(backupName: string): Promise; - /** + /** * This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. */ __private: { @@ -385,9 +400,9 @@ interface Api { */ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { this.startNote = apiParams.startNote; - + this.currentNote = currentNote; - + this.originEntity = apiParams.originEntity; for (const key in apiParams) { @@ -397,18 +412,18 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { this.axios = axios; this.dayjs = dayjs; this.xml2js = xml2js; - this.getInstanceName = () => config.General ? config.General.instanceName : null; - this.getNote = noteId => becca.getNote(noteId); - this.getBranch = branchId => becca.getBranch(branchId); - this.getAttribute = attributeId => becca.getAttribute(attributeId); - this.getAttachment = attachmentId => becca.getAttachment(attachmentId); - this.getRevision = revisionId => becca.getRevision(revisionId); - this.getEtapiToken = etapiTokenId => becca.getEtapiToken(etapiTokenId); + this.getInstanceName = () => (config.General ? config.General.instanceName : null); + this.getNote = (noteId) => becca.getNote(noteId); + this.getBranch = (branchId) => becca.getBranch(branchId); + this.getAttribute = (attributeId) => becca.getAttribute(attributeId); + this.getAttachment = (attachmentId) => becca.getAttachment(attachmentId); + this.getRevision = (revisionId) => becca.getRevision(revisionId); + this.getEtapiToken = (etapiTokenId) => becca.getEtapiToken(etapiTokenId); this.getEtapiTokens = () => becca.getEtapiTokens(); - this.getOption = optionName => becca.getOption(optionName); + this.getOption = (optionName) => becca.getOption(optionName); this.getOptions = () => optionsService.getOptions(); - this.getAttribute = attributeId => becca.getAttribute(attributeId); - + this.getAttribute = (attributeId) => becca.getAttribute(attributeId); + this.searchForNotes = (query, searchParams = {}) => { if (searchParams.includeArchivedNotes === undefined) { searchParams.includeArchivedNotes = true; @@ -418,42 +433,42 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { searchParams.ignoreHoistedNote = true; } - const noteIds = searchService.findResultsWithQuery(query, new SearchContext(searchParams)) - .map(sr => sr.noteId); + const noteIds = searchService.findResultsWithQuery(query, new SearchContext(searchParams)).map((sr) => sr.noteId); return becca.getNotes(noteIds); }; - this.searchForNote = (query, searchParams = {}) => { const notes = this.searchForNotes(query, searchParams); return notes.length > 0 ? notes[0] : null; }; - this.getNotesWithLabel = attributeService.getNotesWithLabel; + this.getNotesWithLabel = attributeService.getNotesWithLabel; this.getNoteWithLabel = attributeService.getNoteWithLabel; this.ensureNoteIsPresentInParent = cloningService.ensureNoteIsPresentInParent; this.ensureNoteIsAbsentFromParent = cloningService.ensureNoteIsAbsentFromParent; this.toggleNoteInParent = cloningService.toggleNoteInParent; - this.createTextNote = (parentNoteId, title, content = '') => noteService.createNewNote({ - parentNoteId, - title, - content, - type: 'text' - }); + this.createTextNote = (parentNoteId, title, content = '') => + noteService.createNewNote({ + parentNoteId, + title, + content, + type: 'text' + }); + + this.createDataNote = (parentNoteId, title, content = {}) => + noteService.createNewNote({ + parentNoteId, + title, + content: JSON.stringify(content, null, '\t'), + type: 'code', + mime: 'application/json' + }); - this.createDataNote = (parentNoteId, title, content = {}) => noteService.createNewNote({ - parentNoteId, - title, - content: JSON.stringify(content, null, '\t'), - type: 'code', - mime: 'application/json' - }); - this.createNewNote = noteService.createNewNote; - - this.createNote = (parentNoteId, title, content = "", _extraOptions = {}) => { + + this.createNote = (parentNoteId, title, content = '', _extraOptions = {}) => { const parentNote = becca.getNote(parentNoteId); if (!parentNote) { throw new Error(`Unable to find parent note with ID ${parentNote}.`); @@ -461,8 +476,8 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { let extraOptions: NoteParams = { ..._extraOptions, - content: "", - type: "text", + content: '', + type: 'text', parentNoteId, title }; @@ -475,13 +490,12 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { extraOptions.content = JSON.stringify(content || {}, null, '\t'); extraOptions.type = 'code'; extraOptions.mime = 'application/json'; - } - else { + } else { extraOptions.content = content; } return sql.transactional(() => { - const { note, branch } = noteService.createNewNote(extraOptions); + const {note, branch} = noteService.createNewNote(extraOptions); for (const attr of _extraOptions.attributes || []) { attributeService.createAttribute({ @@ -493,33 +507,35 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { }); } - return { note, branch }; + return {note, branch}; }); }; this.logMessages = {}; this.logSpacedUpdates = {}; - - this.log = message => { + + this.log = (message) => { log.info(message); if (!this.startNote) { return; } - const { noteId } = this.startNote; + const {noteId} = this.startNote; this.logMessages[noteId] = this.logMessages[noteId] || []; - this.logSpacedUpdates[noteId] = this.logSpacedUpdates[noteId] || new SpacedUpdate(() => { - const messages = this.logMessages[noteId]; - this.logMessages[noteId] = []; + this.logSpacedUpdates[noteId] = + this.logSpacedUpdates[noteId] || + new SpacedUpdate(() => { + const messages = this.logMessages[noteId]; + this.logMessages[noteId] = []; - ws.sendMessageToAllClients({ - type: 'api-log-messages', - noteId, - messages - }); - }, 100); + ws.sendMessageToAllClients({ + type: 'api-log-messages', + noteId, + messages + }); + }, 100); this.logMessages[noteId].push(message); this.logSpacedUpdates[noteId].scheduleUpdate(); @@ -532,12 +548,7 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { this.getMonthNote = dateNoteService.getMonthNote; this.getYearNote = dateNoteService.getYearNote; - this.sortNotes = (parentNoteId, sortConfig = {}) => treeService.sortNotes( - parentNoteId, - sortConfig.sortBy || "title", - !!sortConfig.reverse, - !!sortConfig.foldersFirst - ); + this.sortNotes = (parentNoteId, sortConfig = {}) => treeService.sortNotes(parentNoteId, sortConfig.sortBy || 'title', !!sortConfig.reverse, !!sortConfig.foldersFirst); this.setNoteToParent = treeService.setNoteToParent; this.transactional = sql.transactional; @@ -547,16 +558,31 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { this.sql = sql; this.getAppInfo = () => appInfo; - - this.createOrUpdateLauncher = opts => { - if (!opts.id) { throw new Error("ID is a mandatory parameter for api.createOrUpdateLauncher(opts)"); } - if (!opts.id.match(/[a-z0-9]{6,1000}/i)) { throw new Error(`ID must be an alphanumeric string at least 6 characters long.`); } - if (!opts.type) { throw new Error("Launcher Type is a mandatory parameter for api.createOrUpdateLauncher(opts)"); } - if (!["note", "script", "customWidget"].includes(opts.type)) { throw new Error(`Given launcher type '${opts.type}'`); } - if (!opts.title?.trim()) { throw new Error("Title is a mandatory parameter for api.createOrUpdateLauncher(opts)"); } - if (opts.type === 'note' && !opts.targetNoteId) { throw new Error("targetNoteId is mandatory for launchers of type 'note'"); } - if (opts.type === 'script' && !opts.scriptNoteId) { throw new Error("scriptNoteId is mandatory for launchers of type 'script'"); } - if (opts.type === 'customWidget' && !opts.widgetNoteId) { throw new Error("widgetNoteId is mandatory for launchers of type 'customWidget'"); } + this.createOrUpdateLauncher = (opts) => { + if (!opts.id) { + throw new Error('ID is a mandatory parameter for api.createOrUpdateLauncher(opts)'); + } + if (!opts.id.match(/[a-z0-9]{6,1000}/i)) { + throw new Error(`ID must be an alphanumeric string at least 6 characters long.`); + } + if (!opts.type) { + throw new Error('Launcher Type is a mandatory parameter for api.createOrUpdateLauncher(opts)'); + } + if (!['note', 'script', 'customWidget'].includes(opts.type)) { + throw new Error(`Given launcher type '${opts.type}'`); + } + if (!opts.title?.trim()) { + throw new Error('Title is a mandatory parameter for api.createOrUpdateLauncher(opts)'); + } + if (opts.type === 'note' && !opts.targetNoteId) { + throw new Error("targetNoteId is mandatory for launchers of type 'note'"); + } + if (opts.type === 'script' && !opts.scriptNoteId) { + throw new Error("scriptNoteId is mandatory for launchers of type 'script'"); + } + if (opts.type === 'customWidget' && !opts.widgetNoteId) { + throw new Error("widgetNoteId is mandatory for launchers of type 'customWidget'"); + } const parentNoteId = opts.isVisible ? '_lbVisibleLaunchers' : '_lbAvailableLaunchers'; const noteId = 'al_' + opts.id; @@ -566,7 +592,7 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { specialNotesService.createLauncher({ noteId: noteId, parentNoteId: parentNoteId, - launcherType: opts.type, + launcherType: opts.type }).note; if (launcherNote.title !== opts.title) { @@ -604,14 +630,14 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { launcherNote.removeLabel('iconClass'); } - return { note: launcherNote }; + return {note: launcherNote}; }; this.exportSubtreeToZipFile = async (noteId, format, zipFilePath) => await exportService.exportToZipFile(noteId, format, zipFilePath); this.runOnFrontend = async (_script, params = []) => { let script: string; - if (typeof _script === "string") { + if (typeof _script === 'string') { script = _script; } else { script = _script.toString(); @@ -623,8 +649,8 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { params: prepareParams(params), startNoteId: this.startNote?.noteId, currentNoteId: this.currentNote.noteId, - originEntityName: "notes", // currently there's no other entity on the frontend which can trigger event - originEntityId: (this.originEntity && "noteId" in this.originEntity && (this.originEntity as BNote)?.noteId) || null + originEntityName: 'notes', // currently there's no other entity on the frontend which can trigger event + originEntityId: (this.originEntity && 'noteId' in this.originEntity && (this.originEntity as BNote)?.noteId) || null }); function prepareParams(params: any[]) { @@ -632,25 +658,24 @@ function BackendScriptApi(this: Api, currentNote: BNote, apiParams: ApiParams) { return params; } - return params.map(p => { - if (typeof p === "function") { + return params.map((p) => { + if (typeof p === 'function') { return `!@#Function: ${p.toString()}`; - } - else { + } else { return p; } }); } }; - + this.runOutsideOfSync = syncMutex.doExclusively; this.backupNow = backupService.backupNow; - + this.__private = { becca - } + }; } export = BackendScriptApi as any as { - new (currentNote: BNote, apiParams: ApiParams): Api + new (currentNote: BNote, apiParams: ApiParams): Api; };