mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
Merge pull request #18 from TriliumNext/feature/typescript_backend_2
Convert backend to TypeScript (19% -> 35%)
This commit is contained in:
commit
a7ae16bb39
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const anonymizationService = require('../src/services/anonymization.js');
|
const anonymizationService = require('../src/services/anonymization');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ jq '.version = "'$VERSION'"' package.json|sponge package.json
|
|||||||
|
|
||||||
git add package.json
|
git add package.json
|
||||||
|
|
||||||
echo 'module.exports = { buildDate:"'`date --iso-8601=seconds`'", buildRevision: "'`git log -1 --format="%H"`'" };' > src/services/build.js
|
echo 'export = { buildDate:"'`date --iso-8601=seconds`'", buildRevision: "'`git log -1 --format="%H"`'" };' > src/services/build.ts
|
||||||
|
|
||||||
git add src/services/build.js
|
git add src/services/build.ts
|
||||||
|
|
||||||
TAG=v$VERSION
|
TAG=v$VERSION
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
const beccaLoader = require('../../src/becca/becca_loader.js');
|
const beccaLoader = require('../../src/becca/becca_loader');
|
||||||
const becca = require('../../src/becca/becca');
|
const becca = require('../../src/becca/becca');
|
||||||
const cls = require('../../src/services/cls');
|
const cls = require('../../src/services/cls');
|
||||||
const log = require('../../src/services/log');
|
const log = require('../../src/services/log');
|
||||||
|
@ -10,7 +10,7 @@ if (config.Network.https) {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = require('./src/services/port.js');
|
const port = require('./src/services/port.ts');
|
||||||
const host = require('./src/services/host.js');
|
const host = require('./src/services/host.js');
|
||||||
|
|
||||||
const options = { timeout: 2000 };
|
const options = { timeout: 2000 };
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const {app, globalShortcut, BrowserWindow} = require('electron');
|
const {app, globalShortcut, BrowserWindow} = require('electron');
|
||||||
const sqlInit = require('./src/services/sql_init.js');
|
const sqlInit = require('./src/services/sql_init');
|
||||||
const appIconService = require('./src/services/app_icon.js');
|
const appIconService = require('./src/services/app_icon.js');
|
||||||
const windowService = require('./src/services/window.js');
|
const windowService = require('./src/services/window.js');
|
||||||
const tray = require('./src/services/tray.js');
|
const tray = require('./src/services/tray.js');
|
||||||
|
220
package-lock.json
generated
220
package-lock.json
generated
@ -93,8 +93,10 @@
|
|||||||
"@types/escape-html": "^1.0.4",
|
"@types/escape-html": "^1.0.4",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/ini": "^4.1.0",
|
"@types/ini": "^4.1.0",
|
||||||
|
"@types/jsdom": "^21.1.6",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^20.11.19",
|
"@types/node": "^20.11.19",
|
||||||
|
"@types/sanitize-html": "^2.11.0",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/ws": "^8.5.10",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"electron": "25.9.8",
|
"electron": "25.9.8",
|
||||||
@ -1333,6 +1335,41 @@
|
|||||||
"integrity": "sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==",
|
"integrity": "sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jsdom": {
|
||||||
|
"version": "21.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz",
|
||||||
|
"integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/tough-cookie": "*",
|
||||||
|
"parse5": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/jsdom/node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/jsdom/node_modules/parse5": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.9",
|
"version": "7.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||||
@ -1439,6 +1476,89 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/sanitize-html": {
|
||||||
|
"version": "2.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
|
||||||
|
"integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"htmlparser2": "^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/sanitize-html/node_modules/dom-serializer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.2",
|
||||||
|
"entities": "^4.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/sanitize-html/node_modules/domhandler": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/sanitize-html/node_modules/domutils": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/sanitize-html/node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/sanitize-html/node_modules/htmlparser2": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/send": {
|
"node_modules/@types/send": {
|
||||||
"version": "0.17.4",
|
"version": "0.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
||||||
@ -1460,6 +1580,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/tough-cookie": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/unist": {
|
"node_modules/@types/unist": {
|
||||||
"version": "2.0.10",
|
"version": "2.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
||||||
@ -14124,6 +14250,34 @@
|
|||||||
"integrity": "sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==",
|
"integrity": "sha512-mTehMtc+xtnWBBvqizcqYCktKDBH2WChvx1GU3Sfe4PysFDXiNe+1YwtpVX1MDtCa4NQrSPw2+3HmvXHY3gt1w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/jsdom": {
|
||||||
|
"version": "21.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz",
|
||||||
|
"integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"@types/tough-cookie": "*",
|
||||||
|
"parse5": "^7.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"parse5": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/json-schema": {
|
"@types/json-schema": {
|
||||||
"version": "7.0.9",
|
"version": "7.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
|
||||||
@ -14230,6 +14384,66 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/sanitize-html": {
|
||||||
|
"version": "2.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
|
||||||
|
"integrity": "sha512-7oxPGNQHXLHE48r/r/qjn7q0hlrs3kL7oZnGj0Wf/h9tj/6ibFyRkNbsDxaBBZ4XUZ0Dx5LGCyDJ04ytSofacQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"htmlparser2": "^8.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.2",
|
||||||
|
"entities": "^4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domhandler": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domutils": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"htmlparser2": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/send": {
|
"@types/send": {
|
||||||
"version": "0.17.4",
|
"version": "0.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
||||||
@ -14251,6 +14465,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/tough-cookie": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/unist": {
|
"@types/unist": {
|
||||||
"version": "2.0.10",
|
"version": "2.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
||||||
|
@ -114,8 +114,10 @@
|
|||||||
"@types/escape-html": "^1.0.4",
|
"@types/escape-html": "^1.0.4",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/ini": "^4.1.0",
|
"@types/ini": "^4.1.0",
|
||||||
|
"@types/jsdom": "^21.1.6",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^20.11.19",
|
"@types/node": "^20.11.19",
|
||||||
|
"@types/sanitize-html": "^2.11.0",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/ws": "^8.5.10",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"electron": "25.9.8",
|
"electron": "25.9.8",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const anonymizationService = require('./services/anonymization.js');
|
const anonymizationService = require('./services/anonymization');
|
||||||
const sqlInit = require('./services/sql_init.js');
|
const sqlInit = require('./services/sql_init');
|
||||||
require('./becca/entity_constructor.js');
|
require('./becca/entity_constructor');
|
||||||
|
|
||||||
sqlInit.dbReady.then(async () => {
|
sqlInit.dbReady.then(async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -8,7 +8,7 @@ const sessionParser = require('./routes/session_parser.js');
|
|||||||
const utils = require('./services/utils');
|
const utils = require('./services/utils');
|
||||||
|
|
||||||
require('./services/handlers.js');
|
require('./services/handlers.js');
|
||||||
require('./becca/becca_loader.js');
|
require('./becca/becca_loader');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ require('./routes/error_handlers.js').register(app);
|
|||||||
require('./services/sync.js');
|
require('./services/sync.js');
|
||||||
|
|
||||||
// triggers backup timer
|
// triggers backup timer
|
||||||
require('./services/backup.js');
|
require('./services/backup');
|
||||||
|
|
||||||
// trigger consistency checks timer
|
// trigger consistency checks timer
|
||||||
require('./services/consistency_checks.js');
|
require('./services/consistency_checks.js');
|
||||||
|
@ -21,7 +21,7 @@ interface AttachmentOpts {
|
|||||||
* Becca is a backend cache of all notes, branches, and attributes.
|
* Becca is a backend cache of all notes, branches, and attributes.
|
||||||
* There's a similar frontend cache Froca, and share cache Shaca.
|
* There's a similar frontend cache Froca, and share cache Shaca.
|
||||||
*/
|
*/
|
||||||
class Becca {
|
export default class Becca {
|
||||||
loaded!: boolean;
|
loaded!: boolean;
|
||||||
|
|
||||||
notes!: Record<string, BNote>;
|
notes!: Record<string, BNote>;
|
||||||
@ -280,4 +280,12 @@ class Becca {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export = 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.
|
||||||
|
*/
|
||||||
|
export interface ConstructorData<T extends AbstractBeccaEntity<T>> {
|
||||||
|
primaryKeyName: string;
|
||||||
|
entityName: string;
|
||||||
|
hashedProperties: (keyof T)[];
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import Becca = require("./becca-interface");
|
import Becca from "./becca-interface";
|
||||||
|
|
||||||
const becca = new Becca();
|
const becca = new Becca();
|
||||||
|
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sql = require('../services/sql');
|
import sql = require('../services/sql');
|
||||||
const eventService = require('../services/events');
|
import eventService = require('../services/events');
|
||||||
const becca = require('./becca');
|
import becca = require('./becca');
|
||||||
const sqlInit = require('../services/sql_init');
|
import sqlInit = require('../services/sql_init');
|
||||||
const log = require('../services/log');
|
import log = require('../services/log');
|
||||||
const BNote = require('./entities/bnote');
|
import BNote = require('./entities/bnote');
|
||||||
const BBranch = require('./entities/bbranch');
|
import BBranch = require('./entities/bbranch');
|
||||||
const BAttribute = require('./entities/battribute');
|
import BAttribute = require('./entities/battribute');
|
||||||
const BOption = require('./entities/boption');
|
import BOption = require('./entities/boption');
|
||||||
const BEtapiToken = require('./entities/betapi_token');
|
import BEtapiToken = require('./entities/betapi_token');
|
||||||
const cls = require('../services/cls');
|
import cls = require('../services/cls');
|
||||||
const entityConstructor = require('../becca/entity_constructor');
|
import entityConstructor = require('../becca/entity_constructor');
|
||||||
|
import { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from './entities/rows';
|
||||||
|
import AbstractBeccaEntity = require('./entities/abstract_becca_entity');
|
||||||
|
|
||||||
const beccaLoaded = new Promise((res, rej) => {
|
const beccaLoaded = new Promise<void>((res, rej) => {
|
||||||
sqlInit.dbReady.then(() => {
|
sqlInit.dbReady.then(() => {
|
||||||
cls.init(() => {
|
cls.init(() => {
|
||||||
load();
|
load();
|
||||||
@ -38,23 +40,23 @@ function load() {
|
|||||||
new BNote().update(row).init();
|
new BNote().update(row).init();
|
||||||
}
|
}
|
||||||
|
|
||||||
const branchRows = sql.getRawRows(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0`);
|
const branchRows = sql.getRawRows<BranchRow>(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0`);
|
||||||
// in-memory sort is faster than in the DB
|
// in-memory sort is faster than in the DB
|
||||||
branchRows.sort((a, b) => a.notePosition - b.notePosition);
|
branchRows.sort((a, b) => (a.notePosition || 0) - (b.notePosition || 0));
|
||||||
|
|
||||||
for (const row of branchRows) {
|
for (const row of branchRows) {
|
||||||
new BBranch().update(row).init();
|
new BBranch().update(row).init();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const row of sql.getRawRows(`SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0`)) {
|
for (const row of sql.getRawRows<AttributeRow>(`SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0`)) {
|
||||||
new BAttribute().update(row).init();
|
new BAttribute().update(row).init();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const row of sql.getRows(`SELECT name, value, isSynced, utcDateModified FROM options`)) {
|
for (const row of sql.getRows<OptionRow>(`SELECT name, value, isSynced, utcDateModified FROM options`)) {
|
||||||
new BOption(row);
|
new BOption(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const row of sql.getRows(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
|
for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
|
||||||
new BEtapiToken(row);
|
new BEtapiToken(row);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -68,7 +70,7 @@ function load() {
|
|||||||
log.info(`Becca (note cache) load took ${Date.now() - start}ms`);
|
log.info(`Becca (note cache) load took ${Date.now() - start}ms`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload(reason) {
|
function reload(reason: string) {
|
||||||
load();
|
load();
|
||||||
|
|
||||||
require('../services/ws').reloadFrontend(reason || "becca reloaded");
|
require('../services/ws').reloadFrontend(reason || "becca reloaded");
|
||||||
@ -88,7 +90,7 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({ entity
|
|||||||
if (beccaEntity) {
|
if (beccaEntity) {
|
||||||
beccaEntity.updateFromRow(entityRow);
|
beccaEntity.updateFromRow(entityRow);
|
||||||
} else {
|
} else {
|
||||||
beccaEntity = new EntityClass();
|
beccaEntity = new EntityClass() as AbstractBeccaEntity<AbstractBeccaEntity<any>>;
|
||||||
beccaEntity.updateFromRow(entityRow);
|
beccaEntity.updateFromRow(entityRow);
|
||||||
beccaEntity.init();
|
beccaEntity.init();
|
||||||
}
|
}
|
||||||
@ -112,7 +114,7 @@ eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED, ({ entityName, en
|
|||||||
* @param entityRow - can be a becca entity (change comes from this trilium instance) or just a row (from sync).
|
* @param entityRow - can be a becca entity (change comes from this trilium instance) or just a row (from sync).
|
||||||
* It should be therefore treated as a row.
|
* It should be therefore treated as a row.
|
||||||
*/
|
*/
|
||||||
function postProcessEntityUpdate(entityName, entityRow) {
|
function postProcessEntityUpdate(entityName: string, entityRow: any) {
|
||||||
if (entityName === 'notes') {
|
if (entityName === 'notes') {
|
||||||
noteUpdated(entityRow);
|
noteUpdated(entityRow);
|
||||||
} else if (entityName === 'branches') {
|
} else if (entityName === 'branches') {
|
||||||
@ -140,13 +142,13 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENT
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function noteDeleted(noteId) {
|
function noteDeleted(noteId: string) {
|
||||||
delete becca.notes[noteId];
|
delete becca.notes[noteId];
|
||||||
|
|
||||||
becca.dirtyNoteSetCache();
|
becca.dirtyNoteSetCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
function branchDeleted(branchId) {
|
function branchDeleted(branchId: string) {
|
||||||
const branch = becca.branches[branchId];
|
const branch = becca.branches[branchId];
|
||||||
|
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
@ -173,23 +175,26 @@ function branchDeleted(branchId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete becca.childParentToBranch[`${branch.noteId}-${branch.parentNoteId}`];
|
delete becca.childParentToBranch[`${branch.noteId}-${branch.parentNoteId}`];
|
||||||
|
if (branch.branchId) {
|
||||||
delete becca.branches[branch.branchId];
|
delete becca.branches[branch.branchId];
|
||||||
}
|
|
||||||
|
|
||||||
function noteUpdated(entityRow) {
|
|
||||||
const note = becca.notes[entityRow.noteId];
|
|
||||||
|
|
||||||
if (note) {
|
|
||||||
// type / mime could have been changed, and they are present in flatTextCache
|
|
||||||
note.flatTextCache = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function branchUpdated(branchRow) {
|
function noteUpdated(entityRow: NoteRow) {
|
||||||
|
const note = becca.notes[entityRow.noteId];
|
||||||
|
|
||||||
|
if (note) {
|
||||||
|
// TODO, this wouldn't have worked in the original implementation since the variable was named __flatTextCache.
|
||||||
|
// type / mime could have been changed, and they are present in flatTextCache
|
||||||
|
note.__flatTextCache = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function branchUpdated(branchRow: BranchRow) {
|
||||||
const childNote = becca.notes[branchRow.noteId];
|
const childNote = becca.notes[branchRow.noteId];
|
||||||
|
|
||||||
if (childNote) {
|
if (childNote) {
|
||||||
childNote.flatTextCache = null;
|
childNote.__flatTextCache = null;
|
||||||
childNote.sortParents();
|
childNote.sortParents();
|
||||||
|
|
||||||
// notes in the subtree can get new inherited attributes
|
// notes in the subtree can get new inherited attributes
|
||||||
@ -204,7 +209,7 @@ function branchUpdated(branchRow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function attributeDeleted(attributeId) {
|
function attributeDeleted(attributeId: string) {
|
||||||
const attribute = becca.attributes[attributeId];
|
const attribute = becca.attributes[attributeId];
|
||||||
|
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
@ -239,8 +244,7 @@ function attributeDeleted(attributeId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {BAttribute} attributeRow */
|
function attributeUpdated(attributeRow: BAttribute) {
|
||||||
function attributeUpdated(attributeRow) {
|
|
||||||
const attribute = becca.attributes[attributeRow.attributeId];
|
const attribute = becca.attributes[attributeRow.attributeId];
|
||||||
const note = becca.notes[attributeRow.noteId];
|
const note = becca.notes[attributeRow.noteId];
|
||||||
|
|
||||||
@ -253,7 +257,7 @@ function attributeUpdated(attributeRow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function noteReorderingUpdated(branchIdList) {
|
function noteReorderingUpdated(branchIdList: number[]) {
|
||||||
const parentNoteIds = new Set();
|
const parentNoteIds = new Set();
|
||||||
|
|
||||||
for (const branchId in branchIdList) {
|
for (const branchId in branchIdList) {
|
||||||
@ -267,7 +271,7 @@ function noteReorderingUpdated(branchIdList) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function etapiTokenDeleted(etapiTokenId) {
|
function etapiTokenDeleted(etapiTokenId: string) {
|
||||||
delete becca.etapiTokens[etapiTokenId];
|
delete becca.etapiTokens[etapiTokenId];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,14 +279,14 @@ eventService.subscribeBeccaLoader(eventService.ENTER_PROTECTED_SESSION, () => {
|
|||||||
try {
|
try {
|
||||||
becca.decryptProtectedNotes();
|
becca.decryptProtectedNotes();
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
log.error(`Could not decrypt protected notes: ${e.message} ${e.stack}`);
|
log.error(`Could not decrypt protected notes: ${e.message} ${e.stack}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
eventService.subscribeBeccaLoader(eventService.LEAVE_PROTECTED_SESSION, load);
|
eventService.subscribeBeccaLoader(eventService.LEAVE_PROTECTED_SESSION, load);
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
load,
|
load,
|
||||||
reload,
|
reload,
|
||||||
beccaLoaded
|
beccaLoaded
|
@ -1,10 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const becca = require('./becca');
|
import becca = require('./becca');
|
||||||
const cls = require('../services/cls');
|
import cls = require('../services/cls');
|
||||||
const log = require('../services/log');
|
import log = require('../services/log');
|
||||||
|
|
||||||
function isNotePathArchived(notePath) {
|
function isNotePathArchived(notePath: string[]) {
|
||||||
const noteId = notePath[notePath.length - 1];
|
const noteId = notePath[notePath.length - 1];
|
||||||
const note = becca.notes[noteId];
|
const note = becca.notes[noteId];
|
||||||
|
|
||||||
@ -24,9 +24,9 @@ function isNotePathArchived(notePath) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteTitle(childNoteId, parentNoteId) {
|
function getNoteTitle(childNoteId: string, parentNoteId?: string) {
|
||||||
const childNote = becca.notes[childNoteId];
|
const childNote = becca.notes[childNoteId];
|
||||||
const parentNote = becca.notes[parentNoteId];
|
const parentNote = parentNoteId ? becca.notes[parentNoteId] : null;
|
||||||
|
|
||||||
if (!childNote) {
|
if (!childNote) {
|
||||||
log.info(`Cannot find note '${childNoteId}'`);
|
log.info(`Cannot find note '${childNoteId}'`);
|
||||||
@ -40,7 +40,7 @@ function getNoteTitle(childNoteId, parentNoteId) {
|
|||||||
return `${(branch && branch.prefix) ? `${branch.prefix} - ` : ''}${title}`;
|
return `${(branch && branch.prefix) ? `${branch.prefix} - ` : ''}${title}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteTitleArrayForPath(notePathArray) {
|
function getNoteTitleArrayForPath(notePathArray: string[]) {
|
||||||
if (!notePathArray || !Array.isArray(notePathArray)) {
|
if (!notePathArray || !Array.isArray(notePathArray)) {
|
||||||
throw new Error(`${notePathArray} is not an array.`);
|
throw new Error(`${notePathArray} is not an array.`);
|
||||||
}
|
}
|
||||||
@ -76,13 +76,13 @@ function getNoteTitleArrayForPath(notePathArray) {
|
|||||||
return titles;
|
return titles;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteTitleForPath(notePathArray) {
|
function getNoteTitleForPath(notePathArray: string[]) {
|
||||||
const titles = getNoteTitleArrayForPath(notePathArray);
|
const titles = getNoteTitleArrayForPath(notePathArray);
|
||||||
|
|
||||||
return titles.join(' / ');
|
return titles.join(' / ');
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getNoteTitle,
|
getNoteTitle,
|
||||||
getNoteTitleForPath,
|
getNoteTitleForPath,
|
||||||
isNotePathArchived
|
isNotePathArchived
|
@ -9,25 +9,15 @@ import cls = require('../../services/cls');
|
|||||||
import log = require('../../services/log');
|
import log = require('../../services/log');
|
||||||
import protectedSessionService = require('../../services/protected_session');
|
import protectedSessionService = require('../../services/protected_session');
|
||||||
import blobService = require('../../services/blob');
|
import blobService = require('../../services/blob');
|
||||||
import Becca = require('../becca-interface');
|
import Becca, { ConstructorData } from '../becca-interface';
|
||||||
|
|
||||||
let becca: Becca | null = null;
|
let becca: Becca;
|
||||||
|
|
||||||
interface ContentOpts {
|
interface ContentOpts {
|
||||||
forceSave?: boolean;
|
forceSave?: boolean;
|
||||||
forceFrontendReload?: boolean;
|
forceFrontendReload?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
interface ConstructorData<T extends AbstractBeccaEntity<T>> {
|
|
||||||
primaryKeyName: string;
|
|
||||||
entityName: string;
|
|
||||||
hashedProperties: (keyof T)[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all backend entities.
|
* Base class for all backend entities.
|
||||||
*
|
*
|
||||||
@ -35,11 +25,12 @@ interface ConstructorData<T extends AbstractBeccaEntity<T>> {
|
|||||||
*/
|
*/
|
||||||
abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> {
|
abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> {
|
||||||
|
|
||||||
protected utcDateCreated?: string;
|
|
||||||
protected utcDateModified?: string;
|
protected utcDateModified?: string;
|
||||||
protected dateCreated?: string;
|
protected dateCreated?: string;
|
||||||
protected dateModified?: string;
|
protected dateModified?: string;
|
||||||
|
|
||||||
|
utcDateCreated!: string;
|
||||||
|
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
isSynced?: boolean;
|
isSynced?: boolean;
|
||||||
blobId?: string;
|
blobId?: string;
|
||||||
@ -101,6 +92,12 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> {
|
|||||||
|
|
||||||
abstract getPojo(): {};
|
abstract getPojo(): {};
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// Do nothing by default, can be overriden in derived classes.
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract updateFromRow(row: unknown): void;
|
||||||
|
|
||||||
get isDeleted(): boolean {
|
get isDeleted(): boolean {
|
||||||
// TODO: Not sure why some entities don't implement it.
|
// TODO: Not sure why some entities don't implement it.
|
||||||
return false;
|
return false;
|
||||||
@ -109,7 +106,8 @@ abstract class AbstractBeccaEntity<T extends AbstractBeccaEntity<T>> {
|
|||||||
/**
|
/**
|
||||||
* Saves entity - executes SQL, but doesn't commit the transaction on its own
|
* Saves entity - executes SQL, but doesn't commit the transaction on its own
|
||||||
*/
|
*/
|
||||||
save(): this {
|
// TODO: opts not used but called a few times, maybe should be used by derived classes or passed to beforeSaving.
|
||||||
|
save(opts?: {}): this {
|
||||||
const constructorData = (this.constructor as unknown as ConstructorData<T>);
|
const constructorData = (this.constructor as unknown as ConstructorData<T>);
|
||||||
const entityName = constructorData.entityName;
|
const entityName = constructorData.entityName;
|
||||||
const primaryKeyName = constructorData.primaryKeyName;
|
const primaryKeyName = constructorData.primaryKeyName;
|
||||||
|
@ -37,16 +37,16 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> {
|
|||||||
noteId?: number;
|
noteId?: number;
|
||||||
attachmentId?: string;
|
attachmentId?: string;
|
||||||
/** either noteId or revisionId to which this attachment belongs */
|
/** either noteId or revisionId to which this attachment belongs */
|
||||||
ownerId: string;
|
ownerId!: string;
|
||||||
role: string;
|
role!: string;
|
||||||
mime: string;
|
mime!: string;
|
||||||
title: string;
|
title!: string;
|
||||||
type?: keyof typeof attachmentRoleToNoteTypeMapping;
|
type?: keyof typeof attachmentRoleToNoteTypeMapping;
|
||||||
position?: number;
|
position?: number;
|
||||||
blobId?: string;
|
blobId?: string;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
dateModified?: string;
|
dateModified?: string;
|
||||||
utcDateScheduledForErasureSince?: string;
|
utcDateScheduledForErasureSince?: string | null;
|
||||||
/** optionally added to the entity */
|
/** optionally added to the entity */
|
||||||
contentLength?: number;
|
contentLength?: number;
|
||||||
isDecrypted?: boolean;
|
isDecrypted?: boolean;
|
||||||
@ -54,6 +54,11 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> {
|
|||||||
constructor(row: AttachmentRow) {
|
constructor(row: AttachmentRow) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.updateFromRow(row);
|
||||||
|
this.decrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromRow(row: AttachmentRow): void {
|
||||||
if (!row.ownerId?.trim()) {
|
if (!row.ownerId?.trim()) {
|
||||||
throw new Error("'ownerId' must be given to initialize a Attachment entity");
|
throw new Error("'ownerId' must be given to initialize a Attachment entity");
|
||||||
} else if (!row.role?.trim()) {
|
} else if (!row.role?.trim()) {
|
||||||
@ -76,8 +81,6 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> {
|
|||||||
this.utcDateModified = row.utcDateModified;
|
this.utcDateModified = row.utcDateModified;
|
||||||
this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince;
|
this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince;
|
||||||
this.contentLength = row.contentLength;
|
this.contentLength = row.contentLength;
|
||||||
|
|
||||||
this.decrypt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(): BAttachment {
|
copy(): BAttachment {
|
||||||
@ -127,8 +130,8 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getContent(): string | Buffer {
|
getContent(): Buffer {
|
||||||
return this._getContent();
|
return this._getContent() as Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
setContent(content: string | Buffer, opts: ContentOpts) {
|
setContent(content: string | Buffer, opts: ContentOpts) {
|
||||||
@ -171,6 +174,11 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> {
|
|||||||
|
|
||||||
if (this.role === 'image' && parentNote.type === 'text') {
|
if (this.role === 'image' && parentNote.type === 'text') {
|
||||||
const origContent = parentNote.getContent();
|
const origContent = parentNote.getContent();
|
||||||
|
|
||||||
|
if (typeof origContent !== "string") {
|
||||||
|
throw new Error(`Note with ID '${note.noteId} has a text type but non-string content.`);
|
||||||
|
}
|
||||||
|
|
||||||
const oldAttachmentUrl = `api/attachments/${this.attachmentId}/image/`;
|
const oldAttachmentUrl = `api/attachments/${this.attachmentId}/image/`;
|
||||||
const newNoteUrl = `api/images/${note.noteId}/`;
|
const newNoteUrl = `api/images/${note.noteId}/`;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class BAttribute extends AbstractBeccaEntity<BAttribute> {
|
|||||||
value!: string;
|
value!: string;
|
||||||
isInheritable!: boolean;
|
isInheritable!: boolean;
|
||||||
|
|
||||||
constructor(row: AttributeRow) {
|
constructor(row?: AttributeRow) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
@ -52,7 +52,7 @@ class BAttribute extends AbstractBeccaEntity<BAttribute> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]: any[]) {
|
update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]: any) {
|
||||||
this.attributeId = attributeId;
|
this.attributeId = attributeId;
|
||||||
this.noteId = noteId;
|
this.noteId = noteId;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
|
import AbstractBeccaEntity = require("./abstract_becca_entity");
|
||||||
import { BlobRow } from "./rows";
|
import { BlobRow } from "./rows";
|
||||||
|
|
||||||
// TODO: Why this does not extend the abstract becca?
|
// TODO: Why this does not extend the abstract becca?
|
||||||
class BBlob {
|
class BBlob extends AbstractBeccaEntity<BBlob> {
|
||||||
static get entityName() { return "blobs"; }
|
static get entityName() { return "blobs"; }
|
||||||
static get primaryKeyName() { return "blobId"; }
|
static get primaryKeyName() { return "blobId"; }
|
||||||
static get hashedProperties() { return ["blobId", "content"]; }
|
static get hashedProperties() { return ["blobId", "content"]; }
|
||||||
|
|
||||||
blobId: string;
|
blobId!: string;
|
||||||
content: string | Buffer;
|
content!: string | Buffer;
|
||||||
contentLength: number;
|
contentLength!: number;
|
||||||
dateModified: string;
|
dateModified!: string;
|
||||||
utcDateModified: string;
|
utcDateModified!: string;
|
||||||
|
|
||||||
constructor(row: BlobRow) {
|
constructor(row: BlobRow) {
|
||||||
|
super();
|
||||||
|
this.updateFromRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromRow(row: BlobRow): void {
|
||||||
this.blobId = row.blobId;
|
this.blobId = row.blobId;
|
||||||
this.content = row.content;
|
this.content = row.content;
|
||||||
this.contentLength = row.contentLength;
|
this.contentLength = row.contentLength;
|
||||||
|
@ -30,7 +30,7 @@ class BBranch extends AbstractBeccaEntity<BBranch> {
|
|||||||
isExpanded!: boolean;
|
isExpanded!: boolean;
|
||||||
utcDateModified?: string;
|
utcDateModified?: string;
|
||||||
|
|
||||||
constructor(row: BranchRow) {
|
constructor(row?: BranchRow) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
|
@ -19,12 +19,12 @@ class BEtapiToken extends AbstractBeccaEntity<BEtapiToken> {
|
|||||||
static get primaryKeyName() { return "etapiTokenId"; }
|
static get primaryKeyName() { return "etapiTokenId"; }
|
||||||
static get hashedProperties() { return ["etapiTokenId", "name", "tokenHash", "utcDateCreated", "utcDateModified", "isDeleted"]; }
|
static get hashedProperties() { return ["etapiTokenId", "name", "tokenHash", "utcDateCreated", "utcDateModified", "isDeleted"]; }
|
||||||
|
|
||||||
etapiTokenId!: string;
|
etapiTokenId?: string;
|
||||||
name!: string;
|
name!: string;
|
||||||
tokenHash!: string;
|
tokenHash!: string;
|
||||||
private _isDeleted!: boolean;
|
private _isDeleted?: boolean;
|
||||||
|
|
||||||
constructor(row: EtapiTokenRow) {
|
constructor(row?: EtapiTokenRow) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
@ -36,7 +36,7 @@ class BEtapiToken extends AbstractBeccaEntity<BEtapiToken> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get isDeleted() {
|
get isDeleted() {
|
||||||
return this._isDeleted;
|
return !!this._isDeleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFromRow(row: EtapiTokenRow) {
|
updateFromRow(row: EtapiTokenRow) {
|
||||||
@ -74,8 +74,10 @@ class BEtapiToken extends AbstractBeccaEntity<BEtapiToken> {
|
|||||||
|
|
||||||
super.beforeSaving();
|
super.beforeSaving();
|
||||||
|
|
||||||
|
if (this.etapiTokenId) {
|
||||||
this.becca.etapiTokens[this.etapiTokenId] = this;
|
this.becca.etapiTokens[this.etapiTokenId] = this;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export = BEtapiToken;
|
export = BEtapiToken;
|
||||||
|
@ -70,7 +70,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
children!: BNote[];
|
children!: BNote[];
|
||||||
targetRelations!: BAttribute[];
|
targetRelations!: BAttribute[];
|
||||||
|
|
||||||
private __flatTextCache!: string | null;
|
__flatTextCache!: string | null;
|
||||||
|
|
||||||
private __attributeCache!: BAttribute[] | null;
|
private __attributeCache!: BAttribute[] | null;
|
||||||
private __inheritableAttributeCache!: BAttribute[] | null;
|
private __inheritableAttributeCache!: BAttribute[] | null;
|
||||||
@ -86,7 +86,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
/** number of note revisions for this note */
|
/** number of note revisions for this note */
|
||||||
private revisionCount!: number | null;
|
private revisionCount!: number | null;
|
||||||
|
|
||||||
constructor(row: Partial<NoteRow>) {
|
constructor(row?: Partial<NoteRow>) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
@ -216,9 +216,8 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
* - changes in the note metadata or title should not trigger note content sync (so we keep separate utcDateModified and entity changes records)
|
* - changes in the note metadata or title should not trigger note content sync (so we keep separate utcDateModified and entity changes records)
|
||||||
* - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity)
|
* - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity)
|
||||||
*/
|
*/
|
||||||
// TODO: original declaration was (string | Buffer), but everywhere it's used as a string.
|
getContent() {
|
||||||
getContent(): string {
|
return this._getContent();
|
||||||
return this._getContent() as string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,7 +225,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
getJsonContent(): {} | null {
|
getJsonContent(): {} | null {
|
||||||
const content = this.getContent();
|
const content = this.getContent();
|
||||||
|
|
||||||
if (!content || !content.trim()) {
|
if (typeof content !== "string" || !content || !content.trim()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +242,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setContent(content: string, opts: ContentOpts = {}) {
|
setContent(content: Buffer | string, opts: ContentOpts = {}) {
|
||||||
this._setContent(content, opts);
|
this._setContent(content, opts);
|
||||||
|
|
||||||
eventService.emit(eventService.NOTE_CONTENT_CHANGE, { entity: this });
|
eventService.emit(eventService.NOTE_CONTENT_CHANGE, { entity: this });
|
||||||
@ -661,7 +660,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
* @param name - relation name to filter
|
* @param name - relation name to filter
|
||||||
* @returns all note's relations (attributes with type relation), including inherited ones
|
* @returns all note's relations (attributes with type relation), including inherited ones
|
||||||
*/
|
*/
|
||||||
getRelations(name: string): BAttribute[] {
|
getRelations(name?: string): BAttribute[] {
|
||||||
return this.getAttributes(RELATION, name);
|
return this.getAttributes(RELATION, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1510,6 +1509,10 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
const oldNoteUrl = `api/images/${this.noteId}/`;
|
const oldNoteUrl = `api/images/${this.noteId}/`;
|
||||||
const newAttachmentUrl = `api/attachments/${attachment.attachmentId}/image/`;
|
const newAttachmentUrl = `api/attachments/${attachment.attachmentId}/image/`;
|
||||||
|
|
||||||
|
if (typeof parentContent !== "string") {
|
||||||
|
throw new Error("Unable to convert image note into attachment because parent note does not have a string content.");
|
||||||
|
}
|
||||||
|
|
||||||
const fixedContent = utils.replaceAll(parentContent, oldNoteUrl, newAttachmentUrl);
|
const fixedContent = utils.replaceAll(parentContent, oldNoteUrl, newAttachmentUrl);
|
||||||
|
|
||||||
parentNote.setContent(fixedContent);
|
parentNote.setContent(fixedContent);
|
||||||
@ -1611,7 +1614,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
revisionAttachment.ownerId = revision.revisionId;
|
revisionAttachment.ownerId = revision.revisionId;
|
||||||
revisionAttachment.setContent(noteAttachment.getContent(), { forceSave: true });
|
revisionAttachment.setContent(noteAttachment.getContent(), { forceSave: true });
|
||||||
|
|
||||||
if (this.type === 'text') {
|
if (this.type === 'text' && typeof noteContent === "string") {
|
||||||
// content is rewritten to point to the revision attachments
|
// content is rewritten to point to the revision attachments
|
||||||
noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`,
|
noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`,
|
||||||
`attachments/${revisionAttachment.attachmentId}`);
|
`attachments/${revisionAttachment.attachmentId}`);
|
||||||
@ -1654,7 +1657,10 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
|||||||
position
|
position
|
||||||
});
|
});
|
||||||
|
|
||||||
content = content || "";
|
if (!content) {
|
||||||
|
throw new Error("Attempted to save an attachment with no content.");
|
||||||
|
}
|
||||||
|
|
||||||
attachment.setContent(content, {forceSave: true});
|
attachment.setContent(content, {forceSave: true});
|
||||||
|
|
||||||
return attachment;
|
return attachment;
|
||||||
|
@ -16,10 +16,12 @@ class BOption extends AbstractBeccaEntity<BOption> {
|
|||||||
value!: string;
|
value!: string;
|
||||||
isSynced!: boolean;
|
isSynced!: boolean;
|
||||||
|
|
||||||
constructor(row: OptionRow) {
|
constructor(row?: OptionRow) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
if (row) {
|
||||||
this.updateFromRow(row);
|
this.updateFromRow(row);
|
||||||
|
}
|
||||||
this.becca.options[this.name] = this;
|
this.becca.options[this.name] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,14 +11,19 @@ import AbstractBeccaEntity = require('./abstract_becca_entity');
|
|||||||
class BRecentNote extends AbstractBeccaEntity<BRecentNote> {
|
class BRecentNote extends AbstractBeccaEntity<BRecentNote> {
|
||||||
static get entityName() { return "recent_notes"; }
|
static get entityName() { return "recent_notes"; }
|
||||||
static get primaryKeyName() { return "noteId"; }
|
static get primaryKeyName() { return "noteId"; }
|
||||||
|
static get hashedProperties() { return ["noteId", "notePath"]; }
|
||||||
|
|
||||||
noteId: string;
|
noteId!: string;
|
||||||
notePath: string;
|
notePath!: string;
|
||||||
utcDateCreated: string;
|
utcDateCreated!: string;
|
||||||
|
|
||||||
constructor(row: RecentNoteRow) {
|
constructor(row: RecentNoteRow) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.updateFromRow(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromRow(row: RecentNoteRow): void {
|
||||||
this.noteId = row.noteId;
|
this.noteId = row.noteId;
|
||||||
this.notePath = row.notePath;
|
this.notePath = row.notePath;
|
||||||
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
|
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
|
||||||
|
@ -29,22 +29,30 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
|||||||
"utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"]; }
|
"utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"]; }
|
||||||
|
|
||||||
revisionId?: string;
|
revisionId?: string;
|
||||||
noteId: string;
|
noteId!: string;
|
||||||
type: string;
|
type!: string;
|
||||||
mime: string;
|
mime!: string;
|
||||||
isProtected: boolean;
|
isProtected!: boolean;
|
||||||
title: string;
|
title!: string;
|
||||||
blobId?: string;
|
blobId?: string;
|
||||||
dateLastEdited?: string;
|
dateLastEdited?: string;
|
||||||
dateCreated: string;
|
dateCreated!: string;
|
||||||
utcDateLastEdited?: string;
|
utcDateLastEdited?: string;
|
||||||
utcDateCreated: string;
|
utcDateCreated!: string;
|
||||||
contentLength?: number;
|
contentLength?: number;
|
||||||
content?: string;
|
content?: string;
|
||||||
|
|
||||||
constructor(row: RevisionRow, titleDecrypted = false) {
|
constructor(row: RevisionRow, titleDecrypted = false) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.updateFromRow(row);
|
||||||
|
if (this.isProtected && !titleDecrypted) {
|
||||||
|
const decryptedTitle = protectedSessionService.isProtectedSessionAvailable() ? protectedSessionService.decryptString(this.title) : null;
|
||||||
|
this.title = decryptedTitle || "[protected]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromRow(row: RevisionRow) {
|
||||||
this.revisionId = row.revisionId;
|
this.revisionId = row.revisionId;
|
||||||
this.noteId = row.noteId;
|
this.noteId = row.noteId;
|
||||||
this.type = row.type;
|
this.type = row.type;
|
||||||
@ -58,11 +66,6 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
|||||||
this.utcDateCreated = row.utcDateCreated;
|
this.utcDateCreated = row.utcDateCreated;
|
||||||
this.utcDateModified = row.utcDateModified;
|
this.utcDateModified = row.utcDateModified;
|
||||||
this.contentLength = row.contentLength;
|
this.contentLength = row.contentLength;
|
||||||
|
|
||||||
if (this.isProtected && !titleDecrypted) {
|
|
||||||
const decryptedTitle = protectedSessionService.isProtectedSessionAvailable() ? protectedSessionService.decryptString(this.title) : null;
|
|
||||||
this.title = decryptedTitle || "[protected]";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getNote() {
|
getNote() {
|
||||||
|
@ -5,7 +5,7 @@ export interface AttachmentRow {
|
|||||||
ownerId?: string;
|
ownerId?: string;
|
||||||
role: string;
|
role: string;
|
||||||
mime: string;
|
mime: string;
|
||||||
title?: string;
|
title: string;
|
||||||
position?: number;
|
position?: number;
|
||||||
blobId?: string;
|
blobId?: string;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
@ -13,7 +13,7 @@ export interface AttachmentRow {
|
|||||||
utcDateModified?: string;
|
utcDateModified?: string;
|
||||||
utcDateScheduledForErasureSince?: string;
|
utcDateScheduledForErasureSince?: string;
|
||||||
contentLength?: number;
|
contentLength?: number;
|
||||||
content?: string;
|
content?: Buffer | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RevisionRow {
|
export interface RevisionRow {
|
||||||
@ -46,12 +46,12 @@ export interface OptionRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface EtapiTokenRow {
|
export interface EtapiTokenRow {
|
||||||
etapiTokenId: string;
|
etapiTokenId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
tokenHash: string;
|
tokenHash: string;
|
||||||
utcDateCreated?: string;
|
utcDateCreated?: string;
|
||||||
utcDateModified?: string;
|
utcDateModified?: string;
|
||||||
isDeleted: boolean;
|
isDeleted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlobRow {
|
export interface BlobRow {
|
||||||
@ -69,9 +69,9 @@ export interface AttributeRow {
|
|||||||
noteId: string;
|
noteId: string;
|
||||||
type: AttributeType;
|
type: AttributeType;
|
||||||
name: string;
|
name: string;
|
||||||
position: number;
|
position?: number;
|
||||||
value: string;
|
value?: string;
|
||||||
isInheritable: boolean;
|
isInheritable?: boolean;
|
||||||
utcDateModified?: string;
|
utcDateModified?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +79,10 @@ export interface BranchRow {
|
|||||||
branchId?: string;
|
branchId?: string;
|
||||||
noteId: string;
|
noteId: string;
|
||||||
parentNoteId: string;
|
parentNoteId: string;
|
||||||
prefix: string | null;
|
prefix?: string | null;
|
||||||
notePosition: number;
|
notePosition: number | null;
|
||||||
isExpanded: boolean;
|
isExpanded?: boolean;
|
||||||
|
isDeleted?: boolean;
|
||||||
utcDateModified?: string;
|
utcDateModified?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,10 +95,12 @@ export type NoteType = ("file" | "image" | "search" | "noteMap" | "launcher" | "
|
|||||||
|
|
||||||
export interface NoteRow {
|
export interface NoteRow {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
|
deleteId: string;
|
||||||
title: string;
|
title: string;
|
||||||
type: NoteType;
|
type: NoteType;
|
||||||
mime: string;
|
mime: string;
|
||||||
isProtected: boolean;
|
isProtected: boolean;
|
||||||
|
isDeleted: boolean;
|
||||||
blobId: string;
|
blobId: string;
|
||||||
dateCreated: string;
|
dateCreated: string;
|
||||||
dateModified: string;
|
dateModified: string;
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
const BAttachment = require('./entities/battachment');
|
|
||||||
const BAttribute = require('./entities/battribute');
|
|
||||||
const BBlob = require('./entities/bblob');
|
|
||||||
const BBranch = require('./entities/bbranch');
|
|
||||||
const BEtapiToken = require('./entities/betapi_token');
|
|
||||||
const BNote = require('./entities/bnote');
|
|
||||||
const BOption = require('./entities/boption');
|
|
||||||
const BRecentNote = require('./entities/brecent_note');
|
|
||||||
const BRevision = require('./entities/brevision');
|
|
||||||
|
|
||||||
const ENTITY_NAME_TO_ENTITY = {
|
|
||||||
"attachments": BAttachment,
|
|
||||||
"attributes": BAttribute,
|
|
||||||
"blobs": BBlob,
|
|
||||||
"branches": BBranch,
|
|
||||||
"etapi_tokens": BEtapiToken,
|
|
||||||
"notes": BNote,
|
|
||||||
"options": BOption,
|
|
||||||
"recent_notes": BRecentNote,
|
|
||||||
"revisions": BRevision
|
|
||||||
};
|
|
||||||
|
|
||||||
function getEntityFromEntityName(entityName) {
|
|
||||||
if (!(entityName in ENTITY_NAME_TO_ENTITY)) {
|
|
||||||
throw new Error(`Entity for table '${entityName}' not found!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ENTITY_NAME_TO_ENTITY[entityName];
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getEntityFromEntityName
|
|
||||||
};
|
|
37
src/becca/entity_constructor.ts
Normal file
37
src/becca/entity_constructor.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { ConstructorData } from './becca-interface';
|
||||||
|
import AbstractBeccaEntity = require('./entities/abstract_becca_entity');
|
||||||
|
import BAttachment = require('./entities/battachment');
|
||||||
|
import BAttribute = require('./entities/battribute');
|
||||||
|
import BBlob = require('./entities/bblob');
|
||||||
|
import BBranch = require('./entities/bbranch');
|
||||||
|
import BEtapiToken = require('./entities/betapi_token');
|
||||||
|
import BNote = require('./entities/bnote');
|
||||||
|
import BOption = require('./entities/boption');
|
||||||
|
import BRecentNote = require('./entities/brecent_note');
|
||||||
|
import BRevision = require('./entities/brevision');
|
||||||
|
|
||||||
|
type EntityClass = new (row?: any) => AbstractBeccaEntity<any>;
|
||||||
|
|
||||||
|
const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass> = {
|
||||||
|
"attachments": BAttachment,
|
||||||
|
"attributes": BAttribute,
|
||||||
|
"blobs": BBlob,
|
||||||
|
"branches": BBranch,
|
||||||
|
"etapi_tokens": BEtapiToken,
|
||||||
|
"notes": BNote,
|
||||||
|
"options": BOption,
|
||||||
|
"recent_notes": BRecentNote,
|
||||||
|
"revisions": BRevision
|
||||||
|
};
|
||||||
|
|
||||||
|
function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) {
|
||||||
|
if (!(entityName in ENTITY_NAME_TO_ENTITY)) {
|
||||||
|
throw new Error(`Entity for table '${entityName}' not found!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ENTITY_NAME_TO_ENTITY[entityName];
|
||||||
|
}
|
||||||
|
|
||||||
|
export = {
|
||||||
|
getEntityFromEntityName
|
||||||
|
};
|
@ -1,8 +1,9 @@
|
|||||||
const becca = require('./becca');
|
import becca = require('./becca');
|
||||||
const log = require('../services/log');
|
import log = require('../services/log');
|
||||||
const beccaService = require('./becca_service');
|
import beccaService = require('./becca_service');
|
||||||
const dateUtils = require('../services/date_utils');
|
import dateUtils = require('../services/date_utils');
|
||||||
const {JSDOM} = require("jsdom");
|
import { JSDOM } from "jsdom";
|
||||||
|
import BNote = require('./entities/bnote');
|
||||||
|
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
|
|
||||||
@ -32,21 +33,25 @@ const IGNORED_ATTR_NAMES = [
|
|||||||
"pageurl",
|
"pageurl",
|
||||||
];
|
];
|
||||||
|
|
||||||
function filterUrlValue(value) {
|
interface DateLimits {
|
||||||
|
minDate: string;
|
||||||
|
minExcludedDate: string;
|
||||||
|
maxExcludedDate: string;
|
||||||
|
maxDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterUrlValue(value: string) {
|
||||||
return value
|
return value
|
||||||
.replace(/https?:\/\//ig, "")
|
.replace(/https?:\/\//ig, "")
|
||||||
.replace(/www.js\./ig, "")
|
.replace(/www.js\./ig, "")
|
||||||
.replace(/(\.net|\.com|\.org|\.info|\.edu)/ig, "");
|
.replace(/(\.net|\.com|\.org|\.info|\.edu)/ig, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function buildRewardMap(note: BNote) {
|
||||||
* @param {BNote} note
|
|
||||||
*/
|
|
||||||
function buildRewardMap(note) {
|
|
||||||
// Need to use Map instead of object: https://github.com/zadam/trilium/issues/1895
|
// Need to use Map instead of object: https://github.com/zadam/trilium/issues/1895
|
||||||
const map = new Map();
|
const map = new Map();
|
||||||
|
|
||||||
function addToRewardMap(text, rewardFactor) {
|
function addToRewardMap(text: string | undefined | null, rewardFactor: number) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -126,7 +131,7 @@ function buildRewardMap(note) {
|
|||||||
const content = note.getContent();
|
const content = note.getContent();
|
||||||
const dom = new JSDOM(content);
|
const dom = new JSDOM(content);
|
||||||
|
|
||||||
function addHeadingsToRewardMap(elName, rewardFactor) {
|
const addHeadingsToRewardMap = (elName: string, rewardFactor: number) => {
|
||||||
for (const el of dom.window.document.querySelectorAll(elName)) {
|
for (const el of dom.window.document.querySelectorAll(elName)) {
|
||||||
addToRewardMap(el.textContent, rewardFactor);
|
addToRewardMap(el.textContent, rewardFactor);
|
||||||
}
|
}
|
||||||
@ -146,9 +151,9 @@ function buildRewardMap(note) {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mimeCache = {};
|
const mimeCache: Record<string, string> = {};
|
||||||
|
|
||||||
function trimMime(mime) {
|
function trimMime(mime: string) {
|
||||||
if (!mime || mime === 'text/html') {
|
if (!mime || mime === 'text/html') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -173,7 +178,7 @@ function trimMime(mime) {
|
|||||||
return mimeCache[mime];
|
return mimeCache[mime];
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildDateLimits(baseNote) {
|
function buildDateLimits(baseNote: BNote): DateLimits {
|
||||||
const dateCreatedTs = dateUtils.parseDateTime(baseNote.utcDateCreated).getTime();
|
const dateCreatedTs = dateUtils.parseDateTime(baseNote.utcDateCreated).getTime();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -193,7 +198,7 @@ const WORD_BLACKLIST = [
|
|||||||
"than", "then", "and", "either", "or", "neither", "nor", "both", "also"
|
"than", "then", "and", "either", "or", "neither", "nor", "both", "also"
|
||||||
];
|
];
|
||||||
|
|
||||||
function splitToWords(text) {
|
function splitToWords(text: string) {
|
||||||
let words = wordCache.get(text);
|
let words = wordCache.get(text);
|
||||||
|
|
||||||
if (!words) {
|
if (!words) {
|
||||||
@ -221,13 +226,13 @@ function splitToWords(text) {
|
|||||||
* includeNoteLink and imageLink relation mean that notes are clearly related, but so clearly
|
* includeNoteLink and imageLink relation mean that notes are clearly related, but so clearly
|
||||||
* that it doesn't actually need to be shown to the user.
|
* that it doesn't actually need to be shown to the user.
|
||||||
*/
|
*/
|
||||||
function hasConnectingRelation(sourceNote, targetNote) {
|
function hasConnectingRelation(sourceNote: BNote, targetNote: BNote) {
|
||||||
return sourceNote.getAttributes().find(attr => attr.type === 'relation'
|
return sourceNote.getAttributes().find(attr => attr.type === 'relation'
|
||||||
&& ['includenotelink', 'imagelink'].includes(attr.name)
|
&& ['includenotelink', 'imagelink'].includes(attr.name)
|
||||||
&& attr.value === targetNote.noteId);
|
&& attr.value === targetNote.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findSimilarNotes(noteId) {
|
async function findSimilarNotes(noteId: string) {
|
||||||
const results = [];
|
const results = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
@ -237,23 +242,23 @@ async function findSimilarNotes(noteId) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let dateLimits;
|
let dateLimits: DateLimits;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dateLimits = buildDateLimits(baseNote);
|
dateLimits = buildDateLimits(baseNote);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e: any) {
|
||||||
throw new Error(`Date limits failed with ${e.message}, entity: ${JSON.stringify(baseNote.getPojo())}`);
|
throw new Error(`Date limits failed with ${e.message}, entity: ${JSON.stringify(baseNote.getPojo())}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rewardMap = buildRewardMap(baseNote);
|
const rewardMap = buildRewardMap(baseNote);
|
||||||
let ancestorRewardCache = {};
|
let ancestorRewardCache: Record<string, number> = {};
|
||||||
const ancestorNoteIds = new Set(baseNote.getAncestors().map(note => note.noteId));
|
const ancestorNoteIds = new Set(baseNote.getAncestors().map(note => note.noteId));
|
||||||
ancestorNoteIds.add(baseNote.noteId);
|
ancestorNoteIds.add(baseNote.noteId);
|
||||||
|
|
||||||
let displayRewards = false;
|
let displayRewards = false;
|
||||||
|
|
||||||
function gatherRewards(text, factor = 1) {
|
function gatherRewards(text?: string | null, factor: number = 1) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -279,7 +284,7 @@ async function findSimilarNotes(noteId) {
|
|||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gatherAncestorRewards(note) {
|
function gatherAncestorRewards(note?: BNote) {
|
||||||
if (!note || ancestorNoteIds.has(note.noteId)) {
|
if (!note || ancestorNoteIds.has(note.noteId)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -311,7 +316,7 @@ async function findSimilarNotes(noteId) {
|
|||||||
return ancestorRewardCache[note.noteId];
|
return ancestorRewardCache[note.noteId];
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeScore(candidateNote) {
|
function computeScore(candidateNote: BNote) {
|
||||||
let score = gatherRewards(trimMime(candidateNote.mime))
|
let score = gatherRewards(trimMime(candidateNote.mime))
|
||||||
+ gatherAncestorRewards(candidateNote);
|
+ gatherAncestorRewards(candidateNote);
|
||||||
|
|
||||||
@ -451,11 +456,11 @@ async function findSimilarNotes(noteId) {
|
|||||||
* see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
|
* see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
|
||||||
*/
|
*/
|
||||||
function setImmediatePromise() {
|
function setImmediatePromise() {
|
||||||
return new Promise((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
setTimeout(() => resolve(), 0);
|
setTimeout(() => resolve(), 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
findSimilarNotes
|
findSimilarNotes
|
||||||
};
|
};
|
@ -6,4 +6,4 @@ class ValidationError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ValidationError;
|
export = ValidationError;
|
@ -1,4 +1,4 @@
|
|||||||
const appInfo = require('../services/app_info.js');
|
const appInfo = require('../services/app_info');
|
||||||
const eu = require('./etapi_utils');
|
const eu = require('./etapi_utils');
|
||||||
|
|
||||||
function register(router) {
|
function register(router) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const eu = require('./etapi_utils');
|
const eu = require('./etapi_utils');
|
||||||
const passwordEncryptionService = require('../services/encryption/password_encryption');
|
const passwordEncryptionService = require('../services/encryption/password_encryption');
|
||||||
const etapiTokenService = require('../services/etapi_tokens.js');
|
const etapiTokenService = require('../services/etapi_tokens');
|
||||||
|
|
||||||
function register(router, loginMiddleware) {
|
function register(router, loginMiddleware) {
|
||||||
eu.NOT_AUTHENTICATED_ROUTE(router, 'post', '/etapi/auth/login', loginMiddleware, (req, res, next) => {
|
eu.NOT_AUTHENTICATED_ROUTE(router, 'post', '/etapi/auth/login', loginMiddleware, (req, res, next) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const eu = require('./etapi_utils');
|
const eu = require('./etapi_utils');
|
||||||
const backupService = require('../services/backup.js');
|
const backupService = require('../services/backup');
|
||||||
|
|
||||||
function register(router) {
|
function register(router) {
|
||||||
eu.route(router, 'put', '/etapi/backup/:backupName', async (req, res, next) => {
|
eu.route(router, 'put', '/etapi/backup/:backupName', async (req, res, next) => {
|
||||||
|
@ -2,7 +2,7 @@ const cls = require('../services/cls');
|
|||||||
const sql = require('../services/sql');
|
const sql = require('../services/sql');
|
||||||
const log = require('../services/log');
|
const log = require('../services/log');
|
||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const etapiTokenService = require('../services/etapi_tokens.js');
|
const etapiTokenService = require('../services/etapi_tokens');
|
||||||
const config = require('../services/config');
|
const config = require('../services/config');
|
||||||
const GENERIC_CODE = "GENERIC";
|
const GENERIC_CODE = "GENERIC";
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ const becca = require('../becca/becca');
|
|||||||
const utils = require('../services/utils');
|
const utils = require('../services/utils');
|
||||||
const eu = require('./etapi_utils');
|
const eu = require('./etapi_utils');
|
||||||
const mappers = require('./mappers.js');
|
const mappers = require('./mappers.js');
|
||||||
const noteService = require('../services/notes.js');
|
const noteService = require('../services/notes');
|
||||||
const TaskContext = require('../services/task_context');
|
const TaskContext = require('../services/task_context');
|
||||||
const v = require('./validators.js');
|
const v = require('./validators.js');
|
||||||
const searchService = require('../services/search/services/search.js');
|
const searchService = require('../services/search/services/search.js');
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const noteTypeService = require('../services/note_types.js');
|
const noteTypeService = require('../services/note_types');
|
||||||
const dateUtils = require('../services/date_utils');
|
const dateUtils = require('../services/date_utils');
|
||||||
|
|
||||||
function mandatory(obj) {
|
function mandatory(obj) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const appInfo = require('../../services/app_info.js');
|
const appInfo = require('../../services/app_info');
|
||||||
|
|
||||||
function getAppInfo() {
|
function getAppInfo() {
|
||||||
return appInfo;
|
return appInfo;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const beccaService = require('../../becca/becca_service.js');
|
const beccaService = require('../../becca/becca_service');
|
||||||
const searchService = require('../../services/search/services/search.js');
|
const searchService = require('../../services/search/services/search.js');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
|
@ -4,7 +4,7 @@ const sql = require('../../services/sql');
|
|||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const entityChangesService = require('../../services/entity_changes');
|
const entityChangesService = require('../../services/entity_changes');
|
||||||
const treeService = require('../../services/tree.js');
|
const treeService = require('../../services/tree.js');
|
||||||
const eraseService = require('../../services/erase.js');
|
const eraseService = require('../../services/erase');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
const TaskContext = require('../../services/task_context');
|
const TaskContext = require('../../services/task_context');
|
||||||
const branchService = require('../../services/branches.js');
|
const branchService = require('../../services/branches.js');
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
const attributeService = require('../../services/attributes.js');
|
const attributeService = require('../../services/attributes.js');
|
||||||
const cloneService = require('../../services/cloning.js');
|
const cloneService = require('../../services/cloning.js');
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const dateNoteService = require('../../services/date_notes.js');
|
const dateNoteService = require('../../services/date_notes.js');
|
||||||
const dateUtils = require('../../services/date_utils');
|
const dateUtils = require('../../services/date_utils');
|
||||||
const imageService = require('../../services/image.js');
|
const imageService = require('../../services/image.js');
|
||||||
const appInfo = require('../../services/app_info.js');
|
const appInfo = require('../../services/app_info');
|
||||||
const ws = require('../../services/ws');
|
const ws = require('../../services/ws');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const htmlSanitizer = require('../../services/html_sanitizer.js');
|
const htmlSanitizer = require('../../services/html_sanitizer');
|
||||||
const {formatAttrForSearch} = require('../../services/attribute_formatter.js');
|
const {formatAttrForSearch} = require('../../services/attribute_formatter');
|
||||||
const jsdom = require("jsdom");
|
const jsdom = require("jsdom");
|
||||||
const { JSDOM } = jsdom;
|
const { JSDOM } = jsdom;
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const backupService = require('../../services/backup.js');
|
const backupService = require('../../services/backup');
|
||||||
const anonymizationService = require('../../services/anonymization.js');
|
const anonymizationService = require('../../services/anonymization');
|
||||||
const consistencyChecksService = require('../../services/consistency_checks.js');
|
const consistencyChecksService = require('../../services/consistency_checks.js');
|
||||||
|
|
||||||
function getExistingBackups() {
|
function getExistingBackups() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const etapiTokenService = require('../../services/etapi_tokens.js');
|
const etapiTokenService = require('../../services/etapi_tokens');
|
||||||
|
|
||||||
function getTokens() {
|
function getTokens() {
|
||||||
const tokens = etapiTokenService.getTokens();
|
const tokens = etapiTokenService.getTokens();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
const protectedSessionService = require('../../services/protected_session');
|
const protectedSessionService = require('../../services/protected_session');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const tmp = require('tmp');
|
const tmp = require('tmp');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { Readable } = require('stream');
|
const { Readable } = require('stream');
|
||||||
|
@ -7,7 +7,7 @@ const singleImportService = require('../../services/import/single.js');
|
|||||||
const cls = require('../../services/cls');
|
const cls = require('../../services/cls');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
const beccaLoader = require('../../becca/becca_loader.js');
|
const beccaLoader = require('../../becca/becca_loader');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const TaskContext = require('../../services/task_context');
|
const TaskContext = require('../../services/task_context');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
const ValidationError = require('../../errors/validation_error');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const keyboardActions = require('../../services/keyboard_actions.js');
|
const keyboardActions = require('../../services/keyboard_actions');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
|
|
||||||
function getKeyboardActions() {
|
function getKeyboardActions() {
|
||||||
|
@ -6,12 +6,12 @@ const dateUtils = require('../../services/date_utils');
|
|||||||
const instanceId = require('../../services/instance_id');
|
const instanceId = require('../../services/instance_id');
|
||||||
const passwordEncryptionService = require('../../services/encryption/password_encryption');
|
const passwordEncryptionService = require('../../services/encryption/password_encryption');
|
||||||
const protectedSessionService = require('../../services/protected_session');
|
const protectedSessionService = require('../../services/protected_session');
|
||||||
const appInfo = require('../../services/app_info.js');
|
const appInfo = require('../../services/app_info');
|
||||||
const eventService = require('../../services/events');
|
const eventService = require('../../services/events');
|
||||||
const sqlInit = require('../../services/sql_init.js');
|
const sqlInit = require('../../services/sql_init');
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const ws = require('../../services/ws');
|
const ws = require('../../services/ws');
|
||||||
const etapiTokenService = require('../../services/etapi_tokens.js');
|
const etapiTokenService = require('../../services/etapi_tokens');
|
||||||
|
|
||||||
function loginSync(req) {
|
function loginSync(req) {
|
||||||
if (!sqlInit.schemaExists()) {
|
if (!sqlInit.schemaExists()) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const eraseService = require('../../services/erase.js');
|
const eraseService = require('../../services/erase');
|
||||||
const treeService = require('../../services/tree.js');
|
const treeService = require('../../services/tree.js');
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const protectedSessionService = require('../../services/protected_session');
|
const protectedSessionService = require('../../services/protected_session');
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
|
|
||||||
function getRecentChanges(req) {
|
function getRecentChanges(req) {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const beccaService = require('../../becca/becca_service.js');
|
const beccaService = require('../../becca/becca_service');
|
||||||
const revisionService = require('../../services/revisions.js');
|
const revisionService = require('../../services/revisions');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const cls = require('../../services/cls');
|
const cls = require('../../services/cls');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
const blobService = require('../../services/blob');
|
const blobService = require('../../services/blob');
|
||||||
const eraseService = require("../../services/erase.js");
|
const eraseService = require("../../services/erase");
|
||||||
|
|
||||||
function getRevisionBlob(req) {
|
function getRevisionBlob(req) {
|
||||||
const preview = req.query.preview === 'true';
|
const preview = req.query.preview === 'true';
|
||||||
|
@ -5,7 +5,7 @@ const SearchContext = require('../../services/search/search_context.js');
|
|||||||
const searchService = require('../../services/search/services/search.js');
|
const searchService = require('../../services/search/services/search.js');
|
||||||
const bulkActionService = require('../../services/bulk_actions.js');
|
const bulkActionService = require('../../services/bulk_actions.js');
|
||||||
const cls = require('../../services/cls');
|
const cls = require('../../services/cls');
|
||||||
const {formatAttrForSearch} = require('../../services/attribute_formatter.js');
|
const {formatAttrForSearch} = require('../../services/attribute_formatter');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
const ValidationError = require('../../errors/validation_error');
|
||||||
|
|
||||||
function searchFromNote(req) {
|
function searchFromNote(req) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const imageType = require('image-type');
|
const imageType = require('image-type');
|
||||||
const imageService = require('../../services/image.js');
|
const imageService = require('../../services/image.js');
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const {sanitizeAttributeName} = require('../../services/sanitize_attribute_name');
|
const {sanitizeAttributeName} = require('../../services/sanitize_attribute_name');
|
||||||
const specialNotesService = require('../../services/special_notes.js');
|
const specialNotesService = require('../../services/special_notes.js');
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sqlInit = require('../../services/sql_init.js');
|
const sqlInit = require('../../services/sql_init');
|
||||||
const setupService = require('../../services/setup.js');
|
const setupService = require('../../services/setup.js');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const appInfo = require('../../services/app_info.js');
|
const appInfo = require('../../services/app_info');
|
||||||
|
|
||||||
function getStatus() {
|
function getStatus() {
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const similarityService = require('../../becca/similarity.js');
|
const similarityService = require('../../becca/similarity');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
|
|
||||||
async function getSimilarNotes(req) {
|
async function getSimilarNotes(req) {
|
||||||
|
@ -4,11 +4,11 @@ const syncService = require('../../services/sync.js');
|
|||||||
const syncUpdateService = require('../../services/sync_update.js');
|
const syncUpdateService = require('../../services/sync_update.js');
|
||||||
const entityChangesService = require('../../services/entity_changes');
|
const entityChangesService = require('../../services/entity_changes');
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const sqlInit = require('../../services/sql_init.js');
|
const sqlInit = require('../../services/sql_init');
|
||||||
const optionService = require('../../services/options');
|
const optionService = require('../../services/options');
|
||||||
const contentHashService = require('../../services/content_hash.js');
|
const contentHashService = require('../../services/content_hash.js');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const syncOptions = require('../../services/sync_options.js');
|
const syncOptions = require('../../services/sync_options');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const ws = require('../../services/ws');
|
const ws = require('../../services/ws');
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const assetPath = require('../services/asset_path.js');
|
const assetPath = require('../services/asset_path');
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const env = require('../services/env');
|
const env = require('../services/env');
|
||||||
|
@ -9,8 +9,8 @@ const env = require('../services/env');
|
|||||||
const utils = require('../services/utils');
|
const utils = require('../services/utils');
|
||||||
const protectedSessionService = require('../services/protected_session');
|
const protectedSessionService = require('../services/protected_session');
|
||||||
const packageJson = require('../../package.json');
|
const packageJson = require('../../package.json');
|
||||||
const assetPath = require('../services/asset_path.js');
|
const assetPath = require('../services/asset_path');
|
||||||
const appPath = require('../services/app_path.js');
|
const appPath = require('../services/app_path');
|
||||||
|
|
||||||
function index(req, res) {
|
function index(req, res) {
|
||||||
const options = optionService.getOptionMap();
|
const options = optionService.getOptionMap();
|
||||||
|
@ -5,8 +5,8 @@ const optionService = require('../services/options');
|
|||||||
const myScryptService = require('../services/encryption/my_scrypt');
|
const myScryptService = require('../services/encryption/my_scrypt');
|
||||||
const log = require('../services/log');
|
const log = require('../services/log');
|
||||||
const passwordService = require('../services/encryption/password');
|
const passwordService = require('../services/encryption/password');
|
||||||
const assetPath = require('../services/asset_path.js');
|
const assetPath = require('../services/asset_path');
|
||||||
const appPath = require('../services/app_path.js');
|
const appPath = require('../services/app_path');
|
||||||
const ValidationError = require('../errors/validation_error');
|
const ValidationError = require('../errors/validation_error');
|
||||||
|
|
||||||
function loginPage(req, res) {
|
function loginPage(req, res) {
|
||||||
|
@ -5,7 +5,7 @@ const multer = require('multer');
|
|||||||
const log = require('../services/log');
|
const log = require('../services/log');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const auth = require('../services/auth.js');
|
const auth = require('../services/auth');
|
||||||
const cls = require('../services/cls');
|
const cls = require('../services/cls');
|
||||||
const sql = require('../services/sql');
|
const sql = require('../services/sql');
|
||||||
const entityChangesService = require('../services/entity_changes');
|
const entityChangesService = require('../services/entity_changes');
|
||||||
@ -28,14 +28,14 @@ const branchesApiRoute = require('./api/branches.js');
|
|||||||
const attachmentsApiRoute = require('./api/attachments.js');
|
const attachmentsApiRoute = require('./api/attachments.js');
|
||||||
const autocompleteApiRoute = require('./api/autocomplete.js');
|
const autocompleteApiRoute = require('./api/autocomplete.js');
|
||||||
const cloningApiRoute = require('./api/cloning.js');
|
const cloningApiRoute = require('./api/cloning.js');
|
||||||
const revisionsApiRoute = require('./api/revisions.js');
|
const revisionsApiRoute = require('./api/revisions');
|
||||||
const recentChangesApiRoute = require('./api/recent_changes.js');
|
const recentChangesApiRoute = require('./api/recent_changes.js');
|
||||||
const optionsApiRoute = require('./api/options.js');
|
const optionsApiRoute = require('./api/options.js');
|
||||||
const passwordApiRoute = require('./api/password');
|
const passwordApiRoute = require('./api/password');
|
||||||
const syncApiRoute = require('./api/sync.js');
|
const syncApiRoute = require('./api/sync.js');
|
||||||
const loginApiRoute = require('./api/login.js');
|
const loginApiRoute = require('./api/login.js');
|
||||||
const recentNotesRoute = require('./api/recent_notes.js');
|
const recentNotesRoute = require('./api/recent_notes.js');
|
||||||
const appInfoRoute = require('./api/app_info.js');
|
const appInfoRoute = require('./api/app_info');
|
||||||
const exportRoute = require('./api/export.js');
|
const exportRoute = require('./api/export.js');
|
||||||
const importRoute = require('./api/import.js');
|
const importRoute = require('./api/import.js');
|
||||||
const setupApiRoute = require('./api/setup.js');
|
const setupApiRoute = require('./api/setup.js');
|
||||||
@ -56,20 +56,20 @@ const keysRoute = require('./api/keys.js');
|
|||||||
const backendLogRoute = require('./api/backend_log.js');
|
const backendLogRoute = require('./api/backend_log.js');
|
||||||
const statsRoute = require('./api/stats.js');
|
const statsRoute = require('./api/stats.js');
|
||||||
const fontsRoute = require('./api/fonts.js');
|
const fontsRoute = require('./api/fonts.js');
|
||||||
const etapiTokensApiRoutes = require('./api/etapi_tokens.js');
|
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.js');
|
||||||
const shareRoutes = require('../share/routes.js');
|
const shareRoutes = require('../share/routes.js');
|
||||||
|
|
||||||
const etapiAuthRoutes = require('../etapi/auth.js');
|
const etapiAuthRoutes = require('../etapi/auth.js');
|
||||||
const etapiAppInfoRoutes = require('../etapi/app_info.js');
|
const etapiAppInfoRoutes = require('../etapi/app_info');
|
||||||
const etapiAttachmentRoutes = require('../etapi/attachments.js');
|
const etapiAttachmentRoutes = require('../etapi/attachments.js');
|
||||||
const etapiAttributeRoutes = require('../etapi/attributes.js');
|
const etapiAttributeRoutes = require('../etapi/attributes.js');
|
||||||
const etapiBranchRoutes = require('../etapi/branches.js');
|
const etapiBranchRoutes = require('../etapi/branches.js');
|
||||||
const etapiNoteRoutes = require('../etapi/notes.js');
|
const etapiNoteRoutes = require('../etapi/notes.js');
|
||||||
const etapiSpecialNoteRoutes = require('../etapi/special_notes.js');
|
const etapiSpecialNoteRoutes = require('../etapi/special_notes.js');
|
||||||
const etapiSpecRoute = require('../etapi/spec.js');
|
const etapiSpecRoute = require('../etapi/spec.js');
|
||||||
const etapiBackupRoute = require('../etapi/backup.js');
|
const etapiBackupRoute = require('../etapi/backup');
|
||||||
|
|
||||||
const csrfMiddleware = csurf({
|
const csrfMiddleware = csurf({
|
||||||
cookie: true,
|
cookie: true,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sqlInit = require('../services/sql_init.js');
|
const sqlInit = require('../services/sql_init');
|
||||||
const setupService = require('../services/setup.js');
|
const setupService = require('../services/setup.js');
|
||||||
const utils = require('../services/utils');
|
const utils = require('../services/utils');
|
||||||
const assetPath = require('../services/asset_path.js');
|
const assetPath = require('../services/asset_path');
|
||||||
const appPath = require('../services/app_path.js');
|
const appPath = require('../services/app_path');
|
||||||
|
|
||||||
function setupPage(req, res) {
|
function setupPage(req, res) {
|
||||||
if (sqlInit.isDbInitialized()) {
|
if (sqlInit.isDbInitialized()) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
const BUILTIN_ATTRIBUTES = require('./builtin_attributes.js');
|
import BUILTIN_ATTRIBUTES = require('./builtin_attributes');
|
||||||
const fs = require("fs-extra");
|
import fs = require("fs-extra");
|
||||||
const dataDir = require('./data_dir');
|
import dataDir = require('./data_dir');
|
||||||
const dateUtils = require('./date_utils');
|
import dateUtils = require('./date_utils');
|
||||||
const Database = require("better-sqlite3");
|
import Database = require("better-sqlite3");
|
||||||
const sql = require('./sql');
|
import sql = require('./sql');
|
||||||
const path = require("path");
|
import path = require("path");
|
||||||
|
|
||||||
function getFullAnonymizationScript() {
|
function getFullAnonymizationScript() {
|
||||||
// we want to delete all non-builtin attributes because they can contain sensitive names and values
|
// we want to delete all non-builtin attributes because they can contain sensitive names and values
|
||||||
@ -48,7 +48,7 @@ function getLightAnonymizationScript() {
|
|||||||
AND value != '';`;
|
AND value != '';`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createAnonymizedCopy(type) {
|
async function createAnonymizedCopy(type: "full" | "light") {
|
||||||
if (!['full', 'light'].includes(type)) {
|
if (!['full', 'light'].includes(type)) {
|
||||||
throw new Error(`Unrecognized anonymization type '${type}'`);
|
throw new Error(`Unrecognized anonymization type '${type}'`);
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const path = require('path');
|
import path = require('path');
|
||||||
const {ELECTRON_APP_ROOT_DIR} = require('./resource_dir');
|
import resourceDir = require('./resource_dir');
|
||||||
const log = require('./log');
|
import log = require('./log');
|
||||||
const os = require('os');
|
import os = require('os');
|
||||||
const fs = require('fs');
|
import fs = require('fs');
|
||||||
const config = require('./config');
|
import config = require('./config');
|
||||||
const utils = require('./utils');
|
import utils = require('./utils');
|
||||||
|
|
||||||
const template = `[Desktop Entry]
|
const template = `[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
@ -28,7 +28,7 @@ function installLocalAppIcon() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(path.resolve(ELECTRON_APP_ROOT_DIR, "trilium-portable.sh"))) {
|
if (!fs.existsSync(path.resolve(resourceDir.ELECTRON_APP_ROOT_DIR, "trilium-portable.sh"))) {
|
||||||
// simple heuristic to detect ".tar.xz" linux build (i.e., not flatpak, not debian)
|
// simple heuristic to detect ".tar.xz" linux build (i.e., not flatpak, not debian)
|
||||||
// only in such case it's necessary to create an icon
|
// only in such case it's necessary to create an icon
|
||||||
return;
|
return;
|
||||||
@ -56,16 +56,16 @@ function installLocalAppIcon() {
|
|||||||
|
|
||||||
function getDesktopFileContent() {
|
function getDesktopFileContent() {
|
||||||
return template
|
return template
|
||||||
.replace("#APP_ROOT_DIR#", escapePath(ELECTRON_APP_ROOT_DIR))
|
.replace("#APP_ROOT_DIR#", escapePath(resourceDir.ELECTRON_APP_ROOT_DIR))
|
||||||
.replace("#EXE_PATH#", escapePath(getExePath()));
|
.replace("#EXE_PATH#", escapePath(getExePath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapePath(path) {
|
function escapePath(path: string) {
|
||||||
return path.replace(/ /g, "\\ ");
|
return path.replace(/ /g, "\\ ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExePath() {
|
function getExePath() {
|
||||||
return path.resolve(ELECTRON_APP_ROOT_DIR, 'trilium');
|
return path.resolve(resourceDir.ELECTRON_APP_ROOT_DIR, 'trilium');
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
@ -1,21 +1,21 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const build = require('./build.js');
|
import build = require('./build');
|
||||||
const packageJson = require('../../package.json');
|
import packageJson = require('../../package.json');
|
||||||
const {TRILIUM_DATA_DIR} = require('./data_dir');
|
import dataDir = require('./data_dir');
|
||||||
|
|
||||||
const APP_DB_VERSION = 228;
|
const APP_DB_VERSION = 228;
|
||||||
const SYNC_VERSION = 32;
|
const SYNC_VERSION = 32;
|
||||||
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
appVersion: packageJson.version,
|
appVersion: packageJson.version,
|
||||||
dbVersion: APP_DB_VERSION,
|
dbVersion: APP_DB_VERSION,
|
||||||
nodeVersion: process.version,
|
nodeVersion: process.version,
|
||||||
syncVersion: SYNC_VERSION,
|
syncVersion: SYNC_VERSION,
|
||||||
buildDate: build.buildDate,
|
buildDate: build.buildDate,
|
||||||
buildRevision: build.buildRevision,
|
buildRevision: build.buildRevision,
|
||||||
dataDirectory: TRILIUM_DATA_DIR,
|
dataDirectory: dataDir.TRILIUM_DATA_DIR,
|
||||||
clipperProtocolVersion: CLIPPER_PROTOCOL_VERSION,
|
clipperProtocolVersion: CLIPPER_PROTOCOL_VERSION,
|
||||||
utcDateTime: new Date().toISOString() // for timezone inference
|
utcDateTime: new Date().toISOString() // for timezone inference
|
||||||
};
|
};
|
@ -1,6 +0,0 @@
|
|||||||
const assetPath = require('./asset_path.js');
|
|
||||||
const env = require('./env');
|
|
||||||
|
|
||||||
module.exports = env.isDev()
|
|
||||||
? assetPath + "/app"
|
|
||||||
: assetPath + "/app-dist";
|
|
6
src/services/app_path.ts
Normal file
6
src/services/app_path.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import assetPath = require('./asset_path');
|
||||||
|
import env = require('./env');
|
||||||
|
|
||||||
|
export = env.isDev()
|
||||||
|
? assetPath + "/app"
|
||||||
|
: assetPath + "/app-dist";
|
@ -1,3 +0,0 @@
|
|||||||
const packageJson = require('../../package.json');
|
|
||||||
|
|
||||||
module.exports = `assets/v${packageJson.version}`;
|
|
3
src/services/asset_path.ts
Normal file
3
src/services/asset_path.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import packageJson = require('../../package.json');
|
||||||
|
|
||||||
|
export = `assets/v${packageJson.version}`;
|
@ -1,6 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function formatAttrForSearch(attr, searchWithValue) {
|
import BAttribute = require("../becca/entities/battribute");
|
||||||
|
|
||||||
|
function formatAttrForSearch(attr: BAttribute, searchWithValue: string) {
|
||||||
let searchStr = '';
|
let searchStr = '';
|
||||||
|
|
||||||
if (attr.type === 'label') {
|
if (attr.type === 'label') {
|
||||||
@ -27,7 +29,7 @@ function formatAttrForSearch(attr, searchWithValue) {
|
|||||||
return searchStr;
|
return searchStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatValue(val) {
|
function formatValue(val: string) {
|
||||||
if (!/[^\w]/.test(val)) {
|
if (!/[^\w]/.test(val)) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -45,6 +47,6 @@ function formatValue(val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
formatAttrForSearch
|
formatAttrForSearch
|
||||||
};
|
};
|
@ -4,8 +4,8 @@ const searchService = require('./search/services/search.js');
|
|||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const BAttribute = require('../becca/entities/battribute');
|
const BAttribute = require('../becca/entities/battribute');
|
||||||
const {formatAttrForSearch} = require('./attribute_formatter.js');
|
const {formatAttrForSearch} = require('./attribute_formatter');
|
||||||
const BUILTIN_ATTRIBUTES = require('./builtin_attributes.js');
|
const BUILTIN_ATTRIBUTES = require('./builtin_attributes');
|
||||||
|
|
||||||
const ATTRIBUTE_TYPES = ['label', 'relation'];
|
const ATTRIBUTE_TYPES = ['label', 'relation'];
|
||||||
|
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const etapiTokenService = require('./etapi_tokens.js');
|
import etapiTokenService = require('./etapi_tokens');
|
||||||
const log = require('./log');
|
import log = require('./log');
|
||||||
const sqlInit = require('./sql_init.js');
|
import sqlInit = require('./sql_init');
|
||||||
const utils = require('./utils');
|
import utils = require('./utils');
|
||||||
const passwordEncryptionService = require('./encryption/password_encryption');
|
import passwordEncryptionService = require('./encryption/password_encryption');
|
||||||
const config = require('./config');
|
import config = require('./config');
|
||||||
const passwordService = require('./encryption/password');
|
import passwordService = require('./encryption/password');
|
||||||
|
import type { NextFunction, Request, Response } from 'express';
|
||||||
|
|
||||||
const noAuthentication = config.General && config.General.noAuthentication === true;
|
const noAuthentication = config.General && config.General.noAuthentication === true;
|
||||||
|
|
||||||
function checkAuth(req, res, next) {
|
interface AppRequest extends Request {
|
||||||
|
headers: {
|
||||||
|
authorization?: string;
|
||||||
|
"trilium-cred"?: string;
|
||||||
|
}
|
||||||
|
session: {
|
||||||
|
loggedIn: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkAuth(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!sqlInit.isDbInitialized()) {
|
if (!sqlInit.isDbInitialized()) {
|
||||||
res.redirect("setup");
|
res.redirect("setup");
|
||||||
}
|
}
|
||||||
@ -24,7 +35,7 @@ function checkAuth(req, res, next) {
|
|||||||
|
|
||||||
// for electron things which need network stuff
|
// for electron things which need network stuff
|
||||||
// currently, we're doing that for file upload because handling form data seems to be difficult
|
// currently, we're doing that for file upload because handling form data seems to be difficult
|
||||||
function checkApiAuthOrElectron(req, res, next) {
|
function checkApiAuthOrElectron(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!req.session.loggedIn && !utils.isElectron() && !noAuthentication) {
|
if (!req.session.loggedIn && !utils.isElectron() && !noAuthentication) {
|
||||||
reject(req, res, "Logged in session not found");
|
reject(req, res, "Logged in session not found");
|
||||||
}
|
}
|
||||||
@ -33,7 +44,7 @@ function checkApiAuthOrElectron(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkApiAuth(req, res, next) {
|
function checkApiAuth(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!req.session.loggedIn && !noAuthentication) {
|
if (!req.session.loggedIn && !noAuthentication) {
|
||||||
reject(req, res, "Logged in session not found");
|
reject(req, res, "Logged in session not found");
|
||||||
}
|
}
|
||||||
@ -42,7 +53,7 @@ function checkApiAuth(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkAppInitialized(req, res, next) {
|
function checkAppInitialized(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!sqlInit.isDbInitialized()) {
|
if (!sqlInit.isDbInitialized()) {
|
||||||
res.redirect("setup");
|
res.redirect("setup");
|
||||||
}
|
}
|
||||||
@ -51,7 +62,7 @@ function checkAppInitialized(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPasswordSet(req, res, next) {
|
function checkPasswordSet(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!utils.isElectron() && !passwordService.isPasswordSet()) {
|
if (!utils.isElectron() && !passwordService.isPasswordSet()) {
|
||||||
res.redirect("set-password");
|
res.redirect("set-password");
|
||||||
} else {
|
} else {
|
||||||
@ -59,7 +70,7 @@ function checkPasswordSet(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPasswordNotSet(req, res, next) {
|
function checkPasswordNotSet(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!utils.isElectron() && passwordService.isPasswordSet()) {
|
if (!utils.isElectron() && passwordService.isPasswordSet()) {
|
||||||
res.redirect("login");
|
res.redirect("login");
|
||||||
} else {
|
} else {
|
||||||
@ -67,7 +78,7 @@ function checkPasswordNotSet(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkAppNotInitialized(req, res, next) {
|
function checkAppNotInitialized(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (sqlInit.isDbInitialized()) {
|
if (sqlInit.isDbInitialized()) {
|
||||||
reject(req, res, "App already initialized.");
|
reject(req, res, "App already initialized.");
|
||||||
}
|
}
|
||||||
@ -76,7 +87,7 @@ function checkAppNotInitialized(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkEtapiToken(req, res, next) {
|
function checkEtapiToken(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (etapiTokenService.isValidAuthHeader(req.headers.authorization)) {
|
if (etapiTokenService.isValidAuthHeader(req.headers.authorization)) {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
@ -85,7 +96,7 @@ function checkEtapiToken(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reject(req, res, message) {
|
function reject(req: AppRequest, res: Response, message: string) {
|
||||||
log.info(`${req.method} ${req.path} rejected with 401 ${message}`);
|
log.info(`${req.method} ${req.path} rejected with 401 ${message}`);
|
||||||
|
|
||||||
res.setHeader("Content-Type", "text/plain")
|
res.setHeader("Content-Type", "text/plain")
|
||||||
@ -93,7 +104,7 @@ function reject(req, res, message) {
|
|||||||
.send(message);
|
.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCredentials(req, res, next) {
|
function checkCredentials(req: AppRequest, res: Response, next: NextFunction) {
|
||||||
if (!sqlInit.isDbInitialized()) {
|
if (!sqlInit.isDbInitialized()) {
|
||||||
res.setHeader("Content-Type", "text/plain")
|
res.setHeader("Content-Type", "text/plain")
|
||||||
.status(400)
|
.status(400)
|
||||||
@ -109,7 +120,7 @@ function checkCredentials(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const header = req.headers['trilium-cred'] || '';
|
const header = req.headers['trilium-cred'] || '';
|
||||||
const auth = new Buffer.from(header, 'base64').toString();
|
const auth = Buffer.from(header, 'base64').toString();
|
||||||
const colonIndex = auth.indexOf(':');
|
const colonIndex = auth.indexOf(':');
|
||||||
const password = colonIndex === -1 ? "" : auth.substr(colonIndex + 1);
|
const password = colonIndex === -1 ? "" : auth.substr(colonIndex + 1);
|
||||||
// username is ignored
|
// username is ignored
|
||||||
@ -124,7 +135,7 @@ function checkCredentials(req, res, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
checkAuth,
|
checkAuth,
|
||||||
checkApiAuth,
|
checkApiAuth,
|
||||||
checkAppInitialized,
|
checkAppInitialized,
|
@ -1,5 +1,5 @@
|
|||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const noteService = require('./notes.js');
|
const noteService = require('./notes');
|
||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const attributeService = require('./attributes.js');
|
const attributeService = require('./attributes.js');
|
||||||
@ -10,7 +10,7 @@ const axios = require('axios');
|
|||||||
const dayjs = require('dayjs');
|
const dayjs = require('dayjs');
|
||||||
const xml2js = require('xml2js');
|
const xml2js = require('xml2js');
|
||||||
const cloningService = require('./cloning.js');
|
const cloningService = require('./cloning.js');
|
||||||
const appInfo = require('./app_info.js');
|
const appInfo = require('./app_info');
|
||||||
const searchService = require('./search/services/search.js');
|
const searchService = require('./search/services/search.js');
|
||||||
const SearchContext = require('./search/search_context.js');
|
const SearchContext = require('./search/search_context.js');
|
||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
@ -20,7 +20,7 @@ const specialNotesService = require('./special_notes.js');
|
|||||||
const branchService = require('./branches.js');
|
const branchService = require('./branches.js');
|
||||||
const exportService = require('./export/zip.js');
|
const exportService = require('./export/zip.js');
|
||||||
const syncMutex = require('./sync_mutex');
|
const syncMutex = require('./sync_mutex');
|
||||||
const backupService = require('./backup.js');
|
const backupService = require('./backup');
|
||||||
const optionsService = require('./options');
|
const optionsService = require('./options');
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const dateUtils = require('./date_utils');
|
import dateUtils = require('./date_utils');
|
||||||
const optionService = require('./options');
|
import optionService = require('./options');
|
||||||
const fs = require('fs-extra');
|
import fs = require('fs-extra');
|
||||||
const dataDir = require('./data_dir');
|
import dataDir = require('./data_dir');
|
||||||
const log = require('./log');
|
import log = require('./log');
|
||||||
const syncMutexService = require('./sync_mutex');
|
import syncMutexService = require('./sync_mutex');
|
||||||
const cls = require('./cls');
|
import cls = require('./cls');
|
||||||
const sql = require('./sql');
|
import sql = require('./sql');
|
||||||
const path = require('path');
|
import path = require('path');
|
||||||
|
|
||||||
|
type BackupType = ("daily" | "weekly" | "monthly");
|
||||||
|
|
||||||
function getExistingBackups() {
|
function getExistingBackups() {
|
||||||
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
||||||
@ -35,13 +37,13 @@ function regularBackup() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBackupEnabled(backupType) {
|
function isBackupEnabled(backupType: BackupType) {
|
||||||
const optionName = `${backupType}BackupEnabled`;
|
const optionName = `${backupType}BackupEnabled`;
|
||||||
|
|
||||||
return optionService.getOptionBool(optionName);
|
return optionService.getOptionBool(optionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function periodBackup(optionName, backupType, periodInSeconds) {
|
function periodBackup(optionName: string, backupType: BackupType, periodInSeconds: number) {
|
||||||
if (!isBackupEnabled(backupType)) {
|
if (!isBackupEnabled(backupType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -56,7 +58,7 @@ function periodBackup(optionName, backupType, periodInSeconds) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function backupNow(name) {
|
async function backupNow(name: string) {
|
||||||
// we don't want to back up DB in the middle of sync with potentially inconsistent DB state
|
// we don't want to back up DB in the middle of sync with potentially inconsistent DB state
|
||||||
return await syncMutexService.doExclusively(async () => {
|
return await syncMutexService.doExclusively(async () => {
|
||||||
const backupFile = `${dataDir.BACKUP_DIR}/backup-${name}.db`;
|
const backupFile = `${dataDir.BACKUP_DIR}/backup-${name}.db`;
|
||||||
@ -73,7 +75,7 @@ if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
|||||||
fs.mkdirSync(dataDir.BACKUP_DIR, 0o700);
|
fs.mkdirSync(dataDir.BACKUP_DIR, 0o700);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getExistingBackups,
|
getExistingBackups,
|
||||||
backupNow,
|
backupNow,
|
||||||
regularBackup
|
regularBackup
|
@ -1 +0,0 @@
|
|||||||
module.exports = { buildDate:"2024-03-28T07:11:39+01:00", buildRevision: "399458b52f250b22be22d980a78de0b3390d7521" };
|
|
1
src/services/build.ts
Normal file
1
src/services/build.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export = { buildDate:"2024-03-28T07:11:39+01:00", buildRevision: "399458b52f250b22be22d980a78de0b3390d7521" };
|
@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
export = [
|
||||||
// label names
|
// label names
|
||||||
{ type: 'label', name: 'inbox' },
|
{ type: 'label', name: 'inbox' },
|
||||||
{ type: 'label', name: 'disableVersioning' },
|
{ type: 'label', name: 'disableVersioning' },
|
@ -1,10 +1,10 @@
|
|||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const revisionService = require('./revisions.js');
|
const revisionService = require('./revisions');
|
||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const cloningService = require('./cloning.js');
|
const cloningService = require('./cloning.js');
|
||||||
const branchService = require('./branches.js');
|
const branchService = require('./branches.js');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const eraseService = require("./erase.js");
|
const eraseService = require("./erase");
|
||||||
|
|
||||||
const ACTION_HANDLERS = {
|
const ACTION_HANDLERS = {
|
||||||
addLabel: (action, note) => {
|
addLabel: (action, note) => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
const sqlInit = require('./sql_init.js');
|
const sqlInit = require('./sql_init');
|
||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const ws = require('./ws');
|
const ws = require('./ws');
|
||||||
const syncMutexService = require('./sync_mutex');
|
const syncMutexService = require('./sync_mutex');
|
||||||
@ -9,12 +9,12 @@ const cls = require('./cls');
|
|||||||
const entityChangesService = require('./entity_changes');
|
const entityChangesService = require('./entity_changes');
|
||||||
const optionsService = require('./options');
|
const optionsService = require('./options');
|
||||||
const BBranch = require('../becca/entities/bbranch');
|
const BBranch = require('../becca/entities/bbranch');
|
||||||
const revisionService = require('./revisions.js');
|
const revisionService = require('./revisions');
|
||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const utils = require('../services/utils');
|
const utils = require('../services/utils');
|
||||||
const eraseService = require('../services/erase.js');
|
const eraseService = require('../services/erase');
|
||||||
const {sanitizeAttributeName} = require('./sanitize_attribute_name');
|
const {sanitizeAttributeName} = require('./sanitize_attribute_name');
|
||||||
const noteTypes = require('../services/note_types.js').getNoteTypeNames();
|
const noteTypes = require('../services/note_types').getNoteTypeNames();
|
||||||
|
|
||||||
class ConsistencyChecks {
|
class ConsistencyChecks {
|
||||||
/**
|
/**
|
||||||
@ -766,7 +766,7 @@ class ConsistencyChecks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.reloadNeeded) {
|
if (this.reloadNeeded) {
|
||||||
require('../becca/becca_loader.js').reload("consistency checks need becca reload");
|
require('../becca/becca_loader').reload("consistency checks need becca reload");
|
||||||
}
|
}
|
||||||
|
|
||||||
return !this.unrecoveredConsistencyErrors;
|
return !this.unrecoveredConsistencyErrors;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const eraseService = require('./erase.js');
|
const eraseService = require('./erase');
|
||||||
|
|
||||||
function getEntityHashes() {
|
function getEntityHashes() {
|
||||||
// blob erasure is not synced, we should check before each sync if there's some blob to erase
|
// blob erasure is not synced, we should check before each sync if there's some blob to erase
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteService = require('./notes.js');
|
const noteService = require('./notes');
|
||||||
const attributeService = require('./attributes.js');
|
const attributeService = require('./attributes.js');
|
||||||
const dateUtils = require('./date_utils');
|
const dateUtils = require('./date_utils');
|
||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
|
@ -65,7 +65,7 @@ function getDateTimeForFile() {
|
|||||||
return new Date().toISOString().substr(0, 19).replace(/:/g, '');
|
return new Date().toISOString().substr(0, 19).replace(/:/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateLocalDateTime(str: string) {
|
function validateLocalDateTime(str: string | null | undefined) {
|
||||||
if (!str) {
|
if (!str) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ function validateLocalDateTime(str: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateUtcDateTime(str: string) {
|
function validateUtcDateTime(str: string | undefined) {
|
||||||
if (!str) {
|
if (!str) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ function resetPassword() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
isPasswordSet,
|
isPasswordSet,
|
||||||
changePassword,
|
changePassword,
|
||||||
setPassword,
|
setPassword,
|
||||||
|
@ -45,7 +45,7 @@ function putEntityChange(origEntityChange: EntityChange) {
|
|||||||
cls.putEntityChange(ec);
|
cls.putEntityChange(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
function putNoteReorderingEntityChange(parentNoteId: string, componentId: string) {
|
function putNoteReorderingEntityChange(parentNoteId: string, componentId?: string) {
|
||||||
putEntityChange({
|
putEntityChange({
|
||||||
entityName: "note_reordering",
|
entityName: "note_reordering",
|
||||||
entityId: parentNoteId,
|
entityId: parentNoteId,
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
const sql = require("./sql");
|
import sql = require("./sql");
|
||||||
const revisionService = require("./revisions.js");
|
import revisionService = require("./revisions");
|
||||||
const log = require("./log");
|
import log = require("./log");
|
||||||
const entityChangesService = require("./entity_changes");
|
import entityChangesService = require("./entity_changes");
|
||||||
const optionService = require("./options");
|
import optionService = require("./options");
|
||||||
const dateUtils = require("./date_utils");
|
import dateUtils = require("./date_utils");
|
||||||
const sqlInit = require("./sql_init.js");
|
import sqlInit = require("./sql_init");
|
||||||
const cls = require("./cls");
|
import cls = require("./cls");
|
||||||
|
import { EntityChange } from "./entity_changes_interface";
|
||||||
|
|
||||||
function eraseNotes(noteIdsToErase) {
|
function eraseNotes(noteIdsToErase: string[]) {
|
||||||
if (noteIdsToErase.length === 0) {
|
if (noteIdsToErase.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -16,17 +17,17 @@ function eraseNotes(noteIdsToErase) {
|
|||||||
setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'notes' AND entityId IN (???)`, noteIdsToErase));
|
setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'notes' AND entityId IN (???)`, noteIdsToErase));
|
||||||
|
|
||||||
// we also need to erase all "dependent" entities of the erased notes
|
// we also need to erase all "dependent" entities of the erased notes
|
||||||
const branchIdsToErase = sql.getManyRows(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase)
|
const branchIdsToErase = sql.getManyRows<{ branchId: string }>(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase)
|
||||||
.map(row => row.branchId);
|
.map(row => row.branchId);
|
||||||
|
|
||||||
eraseBranches(branchIdsToErase);
|
eraseBranches(branchIdsToErase);
|
||||||
|
|
||||||
const attributeIdsToErase = sql.getManyRows(`SELECT attributeId FROM attributes WHERE noteId IN (???)`, noteIdsToErase)
|
const attributeIdsToErase = sql.getManyRows<{ attributeId: string }>(`SELECT attributeId FROM attributes WHERE noteId IN (???)`, noteIdsToErase)
|
||||||
.map(row => row.attributeId);
|
.map(row => row.attributeId);
|
||||||
|
|
||||||
eraseAttributes(attributeIdsToErase);
|
eraseAttributes(attributeIdsToErase);
|
||||||
|
|
||||||
const revisionIdsToErase = sql.getManyRows(`SELECT revisionId FROM revisions WHERE noteId IN (???)`, noteIdsToErase)
|
const revisionIdsToErase = sql.getManyRows<{ revisionId: string }>(`SELECT revisionId FROM revisions WHERE noteId IN (???)`, noteIdsToErase)
|
||||||
.map(row => row.revisionId);
|
.map(row => row.revisionId);
|
||||||
|
|
||||||
eraseRevisions(revisionIdsToErase);
|
eraseRevisions(revisionIdsToErase);
|
||||||
@ -34,7 +35,7 @@ function eraseNotes(noteIdsToErase) {
|
|||||||
log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`);
|
log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setEntityChangesAsErased(entityChanges) {
|
function setEntityChangesAsErased(entityChanges: EntityChange[]) {
|
||||||
for (const ec of entityChanges) {
|
for (const ec of entityChanges) {
|
||||||
ec.isErased = true;
|
ec.isErased = true;
|
||||||
// we're not changing hash here, not sure if good or not
|
// we're not changing hash here, not sure if good or not
|
||||||
@ -45,7 +46,7 @@ function setEntityChangesAsErased(entityChanges) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseBranches(branchIdsToErase) {
|
function eraseBranches(branchIdsToErase: string[]) {
|
||||||
if (branchIdsToErase.length === 0) {
|
if (branchIdsToErase.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -57,7 +58,7 @@ function eraseBranches(branchIdsToErase) {
|
|||||||
log.info(`Erased branches: ${JSON.stringify(branchIdsToErase)}`);
|
log.info(`Erased branches: ${JSON.stringify(branchIdsToErase)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseAttributes(attributeIdsToErase) {
|
function eraseAttributes(attributeIdsToErase: string[]) {
|
||||||
if (attributeIdsToErase.length === 0) {
|
if (attributeIdsToErase.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -69,7 +70,7 @@ function eraseAttributes(attributeIdsToErase) {
|
|||||||
log.info(`Erased attributes: ${JSON.stringify(attributeIdsToErase)}`);
|
log.info(`Erased attributes: ${JSON.stringify(attributeIdsToErase)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseAttachments(attachmentIdsToErase) {
|
function eraseAttachments(attachmentIdsToErase: string[]) {
|
||||||
if (attachmentIdsToErase.length === 0) {
|
if (attachmentIdsToErase.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -81,7 +82,7 @@ function eraseAttachments(attachmentIdsToErase) {
|
|||||||
log.info(`Erased attachments: ${JSON.stringify(attachmentIdsToErase)}`);
|
log.info(`Erased attachments: ${JSON.stringify(attachmentIdsToErase)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseRevisions(revisionIdsToErase) {
|
function eraseRevisions(revisionIdsToErase: string[]) {
|
||||||
if (revisionIdsToErase.length === 0) {
|
if (revisionIdsToErase.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -116,7 +117,7 @@ function eraseUnusedBlobs() {
|
|||||||
log.info(`Erased unused blobs: ${JSON.stringify(unusedBlobIds)}`);
|
log.info(`Erased unused blobs: ${JSON.stringify(unusedBlobIds)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds = null) {
|
function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds: number | null = null) {
|
||||||
// this is important also so that the erased entity changes are sent to the connected clients
|
// this is important also so that the erased entity changes are sent to the connected clients
|
||||||
sql.transactional(() => {
|
sql.transactional(() => {
|
||||||
if (eraseEntitiesAfterTimeInSeconds === null) {
|
if (eraseEntitiesAfterTimeInSeconds === null) {
|
||||||
@ -125,41 +126,33 @@ function eraseDeletedEntities(eraseEntitiesAfterTimeInSeconds = null) {
|
|||||||
|
|
||||||
const cutoffDate = new Date(Date.now() - eraseEntitiesAfterTimeInSeconds * 1000);
|
const cutoffDate = new Date(Date.now() - eraseEntitiesAfterTimeInSeconds * 1000);
|
||||||
|
|
||||||
const noteIdsToErase = sql.getColumn("SELECT noteId FROM notes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
const noteIdsToErase = sql.getColumn<string>("SELECT noteId FROM notes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
||||||
|
|
||||||
eraseNotes(noteIdsToErase);
|
eraseNotes(noteIdsToErase);
|
||||||
|
|
||||||
const branchIdsToErase = sql.getColumn("SELECT branchId FROM branches WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
const branchIdsToErase = sql.getColumn<string>("SELECT branchId FROM branches WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
||||||
|
|
||||||
eraseBranches(branchIdsToErase);
|
eraseBranches(branchIdsToErase);
|
||||||
|
|
||||||
const attributeIdsToErase = sql.getColumn("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
const attributeIdsToErase = sql.getColumn<string>("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
||||||
|
|
||||||
eraseAttributes(attributeIdsToErase);
|
eraseAttributes(attributeIdsToErase);
|
||||||
|
|
||||||
const attachmentIdsToErase = sql.getColumn("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
const attachmentIdsToErase = sql.getColumn<string>("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND utcDateModified <= ?", [dateUtils.utcDateTimeStr(cutoffDate)]);
|
||||||
|
|
||||||
eraseAttachments(attachmentIdsToErase);
|
eraseAttachments(attachmentIdsToErase);
|
||||||
|
|
||||||
eraseUnusedBlobs();
|
eraseUnusedBlobs();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseNotesWithDeleteId(deleteId) {
|
function eraseNotesWithDeleteId(deleteId: string) {
|
||||||
const noteIdsToErase = sql.getColumn("SELECT noteId FROM notes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
const noteIdsToErase = sql.getColumn<string>("SELECT noteId FROM notes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
||||||
|
|
||||||
eraseNotes(noteIdsToErase);
|
eraseNotes(noteIdsToErase);
|
||||||
|
|
||||||
const branchIdsToErase = sql.getColumn("SELECT branchId FROM branches WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
const branchIdsToErase = sql.getColumn<string>("SELECT branchId FROM branches WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
||||||
|
|
||||||
eraseBranches(branchIdsToErase);
|
eraseBranches(branchIdsToErase);
|
||||||
|
|
||||||
const attributeIdsToErase = sql.getColumn("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
const attributeIdsToErase = sql.getColumn<string>("SELECT attributeId FROM attributes WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
||||||
|
|
||||||
eraseAttributes(attributeIdsToErase);
|
eraseAttributes(attributeIdsToErase);
|
||||||
|
|
||||||
const attachmentIdsToErase = sql.getColumn("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
const attachmentIdsToErase = sql.getColumn<string>("SELECT attachmentId FROM attachments WHERE isDeleted = 1 AND deleteId = ?", [deleteId]);
|
||||||
|
|
||||||
eraseAttachments(attachmentIdsToErase);
|
eraseAttachments(attachmentIdsToErase);
|
||||||
|
|
||||||
eraseUnusedBlobs();
|
eraseUnusedBlobs();
|
||||||
@ -173,13 +166,13 @@ function eraseUnusedAttachmentsNow() {
|
|||||||
eraseScheduledAttachments(0);
|
eraseScheduledAttachments(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function eraseScheduledAttachments(eraseUnusedAttachmentsAfterSeconds = null) {
|
function eraseScheduledAttachments(eraseUnusedAttachmentsAfterSeconds: number | null = null) {
|
||||||
if (eraseUnusedAttachmentsAfterSeconds === null) {
|
if (eraseUnusedAttachmentsAfterSeconds === null) {
|
||||||
eraseUnusedAttachmentsAfterSeconds = optionService.getOptionInt('eraseUnusedAttachmentsAfterSeconds');
|
eraseUnusedAttachmentsAfterSeconds = optionService.getOptionInt('eraseUnusedAttachmentsAfterSeconds');
|
||||||
}
|
}
|
||||||
|
|
||||||
const cutOffDate = dateUtils.utcDateTimeStr(new Date(Date.now() - (eraseUnusedAttachmentsAfterSeconds * 1000)));
|
const cutOffDate = dateUtils.utcDateTimeStr(new Date(Date.now() - (eraseUnusedAttachmentsAfterSeconds * 1000)));
|
||||||
const attachmentIdsToErase = sql.getColumn('SELECT attachmentId FROM attachments WHERE utcDateScheduledForErasureSince < ?', [cutOffDate]);
|
const attachmentIdsToErase = sql.getColumn<string>('SELECT attachmentId FROM attachments WHERE utcDateScheduledForErasureSince < ?', [cutOffDate]);
|
||||||
|
|
||||||
eraseAttachments(attachmentIdsToErase);
|
eraseAttachments(attachmentIdsToErase);
|
||||||
}
|
}
|
||||||
@ -193,7 +186,7 @@ sqlInit.dbReady.then(() => {
|
|||||||
setInterval(cls.wrap(() => eraseScheduledAttachments()), 3600 * 1000);
|
setInterval(cls.wrap(() => eraseScheduledAttachments()), 3600 * 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
eraseDeletedNotesNow,
|
eraseDeletedNotesNow,
|
||||||
eraseUnusedAttachmentsNow,
|
eraseUnusedAttachmentsNow,
|
||||||
eraseNotesWithDeleteId,
|
eraseNotesWithDeleteId,
|
@ -1,17 +1,17 @@
|
|||||||
const becca = require('../becca/becca');
|
import becca = require('../becca/becca');
|
||||||
const utils = require('./utils');
|
import utils = require('./utils');
|
||||||
const BEtapiToken = require('../becca/entities/betapi_token');
|
import BEtapiToken = require('../becca/entities/betapi_token');
|
||||||
const crypto = require("crypto");
|
import crypto = require("crypto");
|
||||||
|
|
||||||
function getTokens() {
|
function getTokens() {
|
||||||
return becca.getEtapiTokens();
|
return becca.getEtapiTokens();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTokenHash(token) {
|
function getTokenHash(token: crypto.BinaryLike) {
|
||||||
return crypto.createHash('sha256').update(token).digest('base64');
|
return crypto.createHash('sha256').update(token).digest('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createToken(tokenName) {
|
function createToken(tokenName: string) {
|
||||||
const token = utils.randomSecureToken(32);
|
const token = utils.randomSecureToken(32);
|
||||||
const tokenHash = getTokenHash(token);
|
const tokenHash = getTokenHash(token);
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ function createToken(tokenName) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseAuthToken(auth) {
|
function parseAuthToken(auth: string | undefined) {
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ function parseAuthToken(auth) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidAuthHeader(auth) {
|
function isValidAuthHeader(auth: string | undefined) {
|
||||||
const parsed = parseAuthToken(auth);
|
const parsed = parseAuthToken(auth);
|
||||||
|
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
@ -93,7 +93,7 @@ function isValidAuthHeader(auth) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renameToken(etapiTokenId, newName) {
|
function renameToken(etapiTokenId: string, newName: string) {
|
||||||
const etapiToken = becca.getEtapiToken(etapiTokenId);
|
const etapiToken = becca.getEtapiToken(etapiTokenId);
|
||||||
|
|
||||||
if (!etapiToken) {
|
if (!etapiToken) {
|
||||||
@ -104,7 +104,7 @@ function renameToken(etapiTokenId, newName) {
|
|||||||
etapiToken.save();
|
etapiToken.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteToken(etapiTokenId) {
|
function deleteToken(etapiTokenId: string) {
|
||||||
const etapiToken = becca.getEtapiToken(etapiTokenId);
|
const etapiToken = becca.getEtapiToken(etapiTokenId);
|
||||||
|
|
||||||
if (!etapiToken) {
|
if (!etapiToken) {
|
||||||
@ -114,7 +114,7 @@ function deleteToken(etapiTokenId) {
|
|||||||
etapiToken.markAsDeletedSimple();
|
etapiToken.markAsDeletedSimple();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getTokens,
|
getTokens,
|
||||||
createToken,
|
createToken,
|
||||||
renameToken,
|
renameToken,
|
@ -16,9 +16,9 @@ const archiver = require('archiver');
|
|||||||
const log = require('../log');
|
const log = require('../log');
|
||||||
const TaskContext = require('../task_context');
|
const TaskContext = require('../task_context');
|
||||||
const ValidationError = require('../../errors/validation_error');
|
const ValidationError = require('../../errors/validation_error');
|
||||||
const NoteMeta = require('../meta/note_meta.js');
|
const NoteMeta = require('../meta/note_meta');
|
||||||
const AttachmentMeta = require('../meta/attachment_meta.js');
|
const AttachmentMeta = require('../meta/attachment_meta');
|
||||||
const AttributeMeta = require('../meta/attribute_meta.js');
|
const AttributeMeta = require('../meta/attribute_meta');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TaskContext} taskContext
|
* @param {TaskContext} taskContext
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
const eventService = require('./events');
|
const eventService = require('./events');
|
||||||
const scriptService = require('./script.js');
|
const scriptService = require('./script.js');
|
||||||
const treeService = require('./tree.js');
|
const treeService = require('./tree.js');
|
||||||
const noteService = require('./notes.js');
|
const noteService = require('./notes');
|
||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const BAttribute = require('../becca/entities/battribute');
|
const BAttribute = require('../becca/entities/battribute');
|
||||||
const hiddenSubtreeService = require('./hidden_subtree.js');
|
const hiddenSubtreeService = require('./hidden_subtree');
|
||||||
const oneTimeTimer = require('./one_time_timer.js');
|
const oneTimeTimer = require('./one_time_timer.js');
|
||||||
|
|
||||||
function runAttachedRelations(note, relationName, originEntity) {
|
function runAttachedRelations(note, relationName, originEntity) {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
const becca = require('../becca/becca');
|
import BAttribute = require("../becca/entities/battribute");
|
||||||
const noteService = require('./notes.js');
|
import { AttributeType, NoteType } from "../becca/entities/rows";
|
||||||
const BAttribute = require('../becca/entities/battribute');
|
|
||||||
const log = require('./log');
|
import becca = require('../becca/becca');
|
||||||
const migrationService = require('./migration.js');
|
import noteService = require('./notes');
|
||||||
|
import log = require('./log');
|
||||||
|
import migrationService = require('./migration');
|
||||||
|
|
||||||
const LBTPL_ROOT = "_lbTplRoot";
|
const LBTPL_ROOT = "_lbTplRoot";
|
||||||
const LBTPL_BASE = "_lbTplBase";
|
const LBTPL_BASE = "_lbTplBase";
|
||||||
@ -13,13 +15,36 @@ const LBTPL_BUILTIN_WIDGET = "_lbTplBuiltinWidget";
|
|||||||
const LBTPL_SPACER = "_lbTplSpacer";
|
const LBTPL_SPACER = "_lbTplSpacer";
|
||||||
const LBTPL_CUSTOM_WIDGET = "_lbTplCustomWidget";
|
const LBTPL_CUSTOM_WIDGET = "_lbTplCustomWidget";
|
||||||
|
|
||||||
|
interface Attribute {
|
||||||
|
type: AttributeType;
|
||||||
|
name: string;
|
||||||
|
isInheritable?: boolean;
|
||||||
|
value?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
notePosition?: number;
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
type: NoteType;
|
||||||
|
icon?: string;
|
||||||
|
attributes?: Attribute[];
|
||||||
|
children?: Item[];
|
||||||
|
isExpanded?: boolean;
|
||||||
|
baseSize?: string;
|
||||||
|
growthFactor?: string;
|
||||||
|
targetNoteId?: "_backendLog" | "_globalNoteMap";
|
||||||
|
builtinWidget?: "bookmarks" | "spacer" | "backInHistoryButton" | "forwardInHistoryButton" | "syncStatus" | "protectedSession" | "todayInJournal" | "calendar";
|
||||||
|
command?: "jumpToNote" | "searchNotes" | "createNoteIntoInbox" | "showRecentChanges";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hidden subtree is generated as a "predictable structure" which means that it avoids generating random IDs to always
|
* Hidden subtree is generated as a "predictable structure" which means that it avoids generating random IDs to always
|
||||||
* produce the same structure. This is needed because it is run on multiple instances in the sync cluster which might produce
|
* produce the same structure. This is needed because it is run on multiple instances in the sync cluster which might produce
|
||||||
* duplicate subtrees. This way, all instances will generate the same structure with the same IDs.
|
* duplicate subtrees. This way, all instances will generate the same structure with the same IDs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const HIDDEN_SUBTREE_DEFINITION = {
|
const HIDDEN_SUBTREE_DEFINITION: Item = {
|
||||||
id: '_hidden',
|
id: '_hidden',
|
||||||
title: 'Hidden Notes',
|
title: 'Hidden Notes',
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
@ -244,7 +269,7 @@ function checkHiddenSubtree(force = false) {
|
|||||||
checkHiddenSubtreeRecursively('root', HIDDEN_SUBTREE_DEFINITION);
|
checkHiddenSubtreeRecursively('root', HIDDEN_SUBTREE_DEFINITION);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkHiddenSubtreeRecursively(parentNoteId, item) {
|
function checkHiddenSubtreeRecursively(parentNoteId: string, item: Item) {
|
||||||
if (!item.id || !item.type || !item.title) {
|
if (!item.id || !item.type || !item.title) {
|
||||||
throw new Error(`Item does not contain mandatory properties: ${JSON.stringify(item)}`);
|
throw new Error(`Item does not contain mandatory properties: ${JSON.stringify(item)}`);
|
||||||
}
|
}
|
||||||
@ -337,7 +362,7 @@ function checkHiddenSubtreeRecursively(parentNoteId, item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
checkHiddenSubtree,
|
checkHiddenSubtree,
|
||||||
LBTPL_ROOT,
|
LBTPL_ROOT,
|
||||||
LBTPL_BASE,
|
LBTPL_BASE,
|
@ -1,18 +1,18 @@
|
|||||||
const sanitizeHtml = require('sanitize-html');
|
import sanitizeHtml = require('sanitize-html');
|
||||||
const sanitizeUrl = require('@braintree/sanitize-url').sanitizeUrl;
|
import sanitizeUrl = require('@braintree/sanitize-url');
|
||||||
|
|
||||||
// intended mainly as protection against XSS via import
|
// intended mainly as protection against XSS via import
|
||||||
// secondarily, it (partly) protects against "CSS takeover"
|
// secondarily, it (partly) protects against "CSS takeover"
|
||||||
// sanitize also note titles, label values etc. - there are so many usages which make it difficult
|
// sanitize also note titles, label values etc. - there are so many usages which make it difficult
|
||||||
// to guarantee all of them are properly handled
|
// to guarantee all of them are properly handled
|
||||||
function sanitize(dirtyHtml) {
|
function sanitize(dirtyHtml: string) {
|
||||||
if (!dirtyHtml) {
|
if (!dirtyHtml) {
|
||||||
return dirtyHtml;
|
return dirtyHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid H1 per https://github.com/zadam/trilium/issues/1552
|
// avoid H1 per https://github.com/zadam/trilium/issues/1552
|
||||||
// demote H1, and if that conflicts with existing H2, demote that, etc
|
// demote H1, and if that conflicts with existing H2, demote that, etc
|
||||||
const transformTags = {};
|
const transformTags: Record<string, string> = {};
|
||||||
const lowercasedHtml = dirtyHtml.toLowerCase();
|
const lowercasedHtml = dirtyHtml.toLowerCase();
|
||||||
for (let i = 1; i < 6; ++i) {
|
for (let i = 1; i < 6; ++i) {
|
||||||
if (lowercasedHtml.includes(`<h${i}`)) {
|
if (lowercasedHtml.includes(`<h${i}`)) {
|
||||||
@ -47,9 +47,9 @@ function sanitize(dirtyHtml) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
sanitize,
|
sanitize,
|
||||||
sanitizeUrl: url => {
|
sanitizeUrl: (url: string) => {
|
||||||
return sanitizeUrl(url).trim();
|
return sanitizeUrl.sanitizeUrl(url).trim();
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -3,7 +3,7 @@
|
|||||||
const becca = require('../becca/becca');
|
const becca = require('../becca/becca');
|
||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const protectedSessionService = require('./protected_session');
|
const protectedSessionService = require('./protected_session');
|
||||||
const noteService = require('./notes.js');
|
const noteService = require('./notes');
|
||||||
const optionService = require('./options');
|
const optionService = require('./options');
|
||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
const jimp = require('jimp');
|
const jimp = require('jimp');
|
||||||
@ -11,7 +11,7 @@ const imageType = require('image-type');
|
|||||||
const sanitizeFilename = require('sanitize-filename');
|
const sanitizeFilename = require('sanitize-filename');
|
||||||
const isSvg = require('is-svg');
|
const isSvg = require('is-svg');
|
||||||
const isAnimated = require('is-animated');
|
const isAnimated = require('is-animated');
|
||||||
const htmlSanitizer = require('./html_sanitizer.js');
|
const htmlSanitizer = require('./html_sanitizer');
|
||||||
|
|
||||||
async function processImage(uploadBuffer, originalName, shrinkImageSwitch) {
|
async function processImage(uploadBuffer, originalName, shrinkImageSwitch) {
|
||||||
const compressImages = optionService.getOptionBool("compressImages");
|
const compressImages = optionService.getOptionBool("compressImages");
|
||||||
@ -154,7 +154,7 @@ function saveImageToAttachment(noteId, uploadBuffer, originalName, shrinkImageSw
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
sql.transactional(() => {
|
sql.transactional(() => {
|
||||||
const note = becca.getNoteOrThrow(noteId);
|
const note = becca.getNoteOrThrow(noteId);
|
||||||
const noteService = require('../services/notes.js');
|
const noteService = require('../services/notes');
|
||||||
noteService.asyncPostProcessContent(note, note.getContent()); // to mark an unused attachment for deletion
|
noteService.asyncPostProcessContent(note, note.getContent()); // to mark an unused attachment for deletion
|
||||||
});
|
});
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
@ -4,10 +4,10 @@ const {Throttle} = require('stream-throttle');
|
|||||||
const log = require('../log');
|
const log = require('../log');
|
||||||
const utils = require('../utils');
|
const utils = require('../utils');
|
||||||
const sql = require('../sql');
|
const sql = require('../sql');
|
||||||
const noteService = require('../notes.js');
|
const noteService = require('../notes');
|
||||||
const imageService = require('../image.js');
|
const imageService = require('../image.js');
|
||||||
const protectedSessionService = require('../protected_session');
|
const protectedSessionService = require('../protected_session');
|
||||||
const htmlSanitizer = require('../html_sanitizer.js');
|
const htmlSanitizer = require('../html_sanitizer');
|
||||||
const {sanitizeAttributeName} = require('../sanitize_attribute_name');
|
const {sanitizeAttributeName} = require('../sanitize_attribute_name');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const marked = require("marked");
|
const marked = require("marked");
|
||||||
const htmlSanitizer = require('../html_sanitizer.js');
|
const htmlSanitizer = require('../html_sanitizer');
|
||||||
const importUtils = require('./utils');
|
const importUtils = require('./utils');
|
||||||
|
|
||||||
function renderToHtml(content, title) {
|
function renderToHtml(content, title) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const parseString = require('xml2js').parseString;
|
const parseString = require('xml2js').parseString;
|
||||||
const protectedSessionService = require('../protected_session');
|
const protectedSessionService = require('../protected_session');
|
||||||
const htmlSanitizer = require('../html_sanitizer.js');
|
const htmlSanitizer = require('../html_sanitizer');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {TaskContext} taskContext
|
* @param {TaskContext} taskContext
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const imageService = require('../../services/image.js');
|
const imageService = require('../../services/image.js');
|
||||||
const protectedSessionService = require('../protected_session');
|
const protectedSessionService = require('../protected_session');
|
||||||
const markdownService = require('./markdown.js');
|
const markdownService = require('./markdown.js');
|
||||||
const mimeService = require('./mime.js');
|
const mimeService = require('./mime.js');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const importUtils = require('./utils');
|
const importUtils = require('./utils');
|
||||||
const htmlSanitizer = require('../html_sanitizer.js');
|
const htmlSanitizer = require('../html_sanitizer');
|
||||||
|
|
||||||
function importSingleFile(taskContext, file, parentNote) {
|
function importSingleFile(taskContext, file, parentNote) {
|
||||||
const mime = mimeService.getMime(file.originalname) || file.mimetype;
|
const mime = mimeService.getMime(file.originalname) || file.mimetype;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
const BAttribute = require('../../becca/entities/battribute');
|
const BAttribute = require('../../becca/entities/battribute');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const noteService = require('../../services/notes.js');
|
const noteService = require('../../services/notes');
|
||||||
const attributeService = require('../../services/attributes.js');
|
const attributeService = require('../../services/attributes.js');
|
||||||
const BBranch = require('../../becca/entities/bbranch');
|
const BBranch = require('../../becca/entities/bbranch');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
@ -11,7 +11,7 @@ const protectedSessionService = require('../protected_session');
|
|||||||
const mimeService = require('./mime.js');
|
const mimeService = require('./mime.js');
|
||||||
const treeService = require('../tree.js');
|
const treeService = require('../tree.js');
|
||||||
const yauzl = require("yauzl");
|
const yauzl = require("yauzl");
|
||||||
const htmlSanitizer = require('../html_sanitizer.js');
|
const htmlSanitizer = require('../html_sanitizer');
|
||||||
const becca = require('../../becca/becca');
|
const becca = require('../../becca/becca');
|
||||||
const BAttachment = require('../../becca/entities/battachment');
|
const BAttachment = require('../../becca/entities/battachment');
|
||||||
const markdownService = require('./markdown.js');
|
const markdownService = require('./markdown.js');
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const optionService = require('./options');
|
import optionService = require('./options');
|
||||||
const log = require('./log');
|
import log = require('./log');
|
||||||
const utils = require('./utils');
|
import utils = require('./utils');
|
||||||
|
|
||||||
const isMac = process.platform === "darwin";
|
const isMac = process.platform === "darwin";
|
||||||
const isElectron = utils.isElectron();
|
const isElectron = utils.isElectron();
|
||||||
|
|
||||||
|
interface KeyboardShortcut {
|
||||||
|
separator?: string;
|
||||||
|
actionName?: string;
|
||||||
|
description?: string;
|
||||||
|
defaultShortcuts?: string[];
|
||||||
|
effectiveShortcuts?: string[];
|
||||||
|
scope?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work,
|
* Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work,
|
||||||
* the focus has to be inside the element.
|
* the focus has to be inside the element.
|
||||||
@ -16,7 +25,7 @@ const isElectron = utils.isElectron();
|
|||||||
* e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor.
|
* e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const DEFAULT_KEYBOARD_ACTIONS = [
|
const DEFAULT_KEYBOARD_ACTIONS: KeyboardShortcut[] = [
|
||||||
{
|
{
|
||||||
separator: "Note navigation"
|
separator: "Note navigation"
|
||||||
},
|
},
|
||||||
@ -606,15 +615,15 @@ for (const action of DEFAULT_KEYBOARD_ACTIONS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getKeyboardActions() {
|
function getKeyboardActions() {
|
||||||
const actions = JSON.parse(JSON.stringify(DEFAULT_KEYBOARD_ACTIONS));
|
const actions: KeyboardShortcut[] = JSON.parse(JSON.stringify(DEFAULT_KEYBOARD_ACTIONS));
|
||||||
|
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
action.effectiveShortcuts = action.effectiveShortcuts ? action.defaultShortcuts.slice() : [];
|
action.effectiveShortcuts = action.defaultShortcuts ? action.defaultShortcuts.slice() : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const option of optionService.getOptions()) {
|
for (const option of optionService.getOptions()) {
|
||||||
if (option.name.startsWith('keyboardShortcuts')) {
|
if (option.name.startsWith('keyboardShortcuts')) {
|
||||||
let actionName = option.name.substr(17);
|
let actionName = option.name.substring(17);
|
||||||
actionName = actionName.charAt(0).toLowerCase() + actionName.slice(1);
|
actionName = actionName.charAt(0).toLowerCase() + actionName.slice(1);
|
||||||
|
|
||||||
const action = actions.find(ea => ea.actionName === actionName);
|
const action = actions.find(ea => ea.actionName === actionName);
|
||||||
@ -636,7 +645,7 @@ function getKeyboardActions() {
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
DEFAULT_KEYBOARD_ACTIONS,
|
DEFAULT_KEYBOARD_ACTIONS,
|
||||||
getKeyboardActions
|
getKeyboardActions
|
||||||
};
|
};
|
@ -1,16 +0,0 @@
|
|||||||
class AttachmentMeta {
|
|
||||||
/** @type {string} */
|
|
||||||
attachmentId;
|
|
||||||
/** @type {string} */
|
|
||||||
title;
|
|
||||||
/** @type {string} */
|
|
||||||
role;
|
|
||||||
/** @type {string} */
|
|
||||||
mime;
|
|
||||||
/** @type {int} */
|
|
||||||
position;
|
|
||||||
/** @type {string} */
|
|
||||||
dataFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = AttachmentMeta;
|
|
10
src/services/meta/attachment_meta.ts
Normal file
10
src/services/meta/attachment_meta.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
interface AttachmentMeta {
|
||||||
|
attachmentId: string;
|
||||||
|
title: string;
|
||||||
|
role: string;
|
||||||
|
mime: string;
|
||||||
|
position: number;
|
||||||
|
dataFileName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = AttachmentMeta;
|
@ -1,14 +0,0 @@
|
|||||||
class AttributeMeta {
|
|
||||||
/** @type {string} */
|
|
||||||
type;
|
|
||||||
/** @type {string} */
|
|
||||||
name;
|
|
||||||
/** @type {string} */
|
|
||||||
value;
|
|
||||||
/** @type {boolean} */
|
|
||||||
isInheritable;
|
|
||||||
/** @type {int} */
|
|
||||||
position;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = AttributeMeta;
|
|
9
src/services/meta/attribute_meta.ts
Normal file
9
src/services/meta/attribute_meta.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
interface AttributeMeta {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
isInheritable: boolean;
|
||||||
|
position: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = AttributeMeta;
|
@ -1,36 +0,0 @@
|
|||||||
class NoteMeta {
|
|
||||||
/** @type {string} */
|
|
||||||
noteId;
|
|
||||||
/** @type {string} */
|
|
||||||
notePath;
|
|
||||||
/** @type {boolean} */
|
|
||||||
isClone;
|
|
||||||
/** @type {string} */
|
|
||||||
title;
|
|
||||||
/** @type {int} */
|
|
||||||
notePosition;
|
|
||||||
/** @type {string} */
|
|
||||||
prefix;
|
|
||||||
/** @type {boolean} */
|
|
||||||
isExpanded;
|
|
||||||
/** @type {string} */
|
|
||||||
type;
|
|
||||||
/** @type {string} */
|
|
||||||
mime;
|
|
||||||
/** @type {string} - 'html' or 'markdown', applicable to text notes only */
|
|
||||||
format;
|
|
||||||
/** @type {string} */
|
|
||||||
dataFileName;
|
|
||||||
/** @type {string} */
|
|
||||||
dirFileName;
|
|
||||||
/** @type {boolean} - this file should not be imported (e.g., HTML navigation) */
|
|
||||||
noImport = false;
|
|
||||||
/** @type {AttributeMeta[]} */
|
|
||||||
attributes;
|
|
||||||
/** @type {AttachmentMeta[]} */
|
|
||||||
attachments;
|
|
||||||
/** @type {NoteMeta[]|undefined} */
|
|
||||||
children;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = NoteMeta;
|
|
24
src/services/meta/note_meta.ts
Normal file
24
src/services/meta/note_meta.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import AttributeMeta = require("./attribute_meta");
|
||||||
|
|
||||||
|
interface NoteMeta {
|
||||||
|
noteId: string;
|
||||||
|
notePath: string;
|
||||||
|
isClone: boolean;
|
||||||
|
title: string;
|
||||||
|
notePosition: number;
|
||||||
|
prefix: string;
|
||||||
|
isExpanded: boolean;
|
||||||
|
type: string;
|
||||||
|
mime: string;
|
||||||
|
/** 'html' or 'markdown', applicable to text notes only */
|
||||||
|
format: "html" | "markdown";
|
||||||
|
dataFileName: string;
|
||||||
|
dirFileName: string;
|
||||||
|
/** this file should not be imported (e.g., HTML navigation) */
|
||||||
|
noImport: boolean;
|
||||||
|
attributes: AttributeMeta[];
|
||||||
|
attachments: AttributeMeta[];
|
||||||
|
children?: NoteMeta[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export = NoteMeta;
|
@ -1,11 +1,18 @@
|
|||||||
const backupService = require('./backup.js');
|
import backupService = require('./backup');
|
||||||
const sql = require('./sql');
|
import sql = require('./sql');
|
||||||
const fs = require('fs-extra');
|
import fs = require('fs-extra');
|
||||||
const log = require('./log');
|
import log = require('./log');
|
||||||
const utils = require('./utils');
|
import utils = require('./utils');
|
||||||
const resourceDir = require('./resource_dir');
|
import resourceDir = require('./resource_dir');
|
||||||
const appInfo = require('./app_info.js');
|
import appInfo = require('./app_info');
|
||||||
const cls = require('./cls');
|
import cls = require('./cls');
|
||||||
|
|
||||||
|
interface MigrationInfo {
|
||||||
|
dbVersion: number;
|
||||||
|
name: string;
|
||||||
|
file: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
async function migrate() {
|
async function migrate() {
|
||||||
const currentDbVersion = getDbVersion();
|
const currentDbVersion = getDbVersion();
|
||||||
@ -25,7 +32,12 @@ async function migrate() {
|
|||||||
: 'before-migration'
|
: 'before-migration'
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrations = fs.readdirSync(resourceDir.MIGRATIONS_DIR).map(file => {
|
const migrationFiles = fs.readdirSync(resourceDir.MIGRATIONS_DIR);
|
||||||
|
if (migrationFiles == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const migrations = migrationFiles.map(file => {
|
||||||
const match = file.match(/^([0-9]{4})__([a-zA-Z0-9_ ]+)\.(sql|js)$/);
|
const match = file.match(/^([0-9]{4})__([a-zA-Z0-9_ ]+)\.(sql|js)$/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return null;
|
return null;
|
||||||
@ -45,7 +57,7 @@ async function migrate() {
|
|||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).filter(el => !!el);
|
}).filter((el): el is MigrationInfo => !!el);
|
||||||
|
|
||||||
migrations.sort((a, b) => a.dbVersion - b.dbVersion);
|
migrations.sort((a, b) => a.dbVersion - b.dbVersion);
|
||||||
|
|
||||||
@ -67,7 +79,7 @@ async function migrate() {
|
|||||||
WHERE name = ?`, [mig.dbVersion.toString(), "dbVersion"]);
|
WHERE name = ?`, [mig.dbVersion.toString(), "dbVersion"]);
|
||||||
|
|
||||||
log.info(`Migration to version ${mig.dbVersion} has been successful.`);
|
log.info(`Migration to version ${mig.dbVersion} has been successful.`);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
log.error(`error during migration to version ${mig.dbVersion}: ${e.stack}`);
|
log.error(`error during migration to version ${mig.dbVersion}: ${e.stack}`);
|
||||||
log.error("migration failed, crashing hard"); // this is not very user-friendly :-/
|
log.error("migration failed, crashing hard"); // this is not very user-friendly :-/
|
||||||
|
|
||||||
@ -84,7 +96,7 @@ async function migrate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeMigration(mig) {
|
function executeMigration(mig: MigrationInfo) {
|
||||||
if (mig.type === 'sql') {
|
if (mig.type === 'sql') {
|
||||||
const migrationSql = fs.readFileSync(`${resourceDir.MIGRATIONS_DIR}/${mig.file}`).toString('utf8');
|
const migrationSql = fs.readFileSync(`${resourceDir.MIGRATIONS_DIR}/${mig.file}`).toString('utf8');
|
||||||
|
|
||||||
@ -131,7 +143,7 @@ async function migrateIfNecessary() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
migrateIfNecessary,
|
migrateIfNecessary,
|
||||||
isDbUpToDate
|
isDbUpToDate
|
||||||
};
|
};
|
@ -16,7 +16,7 @@ const noteTypes = [
|
|||||||
{ type: 'contentWidget', defaultMime: '' }
|
{ type: 'contentWidget', defaultMime: '' }
|
||||||
];
|
];
|
||||||
|
|
||||||
function getDefaultMimeForNoteType(typeName) {
|
function getDefaultMimeForNoteType(typeName: string) {
|
||||||
const typeRec = noteTypes.find(nt => nt.type === typeName);
|
const typeRec = noteTypes.find(nt => nt.type === typeName);
|
||||||
|
|
||||||
if (!typeRec) {
|
if (!typeRec) {
|
||||||
@ -26,7 +26,7 @@ function getDefaultMimeForNoteType(typeName) {
|
|||||||
return typeRec.defaultMime;
|
return typeRec.defaultMime;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export = {
|
||||||
getNoteTypeNames: () => noteTypes.map(nt => nt.type),
|
getNoteTypeNames: () => noteTypes.map(nt => nt.type),
|
||||||
getDefaultMimeForNoteType
|
getDefaultMimeForNoteType
|
||||||
};
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user