mirror of
https://github.com/TriliumNext/Notes.git
synced 2026-02-24 15:18:32 -06:00
format some files
This commit is contained in:
@@ -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<AttachmentRow>("SELECT * FROM attachments WHERE attachmentId IN (???) AND isDeleted = 0", attachmentIds)
|
||||
.map(row => new BAttachment(row));
|
||||
return sql.getManyRows<AttachmentRow>('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<RevisionRow>(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<T extends AbstractBeccaEntity<T>> {
|
||||
primaryKeyName: string;
|
||||
@@ -310,4 +303,4 @@ export interface NotePojo {
|
||||
dateModified?: string;
|
||||
utcDateCreated: string;
|
||||
utcDateModified?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/')));
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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<SessionData> & {
|
||||
loggedIn: boolean;
|
||||
}
|
||||
'trilium-cred'?: string;
|
||||
'x-local-date'?: string;
|
||||
'x-labels'?: string;
|
||||
'trilium-local-now-datetime'?: string;
|
||||
};
|
||||
session: Session &
|
||||
Partial<SessionData> & {
|
||||
loggedIn: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type AppRequestHandler = (
|
||||
req: AppRequest,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => void;
|
||||
export type AppRequestHandler = (req: AppRequest, res: Response, next: NextFunction) => void;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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<any>;
|
||||
|
||||
|
||||
/**
|
||||
* 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<NoteParams, "title" | "content" | "type" | "parentNoteId"> & {
|
||||
/** should the note be JSON */
|
||||
json?: boolean;
|
||||
attributes?: AttributeRow[]
|
||||
}): NoteAndBranch;
|
||||
createNote(
|
||||
parentNoteId: string,
|
||||
title: string,
|
||||
content: string,
|
||||
extraOptions: Omit<NoteParams, 'title' | 'content' | 'type' | 'parentNoteId'> & {
|
||||
/** should the note be JSON */
|
||||
json?: boolean;
|
||||
attributes?: AttributeRow[];
|
||||
}
|
||||
): NoteAndBranch;
|
||||
|
||||
logMessages: Record<string, string[]>;
|
||||
logSpacedUpdates: Record<string, SpacedUpdate>;
|
||||
@@ -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<void>;
|
||||
exportSubtreeToZipFile(noteId: string, format: 'markdown' | 'html', zipFilePath: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Executes given anonymous function on the frontend(s).
|
||||
@@ -367,7 +382,7 @@ interface Api {
|
||||
*/
|
||||
backupNow(backupName: string): Promise<string>;
|
||||
|
||||
/**
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user