Compare commits

...

99 Commits

Author SHA1 Message Date
zadam
569b8898ef release 0.50.3 2022-03-22 21:30:21 +01:00
zadam
2f57d55bea add allow robots.txt tag for /share 2022-03-22 21:02:32 +01:00
zadam
0cd690d980 fix inclusion of share.js in builds, fixes #2738 2022-03-21 23:28:19 +01:00
zadam
316a2aee1a invalidate flat text cache after login to protected session, fixes #2712 2022-03-20 22:23:48 +01:00
zadam
ea56bb772a logging improvements 2022-02-20 12:33:50 +01:00
zadam
9f33791922 fix uploading binary data through ETAPI, closes #2667 2022-02-18 22:34:46 +01:00
zadam
d940590add raise line-height in share CSS to 1.5, fixes #2671 2022-02-18 22:00:58 +01:00
zadam
db79b5ff53 fixed blurred selection background color, closes #2652 2022-02-14 22:59:03 +01:00
zadam
23de8e881d make it clear that Dockerfile needs to be run through a script 2022-02-11 22:05:08 +01:00
zadam
59e8720866 fix importing unknown image types such as .DWG, closes #2628 2022-02-11 22:01:45 +01:00
Nriver
40598d2663 fix param validation (#2624)
(cherry picked from commit 1aeb674733)
2022-02-10 19:33:11 +01:00
zadam
832cac106e release 0.50.2 2022-02-09 22:52:36 +01:00
zadam
23daaa2387 fix exporting huge text notes (export would get stuck on HTML pretty printing) 2022-02-09 22:39:37 +01:00
zadam
d6016f9b81 introduced mutex to avoid conflicts during tab closing 2022-02-09 21:21:17 +01:00
zadam
1dfde76b95 fix updating becca after undeleting notes 2022-02-08 23:38:54 +01:00
zadam
83f8fac088 fixed background color of input label in CKEditor search & replace, #2254 2022-02-07 23:01:14 +01:00
zadam
0ca9bff61b fix multiple UI bugs, closes #2616 2022-02-07 22:50:28 +01:00
zadam
1c4358086d release 0.50.1 2022-02-02 21:38:21 +01:00
zadam
0917fc8be1 log messages now contain script context if available 2022-02-01 22:25:38 +01:00
zadam
6833959f3b added regular DB optimization 2022-02-01 21:36:52 +01:00
zadam
398376108d added integrity check button into advanced options. 2022-02-01 21:22:43 +01:00
zadam
61aa029582 Merge remote-tracking branch 'origin/stable'
# Conflicts:
#	package-lock.json
2022-02-01 21:04:17 +01:00
zadam
46eaa63625 focus promoted/owned attributes input after activating the ribbon tab, closes #2606 2022-02-01 20:24:58 +01:00
zadam
1b54596c5e tweaks to handling of branch removal 2022-01-31 22:09:39 +01:00
zadam
2feb778d8d Merge remote-tracking branch 'origin/stable' 2022-01-31 21:25:37 +01:00
zadam
2075e89239 improved logging 2022-01-31 21:25:18 +01:00
zadam
be44431fde fix setting becca's dateModified after marking as deleted 2022-01-30 13:18:22 +01:00
zadam
99cc4078c6 fix setting becca's utcDateModified after marking as deleted 2022-01-30 13:17:40 +01:00
zadam
b8b6b38a20 added links to sharing/ETAPI to README 2022-01-22 12:54:14 +01:00
zadam
efd8556129 release 0.50.0-beta 2022-01-19 20:24:54 +01:00
zadam
b10a76f150 release 0.50.0-beta 2022-01-19 20:14:40 +01:00
U-Bren
780b520506 Add powershell equivalents to existing batch scripts (#2561)
* Add powershell equivalents to existing windows scripts

Each .bat will try to invoke its .ps1 version if powershell is available, or else will fallback on the behavior
previous to this commit.
Should help fix bugs with accents and non-ASCII characters (issue #2327).

* Add powershell equivalents to existing windows scripts

Each .bat will try to invoke its .ps1 version if powershell is available, or else will fallback on the behavior
previous to this commit.
Should help fix bugs with accents and non-ASCII characters (issue #2327).

Co-authored-by: zadam <zadam.apps@gmail.com>
2022-01-17 23:51:25 +01:00
zadam
3055ed86ec Merge remote-tracking branch 'origin/stable' 2022-01-17 23:48:44 +01:00
zadam
4fc3305080 Merge branch 'generateanonymize-script'
# Conflicts:
#	package-lock.json
#	src/services/builtin_attributes.js
2022-01-17 23:48:30 +01:00
zadam
d1b39ee8fa generate anonymization script into a file 2022-01-17 23:47:26 +01:00
zadam
52b118df7f add #shareRoot label to define an "index" note, closes #2567 2022-01-17 23:13:56 +01:00
zadam
a97a7cdcdd fix note title refreshing with old state when user quickly skips to content and starts editing, closes #2566 2022-01-17 20:54:57 +01:00
zadam
1aff3db81f Merge remote-tracking branch 'origin/master' 2022-01-16 22:17:10 +01:00
zadam
fc89e098b1 Merge remote-tracking branch 'origin/stable' 2022-01-16 22:16:49 +01:00
Mirwaisse Djanbaz
64172a7f6b Get file extension before clipping file name (#2562)
I think this fixes https://github.com/zadam/trilium/issues/2131
2022-01-15 22:35:54 +01:00
zadam
66a6c76552 generate anonymization script WIP 2022-01-15 22:09:51 +01:00
zadam
c8884f1917 don't export hidden subtree to ZIP, fixes #2555 2022-01-15 09:04:44 +01:00
zadam
4933b901f6 Merge remote-tracking branch 'origin/stable' 2022-01-14 21:53:00 +01:00
zadam
b679f4218d release 0.49.5 2022-01-14 21:40:37 +01:00
zadam
77c6c4617b changed shared_info class names to avoid conflict with adblocker, closes #2546 2022-01-14 21:23:10 +01:00
zadam
8240a208dd fixed wrong cherry pick 2022-01-14 21:05:39 +01:00
zadam
1c34f73f61 print should include promoted attributes, #2550
(cherry picked from commit a5444fd6ad)
2022-01-14 21:03:21 +01:00
zadam
a5444fd6ad print should include promoted attributes, #2550 2022-01-14 21:02:11 +01:00
zadam
6fbd5a77e4 forgotten note_types 2022-01-14 19:53:59 +01:00
zadam
c102089731 migration workaround for corrupted index in entity_changes table, closes #2534 2022-01-14 19:44:23 +01:00
zadam
742ec44f55 Merge remote-tracking branch 'origin/stable' 2022-01-13 21:53:57 +01:00
zadam
7495777d97 make getAncestors safe in respect to saved search 2022-01-13 21:28:51 +01:00
zadam
da4f26d7ce Merge remote-tracking branch 'origin/stable' 2022-01-13 20:32:37 +01:00
zadam
fa2ffd7574 ignore "Sync not configured" message when toggling shared state 2022-01-13 20:22:50 +01:00
zadam
d4325db207 revised demo document 2022-01-13 20:02:07 +01:00
zadam
48d93cb3da added custom resource handler to the demo document 2022-01-12 21:24:59 +01:00
zadam
2248d98cc7 using 201 for created entities in etapi 2022-01-12 21:14:12 +01:00
zadam
ce046b2e20 small dark theme tweaks 2022-01-12 20:13:11 +01:00
zadam
4f4cbccf08 Merge remote-tracking branch 'origin/stable'
# Conflicts:
#	package-lock.json
2022-01-12 19:54:11 +01:00
zadam
412c745e53 prevent infinite recursion when checking shared status 2022-01-12 19:46:40 +01:00
zadam
28df5d4aa2 etapi improvements and more tests 2022-01-12 19:32:23 +01:00
zadam
42e85aefdc sync fixes 2022-01-10 21:24:07 +01:00
zadam
91e78998d1 unified Jump-To and quick search behavior with regards to hoisting and opening in a new tab 2022-01-10 20:44:59 +01:00
zadam
6f406f9aa2 search immediately when user chooses "full search" from Jump To dialog, #2483 2022-01-10 20:37:33 +01:00
zadam
86fa80f3eb updated API docs 2022-01-10 19:55:09 +01:00
zadam
7119d08022 updated API docs 2022-01-10 19:54:38 +01:00
zadam
916ff5f2ee Merge remote-tracking branch 'origin/next50' 2022-01-10 19:53:36 +01:00
zadam
913d2c06f3 start sync immediately after sharing/unsharing, fixes #2539 2022-01-10 17:15:21 +01:00
zadam
cbb5b31f72 Merge remote-tracking branch 'origin/master' into next50 2022-01-10 17:09:40 +01:00
zadam
91dec23d5e ETAPI auth, spec improvements etc. 2022-01-10 17:09:20 +01:00
zadam
d04d356429 release 0.49.4 2022-01-09 22:32:13 +01:00
zadam
be59f248e8 fix sync skipping some changes and then forcing sector queuing 2022-01-09 22:22:13 +01:00
zadam
2d2641dbd7 sync fixes 2022-01-09 21:25:15 +01:00
zadam
96f4230bc1 Merge branch 'master' into next50
# Conflicts:
#	src/public/app/widgets/containers/root_container.js
#	src/services/app_info.js
2022-01-09 20:18:30 +01:00
zadam
1995b54770 fix migration to preserve IDs in entity_changes 2022-01-09 20:17:27 +01:00
zadam
7159b13c9d add memberId to entity_changes to avoid having to resend all changes second time 2022-01-09 20:16:39 +01:00
zadam
f2732bcab7 fix display of children notes in an empty note, closes #2536 2022-01-09 09:12:21 +01:00
zadam
0e9d76890b use #shareAlias in parent link, closes #2535 2022-01-09 09:04:21 +01:00
zadam
9df521109b fix migration to handle duplicates in entity_changes, #2534 2022-01-08 22:43:34 +01:00
zadam
75b65c396e fix migration to handle duplicates in entity_changes, #2534 2022-01-08 22:31:52 +01:00
zadam
d4d48f3834 use [protected] for protected notes in the export 2022-01-08 21:50:16 +01:00
zadam
b90ba3d1a9 create note from API/import etc. should allow empty title, fixes #2530 2022-01-08 19:33:56 +01:00
zadam
c448d34a38 ETAPI WIP 2022-01-08 19:30:46 +01:00
zadam
c33bc7e12c ETAPI search endpoint 2022-01-08 13:18:12 +01:00
zadam
c5366abf75 ETAPI put content 2022-01-08 12:01:54 +01:00
zadam
2532ea525d ETAPI openapi spec WIP 2022-01-07 23:06:04 +01:00
zadam
d74371c9f5 added missing placeholder.js 2022-01-07 20:30:14 +01:00
zadam
9ee1c9f3da ETAPI delete/patch, refactoring 2022-01-07 19:33:59 +01:00
zadam
82b2871a08 added date services to ETAPI 2022-01-05 19:25:17 +01:00
zadam
e3114e0602 etapi fixes + basic test 2022-01-04 23:00:59 +01:00
zadam
e8acf3f9f3 Merge branch 'master' into next50
# Conflicts:
#	package-lock.json
2022-01-04 22:11:00 +01:00
zadam
e25a904a84 ETAPI - post services WIP 2022-01-03 23:13:51 +01:00
zadam
dcba6ad70d ETAPI (external API) initial read only access 2022-01-03 22:40:01 +01:00
zadam
ffdd917717 Merge branch 'master' into next50 2022-01-03 20:10:48 +01:00
zadam
a38ccde8bc protect tree will check if password is set and send user to options if not 2021-12-30 23:55:36 +01:00
zadam
8120f1bf25 resetting/setting password from options 2021-12-30 22:54:08 +01:00
zadam
f92016f9ec set password from web trilium 2021-12-29 23:37:12 +01:00
zadam
4e31af8c84 set password WIP 2021-12-29 23:19:05 +01:00
zadam
7e48d214ca removed username/password from setup 2021-12-28 22:59:38 +01:00
225 changed files with 7656 additions and 2112 deletions

3
.gitignore vendored
View File

@@ -8,4 +8,5 @@ yarn-error.log
config.ini
cert.key
cert.crt
server-package.json
server-package.json
.idea/httpRequests/

View File

@@ -2,7 +2,7 @@ image:
file: .gitpod.dockerfile
tasks:
- before: nvm install 16.13.1 && nvm use 16.13.1
- before: nvm install 16.13.2 && nvm use 16.13.2
init: npm install
command: npm run start-server

2
.idea/misc.xml generated
View File

@@ -3,7 +3,7 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -1,4 +1,6 @@
FROM node:16.13.1-alpine
# !!! Don't try to build this Dockerfile directly, run it through bin/build-docker.sh script !!!
FROM node:16.13.2-alpine
# Create app directory
WORKDIR /usr/src/app

View File

@@ -16,9 +16,11 @@ Trilium Notes is a hierarchical note taking application with focus on building l
* Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions)
* Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [scripting](https://github.com/zadam/trilium/wiki/Scripts)
* [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server
* [Sharing](https://github.com/zadam/trilium/wiki/Sharing) (publishing) notes to public internet
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes) with per-note granularity
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) and [link maps](https://github.com/zadam/trilium/wiki/Link-map) for visualizing notes and their relations
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)
* [REST API](https://github.com/zadam/trilium/wiki/ETAPI) for automation
* Scales well in both usability and performance upwards of 100 000 notes
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)

3
TODO
View File

@@ -1,3 +0,0 @@
- new icon
- polish becca entities API
- separate private and public APIs in becca entities

View File

@@ -27,6 +27,8 @@ cp images/app-icons/png/128x128.png $BUILD_DIR/icon.png
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
cp bin/tpl/trilium-portable.sh $BUILD_DIR/
chmod 755 $BUILD_DIR/trilium-portable.sh

View File

@@ -23,6 +23,8 @@ rm -rf $BUILD_DIR
# Mac build has by default useless directory level
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
echo "Zipping mac x64 electron distribution..."
VERSION=`jq -r ".version" package.json`

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=16.13.1
NODE_VERSION=16.13.2
if [ "$1" != "DONTCOPY" ]
then
@@ -20,12 +20,16 @@ rm -r $PKG_DIR/node/lib/node_modules/npm
rm -r $PKG_DIR/node/include/node
rm -r $PKG_DIR/node_modules/electron*
rm -r $PKG_DIR/webpack*
rm -r $PKG_DIR/electron.js
cp -r bin/better-sqlite3/linux-server-better_sqlite3.node $PKG_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
printf "#!/bin/sh\n./node/bin/node src/www" > $PKG_DIR/trilium.sh
chmod 755 $PKG_DIR/trilium.sh
cp bin/tpl/anonymize-database.sql $PKG_DIR/
VERSION=`jq -r ".version" package.json`
cd dist

View File

@@ -25,9 +25,9 @@ mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
cp bin/tpl/trilium-portable.bat $BUILD_DIR/
cp bin/tpl/trilium-no-cert-check.bat $BUILD_DIR/
cp bin/tpl/trilium-safe-mode.bat $BUILD_DIR/
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
cp bin/tpl/trilium-{portable,no-cert-check,safe-mode}.{bat,ps1} $BUILD_DIR/
echo "Zipping windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json`

View File

@@ -5,7 +5,7 @@ if [[ $# -eq 0 ]] ; then
exit 1
fi
n exec 16.13.1 npm run webpack
n exec 16.13.2 npm run webpack
DIR=$1
@@ -27,7 +27,7 @@ cp -r electron.js $DIR/
cp webpack-* $DIR/
# run in subshell (so we return to original dir)
(cd $DIR && n exec 16.13.1 npm install --only=prod)
(cd $DIR && n exec 16.13.2 npm install --only=prod)
# cleanup of useless files in dependencies
rm -r $DIR/node_modules/image-q/demo
@@ -44,8 +44,11 @@ find $DIR/node_modules -name demo -exec rm -rf {} \;
find $DIR/libraries -name "*.map" -type f -delete
rm -r $DIR/src/public/app
cp $DIR/src/public/app/share.js $DIR/src/public/app-dist/
rm -rf $DIR/src/public/app
sed -i -e 's/app\/desktop.js/app-dist\/desktop.js/g' $DIR/src/views/desktop.ejs
sed -i -e 's/app\/mobile.js/app-dist\/mobile.js/g' $DIR/src/views/mobile.ejs
sed -i -e 's/app\/setup.js/app-dist\/setup.js/g' $DIR/src/views/setup.ejs
sed -i -e 's/app\/share.js/app-dist\/share.js/g' $DIR/src/views/share/*.ejs

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env node
const anonymizationService = require('../src/services/anonymization');
const fs = require('fs');
const path = require('path');
fs.writeFileSync(path.resolve(__dirname, 'tpl', 'anonymize-database.sql'), anonymizationService.getAnonymizationScript());

View File

@@ -0,0 +1,17 @@
UPDATE etapi_tokens SET tokenHash = 'API token hash value';
UPDATE notes SET title = 'title' WHERE title NOT IN ('root', 'hidden', 'share');
UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL;
UPDATE note_revisions SET title = 'title';
UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL;
UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'hoistedCssClass', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'hoistedInbox', 'hoistedSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarked', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN ('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'hoistedCssClass', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'hoistedInbox', 'hoistedSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarked', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL AND prefix != 'recovered';
UPDATE options SET value = 'anonymized' WHERE name IN
('documentId', 'documentSecret', 'encryptedDataKey',
'passwordVerificationHash', 'passwordVerificationSalt',
'passwordDerivedKeySalt', 'username', 'syncServerHost', 'syncProxy')
AND value != '';
VACUUM;

View File

@@ -1,4 +1,5 @@
SET DIR=%~dp0
set NODE_TLS_REJECT_UNAUTHORIZED=0
cd %DIR%
start trilium.exe
WHERE powershell.exe
IF %ERRORLEVEL% NEQ 0 (start trilium.exe) ELSE (powershell.exe ./trilium-no-cert-check.ps1)

View File

@@ -0,0 +1,2 @@
Set-Item -Path Env:NODE_TLS_REJECT_UNAUTHORIZED -Value 0
./trilium.exe

View File

@@ -1,4 +1,5 @@
SET DIR=%~dp0
SET TRILIUM_DATA_DIR=%DIR%\trilium-data
cd %DIR%
start trilium.exe
WHERE powershell.exe
IF %ERRORLEVEL% NEQ 0 (start trilium.exe) ELSE (powershell.exe ./trilium-portable.ps1)

View File

@@ -0,0 +1,2 @@
Set-Item -Path Env:TRILIUM_DATA_DIR -Value './trilium-data'
./trilium.exe

View File

@@ -1,4 +1,5 @@
SET DIR=%~dp0
SET TRILIUM_SAFE_MODE=1
cd %DIR%
start trilium.exe
WHERE powershell.exe
IF %ERRORLEVEL% NEQ 0 (start trilium.exe) ELSE (powershell.exe ./trilium-safe-mode.ps1)

View File

@@ -0,0 +1,2 @@
Set-Item -Path Env:TRILIUM_SAFE_MODE -Value 1
./trilium.exe

Binary file not shown.

View File

@@ -10,10 +10,20 @@ CREATE TABLE IF NOT EXISTS "mig_entity_changes" (
`utcDateChanged` TEXT NOT NULL
);
INSERT INTO mig_entity_changes (entityName, entityId, hash, isErased, changeId, sourceId, isSynced, utcDateChanged)
SELECT entityName, entityId, hash, isErased, '', sourceId, isSynced, utcDateChanged FROM entity_changes;
INSERT INTO mig_entity_changes (id, entityName, entityId, hash, isErased, changeId, sourceId, isSynced, utcDateChanged)
SELECT id, entityName, entityId, hash, isErased, '', sourceId, isSynced, utcDateChanged FROM entity_changes;
DROP TABLE entity_changes;
-- delete duplicates https://github.com/zadam/trilium/issues/2534
DELETE FROM mig_entity_changes WHERE isErased = 0 AND id IN (
SELECT id FROM mig_entity_changes ec
WHERE (
SELECT COUNT(*) FROM mig_entity_changes
WHERE ec.entityName = mig_entity_changes.entityName
AND ec.entityId = mig_entity_changes.entityId
) > 1
);
DROP TABLE entity_changes;
ALTER TABLE mig_entity_changes RENAME TO entity_changes;

View File

@@ -0,0 +1 @@
DELETE FROM options WHERE name = 'username';

View File

@@ -0,0 +1,15 @@
CREATE TABLE IF NOT EXISTS "etapi_tokens"
(
etapiTokenId TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
tokenHash TEXT NOT NULL,
utcDateCreated TEXT NOT NULL,
utcDateModified TEXT NOT NULL,
isDeleted INT NOT NULL DEFAULT 0);
INSERT INTO etapi_tokens (etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified, isDeleted)
SELECT apiTokenId, 'Trilium Sender', token, utcDateCreated, utcDateCreated, isDeleted FROM api_tokens;
DROP TABLE api_tokens;
UPDATE entity_changes SET entityName = 'etapi_tokens' WHERE entityName = 'api_tokens';

View File

@@ -0,0 +1,10 @@
module.exports = () => {
const sql = require('../../src/services/sql');
const crypto = require('crypto');
for (const {etapiTokenId, token} of sql.getRows("SELECT etapiTokenId, tokenHash AS token FROM etapi_tokens")) {
const tokenHash = crypto.createHash('sha256').update(token).digest('base64');
sql.execute(`UPDATE etapi_tokens SET tokenHash = ? WHERE etapiTokenId = ?`, [tokenHash, etapiTokenId]);
}
};

View File

@@ -0,0 +1,24 @@
CREATE TABLE IF NOT EXISTS "mig_entity_changes" (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`entityName` TEXT NOT NULL,
`entityId` TEXT NOT NULL,
`hash` TEXT NOT NULL,
`isErased` INT NOT NULL,
`changeId` TEXT NOT NULL,
`componentId` TEXT NOT NULL,
`instanceId` TEXT NOT NULL,
`isSynced` INTEGER NOT NULL,
`utcDateChanged` TEXT NOT NULL
);
INSERT INTO mig_entity_changes (id, entityName, entityId, hash, isErased, changeId, componentId, instanceId, isSynced, utcDateChanged)
SELECT id, entityName, entityId, hash, isErased, changeId, '', '', isSynced, utcDateChanged FROM entity_changes;
DROP TABLE entity_changes;
ALTER TABLE mig_entity_changes RENAME TO entity_changes;
CREATE UNIQUE INDEX `IDX_entityChanges_entityName_entityId` ON "entity_changes" (
`entityName`,
`entityId`
);

View File

@@ -0,0 +1 @@
CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`);

View File

@@ -5,15 +5,18 @@ CREATE TABLE IF NOT EXISTS "entity_changes" (
`hash` TEXT NOT NULL,
`isErased` INT NOT NULL,
`changeId` TEXT NOT NULL,
`sourceId` TEXT NOT NULL,
`componentId` TEXT NOT NULL,
`instanceId` TEXT NOT NULL,
`isSynced` INTEGER NOT NULL,
`utcDateChanged` TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "api_tokens"
CREATE TABLE IF NOT EXISTS "etapi_tokens"
(
apiTokenId TEXT PRIMARY KEY NOT NULL,
token TEXT NOT NULL,
etapiTokenId TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
tokenHash TEXT NOT NULL,
utcDateCreated TEXT NOT NULL,
utcDateModified TEXT NOT NULL,
isDeleted INT NOT NULL DEFAULT 0);
CREATE TABLE IF NOT EXISTS "branches" (
`branchId` TEXT NOT NULL,
@@ -50,7 +53,7 @@ CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIM
`noteId` TEXT NOT NULL,
type TEXT DEFAULT '' NOT NULL,
mime TEXT DEFAULT '' NOT NULL,
`title` TEXT,
`title` TEXT NOT NULL,
`isProtected` INT NOT NULL DEFAULT 0,
`utcDateLastEdited` TEXT NOT NULL,
`utcDateCreated` TEXT NOT NULL,
@@ -63,7 +66,7 @@ CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT N
CREATE TABLE IF NOT EXISTS "options"
(
name TEXT not null PRIMARY KEY,
value TEXT,
value TEXT not null,
isSynced INTEGER default 0 not null,
utcDateModified TEXT NOT NULL
);
@@ -96,6 +99,7 @@ CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCr
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`);
CREATE INDEX IDX_attributes_name_value
on attributes (name, value);
CREATE INDEX IDX_attributes_noteId_index

View File

@@ -1,380 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Class: ApiToken</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Class: ApiToken</h1>
<section>
<header>
<h2><span class="attribs"><span class="type-signature"></span></span>ApiToken<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description">ApiToken is an entity representing token used to authenticate against Trilium API from client applications. Currently used only by Trilium Sender.</div>
</header>
<article>
<div class="container-overview">
<h2>Constructor</h2>
<h4 class="name" id="ApiToken"><span class="type-signature"></span>new ApiToken<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line9">line 9</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Members</h3>
<h4 class="name" id="apiTokenId"><span class="type-signature"></span>apiTokenId<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line18">line 18</a>
</li></ul></dd>
</dl>
<h4 class="name" id="token"><span class="type-signature"></span>token<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line20">line 20</a>
</li></ul></dd>
</dl>
<h4 class="name" id="utcDateCreated"><span class="type-signature"></span>utcDateCreated<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line22">line 22</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -1020,9 +1020,7 @@ and relation (representing named relationship between source and target note)</d
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -614,7 +614,7 @@
<td class="type">
<span class="param-type">module:sql</span>
<span class="param-type"><a href="module-sql.html">module:sql</a></span>
@@ -663,7 +663,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line407">line 407</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line417">line 417</a>
</li></ul></dd>
@@ -1783,7 +1783,7 @@ JSON MIME type. See also createNewNote() for more options.
<div class="description">
If there's a branch between note and parent note, remove it. Otherwise do nothing.
If there's a branch between note and parent note, remove it. Otherwise, do nothing.
</div>
@@ -1961,7 +1961,7 @@ JSON MIME type. See also createNewNote() for more options.
<div class="description">
If there's no branch between note and parent note, create one. Otherwise do nothing.
If there's no branch between note and parent note, create one. Otherwise, do nothing.
</div>
@@ -2059,7 +2059,7 @@ JSON MIME type. See also createNewNote() for more options.
<td class="description last">if branch will be create between note and parent note, set this prefix</td>
<td class="description last">if branch will be created between note and parent note, set this prefix</td>
</tr>
@@ -2251,7 +2251,7 @@ JSON MIME type. See also createNewNote() for more options.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line395">line 395</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line405">line 405</a>
</li></ul></dd>
@@ -2357,7 +2357,7 @@ JSON MIME type. See also createNewNote() for more options.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line418">line 418</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line428">line 428</a>
</li></ul></dd>
@@ -2815,6 +2815,8 @@ JSON MIME type. See also createNewNote() for more options.
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>use getDayNote instead</li></ul></dd>
@@ -2827,7 +2829,165 @@ JSON MIME type. See also createNewNote() for more options.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line313">line 313</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line314">line 314</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type"><a href="Note.html">Note</a></span>
|
<span class="param-type">null</span>
</dd>
</dl>
<h4 class="name" id="getDayNote"><span class="type-signature"></span>getDayNote<span class="signature">(date)</span><span class="type-signature"> &rarr; {<a href="Note.html">Note</a>|null}</span></h4>
<div class="description">
Returns day note for given date. If such note doesn't exist, it is created.
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>date</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">in YYYY-MM-DD format</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line323">line 323</a>
</li></ul></dd>
@@ -3095,7 +3255,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line340">line 340</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line350">line 350</a>
</li></ul></dd>
@@ -3866,7 +4026,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line321">line 321</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line331">line 331</a>
</li></ul></dd>
@@ -4047,7 +4207,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line331">line 331</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line341">line 341</a>
</li></ul></dd>
@@ -4205,7 +4365,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line349">line 349</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line359">line 359</a>
</li></ul></dd>
@@ -4495,7 +4655,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line388">line 388</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line398">line 398</a>
</li></ul></dd>
@@ -4603,7 +4763,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line413">line 413</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line423">line 423</a>
</li></ul></dd>
@@ -5195,7 +5355,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line369">line 369</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line379">line 379</a>
</li></ul></dd>
@@ -5328,7 +5488,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line355">line 355</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line365">line 365</a>
</li></ul></dd>
@@ -5690,7 +5850,7 @@ exists, then we'll use that transaction.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line379">line 379</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line389">line 389</a>
</li></ul></dd>
@@ -5845,7 +6005,7 @@ exists, then we'll use that transaction.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line402">line 402</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line412">line 412</a>
</li></ul></dd>
@@ -5913,9 +6073,7 @@ exists, then we'll use that transaction.
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -752,9 +752,7 @@ parents.</div>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -0,0 +1,588 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Class: EtapiToken</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Class: EtapiToken</h1>
<section>
<header>
<h2><span class="attribs"><span class="type-signature"></span></span>EtapiToken<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description">EtapiToken is an entity representing token used to authenticate against Trilium REST API from client applications.
Used by:
- Trilium Sender
- ETAPI clients
The format user is presented with is "<etapiTokenId>_<tokenHash>". This is also called "authToken" to distinguish it
from tokenHash and token.</div>
</header>
<article>
<div class="container-overview">
<h2>Constructor</h2>
<h4 class="name" id="EtapiToken"><span class="type-signature"></span>new EtapiToken<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line16">line 16</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Members</h3>
<h4 class="name" id="etapiTokenId"><span class="type-signature"></span>etapiTokenId<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line34">line 34</a>
</li></ul></dd>
</dl>
<h4 class="name" id="isDeleted"><span class="type-signature"></span>isDeleted<span class="type-signature"> :boolean</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">boolean</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line44">line 44</a>
</li></ul></dd>
</dl>
<h4 class="name" id="name"><span class="type-signature"></span>name<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line36">line 36</a>
</li></ul></dd>
</dl>
<h4 class="name" id="tokenHash"><span class="type-signature"></span>tokenHash<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line38">line 38</a>
</li></ul></dd>
</dl>
<h4 class="name" id="utcDateCreated"><span class="type-signature"></span>utcDateCreated<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line40">line 40</a>
</li></ul></dd>
</dl>
<h4 class="name" id="utcDateModified"><span class="type-signature"></span>utcDateModified<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_etapi_token.js.html">becca/entities/etapi_token.js</a>, <a href="becca_entities_etapi_token.js.html#line42">line 42</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -1517,7 +1517,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line398">line 398</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line402">line 402</a>
</li></ul></dd>
@@ -1619,7 +1619,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1014">line 1014</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1020">line 1020</a>
</li></ul></dd>
@@ -1721,7 +1721,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line936">line 936</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line942">line 942</a>
</li></ul></dd>
@@ -1827,7 +1827,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line858">line 858</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line862">line 862</a>
</li></ul></dd>
@@ -2001,7 +2001,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line516">line 516</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line520">line 520</a>
</li></ul></dd>
@@ -2201,7 +2201,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line329">line 329</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line333">line 333</a>
</li></ul></dd>
@@ -2379,7 +2379,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line527">line 527</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line531">line 531</a>
</li></ul></dd>
@@ -2490,7 +2490,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line143">line 143</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line147">line 147</a>
</li></ul></dd>
@@ -2592,7 +2592,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line163">line 163</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line167">line 167</a>
</li></ul></dd>
@@ -2694,7 +2694,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line153">line 153</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line157">line 157</a>
</li></ul></dd>
@@ -2796,7 +2796,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line177">line 177</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line181">line 181</a>
</li></ul></dd>
@@ -2898,7 +2898,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line211">line 211</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line215">line 215</a>
</li></ul></dd>
@@ -3006,7 +3006,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line653">line 653</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line657">line 657</a>
</li></ul></dd>
@@ -3112,7 +3112,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line222">line 222</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line226">line 226</a>
</li></ul></dd>
@@ -3263,7 +3263,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line458">line 458</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line462">line 462</a>
</li></ul></dd>
@@ -3433,7 +3433,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line548">line 548</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line552">line 552</a>
</li></ul></dd>
@@ -3588,7 +3588,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line482">line 482</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line486">line 486</a>
</li></ul></dd>
@@ -3758,7 +3758,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line556">line 556</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line560">line 560</a>
</li></ul></dd>
@@ -3864,7 +3864,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line622">line 622</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line626">line 626</a>
</li></ul></dd>
@@ -4066,7 +4066,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line597">line 597</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line601">line 601</a>
</li></ul></dd>
@@ -4244,7 +4244,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line538">line 538</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line542">line 542</a>
</li></ul></dd>
@@ -4402,7 +4402,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line464">line 464</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line468">line 468</a>
</li></ul></dd>
@@ -4572,7 +4572,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line564">line 564</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line568">line 568</a>
</li></ul></dd>
@@ -4727,7 +4727,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line488">line 488</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line492">line 492</a>
</li></ul></dd>
@@ -4897,7 +4897,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line572">line 572</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line576">line 576</a>
</li></ul></dd>
@@ -5052,7 +5052,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line476">line 476</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line480">line 480</a>
</li></ul></dd>
@@ -5222,7 +5222,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line588">line 588</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line592">line 592</a>
</li></ul></dd>
@@ -5377,7 +5377,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line500">line 500</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line504">line 504</a>
</li></ul></dd>
@@ -5486,7 +5486,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line135">line 135</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line139">line 139</a>
</li></ul></dd>
@@ -5588,7 +5588,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line148">line 148</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line152">line 152</a>
</li></ul></dd>
@@ -5739,7 +5739,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line470">line 470</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line474">line 474</a>
</li></ul></dd>
@@ -5909,7 +5909,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line580">line 580</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line584">line 584</a>
</li></ul></dd>
@@ -6064,7 +6064,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line494">line 494</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line498">line 498</a>
</li></ul></dd>
@@ -6173,7 +6173,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line308">line 308</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line312">line 312</a>
</li></ul></dd>
@@ -6282,7 +6282,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line801">line 801</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line805">line 805</a>
</li></ul></dd>
@@ -6384,7 +6384,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line780">line 780</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line784">line 784</a>
</li></ul></dd>
@@ -6486,7 +6486,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line749">line 749</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line753">line 753</a>
</li></ul></dd>
@@ -6588,7 +6588,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line898">line 898</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line904">line 904</a>
</li></ul></dd>
@@ -6695,7 +6695,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line882">line 882</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line888">line 888</a>
</li></ul></dd>
@@ -6797,7 +6797,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line158">line 158</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line162">line 162</a>
</li></ul></dd>
@@ -6948,7 +6948,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line434">line 434</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line438">line 438</a>
</li></ul></dd>
@@ -7126,7 +7126,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line507">line 507</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line511">line 511</a>
</li></ul></dd>
@@ -7281,7 +7281,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line440">line 440</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line444">line 444</a>
</li></ul></dd>
@@ -7436,7 +7436,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line452">line 452</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line456">line 456</a>
</li></ul></dd>
@@ -7591,7 +7591,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line446">line 446</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line450">line 450</a>
</li></ul></dd>
@@ -7741,7 +7741,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line957">line 957</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line963">line 963</a>
</li></ul></dd>
@@ -7847,7 +7847,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line297">line 297</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line301">line 301</a>
</li></ul></dd>
@@ -7953,7 +7953,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line289">line 289</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line293">line 293</a>
</li></ul></dd>
@@ -8059,7 +8059,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line284">line 284</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line288">line 288</a>
</li></ul></dd>
@@ -8165,7 +8165,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line279">line 279</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line283">line 283</a>
</li></ul></dd>
@@ -8271,7 +8271,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line303">line 303</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line307">line 307</a>
</li></ul></dd>
@@ -8504,7 +8504,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1001">line 1001</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1007">line 1007</a>
</li></ul></dd>
@@ -8684,7 +8684,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1092">line 1092</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1098">line 1098</a>
</li></ul></dd>
@@ -8864,7 +8864,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1100">line 1100</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1106">line 1106</a>
</li></ul></dd>
@@ -9075,7 +9075,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line970">line 970</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line976">line 976</a>
</li></ul></dd>
@@ -9255,7 +9255,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1076">line 1076</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1082">line 1082</a>
</li></ul></dd>
@@ -9415,7 +9415,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1084">line 1084</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1090">line 1090</a>
</li></ul></dd>
@@ -9657,7 +9657,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1043">line 1043</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1049">line 1049</a>
</li></ul></dd>
@@ -9868,7 +9868,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1059">line 1059</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1065">line 1065</a>
</li></ul></dd>
@@ -10079,7 +10079,7 @@ This method can be significantly faster than the getAttribute()
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1068">line 1068</a>
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1074">line 1074</a>
</li></ul></dd>
@@ -10125,9 +10125,7 @@ This method can be significantly faster than the getAttribute()
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -1290,9 +1290,7 @@ It's used for seamless note versioning.</div>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -431,9 +431,7 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -363,9 +363,7 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -1,87 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: becca/entities/api_token.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: becca/entities/api_token.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
/**
* ApiToken is an entity representing token used to authenticate against Trilium API from client applications. Currently used only by Trilium Sender.
*/
class ApiToken extends AbstractEntity {
static get entityName() { return "api_tokens"; }
static get primaryKeyName() { return "apiTokenId"; }
static get hashedProperties() { return ["apiTokenId", "token", "utcDateCreated"]; }
constructor(row) {
super();
/** @type {string} */
this.apiTokenId = row.apiTokenId;
/** @type {string} */
this.token = row.token;
/** @type {string} */
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
}
getPojo() {
return {
apiTokenId: this.apiTokenId,
token: this.token,
utcDateCreated: this.utcDateCreated
}
}
}
module.exports = ApiToken;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -28,10 +28,10 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const Note = require('./note.js');
const AbstractEntity = require("./abstract_entity.js");
const sql = require("../../services/sql.js");
const dateUtils = require("../../services/date_utils.js");
const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
const promotedAttributeDefinitionParser = require("../../services/promoted_attribute_definition_parser");
/**
@@ -79,7 +79,7 @@ class Attribute extends AbstractEntity {
/** @type {int} */
this.position = position;
/** @type {string} */
this.value = value;
this.value = value || "";
/** @type {boolean} */
this.isInheritable = !!isInheritable;
/** @type {string} */
@@ -245,9 +245,7 @@ module.exports = Attribute;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -28,10 +28,10 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const Note = require('./note.js');
const AbstractEntity = require("./abstract_entity.js");
const sql = require("../../services/sql.js");
const dateUtils = require("../../services/date_utils.js");
const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
/**
* Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple
@@ -193,9 +193,7 @@ module.exports = Branch;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: becca/entities/etapi_token.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: becca/entities/etapi_token.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql.js");
/**
* EtapiToken is an entity representing token used to authenticate against Trilium REST API from client applications.
* Used by:
* - Trilium Sender
* - ETAPI clients
*
* The format user is presented with is "&lt;etapiTokenId>_&lt;tokenHash>". This is also called "authToken" to distinguish it
* from tokenHash and token.
*/
class EtapiToken extends AbstractEntity {
static get entityName() { return "etapi_tokens"; }
static get primaryKeyName() { return "etapiTokenId"; }
static get hashedProperties() { return ["etapiTokenId", "name", "tokenHash", "utcDateCreated", "utcDateModified", "isDeleted"]; }
constructor(row) {
super();
if (!row) {
return;
}
this.updateFromRow(row);
this.init();
}
updateFromRow(row) {
/** @type {string} */
this.etapiTokenId = row.etapiTokenId;
/** @type {string} */
this.name = row.name;
/** @type {string} */
this.tokenHash = row.tokenHash;
/** @type {string} */
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
/** @type {string} */
this.utcDateModified = row.utcDateModified || this.utcDateCreated;
/** @type {boolean} */
this.isDeleted = !!row.isDeleted;
this.becca.etapiTokens[this.etapiTokenId] = this;
}
init() {
if (this.etapiTokenId) {
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
getPojo() {
return {
etapiTokenId: this.etapiTokenId,
name: this.name,
tokenHash: this.tokenHash,
utcDateCreated: this.utcDateCreated,
utcDateModified: this.utcDateModified,
isDeleted: this.isDeleted
}
}
beforeSaving() {
this.utcDateModified = dateUtils.utcNowDateTime();
super.beforeSaving();
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
module.exports = EtapiToken;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -34,8 +34,8 @@ const sql = require('../../services/sql');
const utils = require('../../services/utils');
const dateUtils = require('../../services/date_utils');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity.js");
const NoteRevision = require("./note_revision.js");
const AbstractEntity = require("./abstract_entity");
const NoteRevision = require("./note_revision");
const LABEL = 'label';
const RELATION = 'relation';
@@ -159,6 +159,10 @@ class Note extends AbstractEntity {
|| protectedSessionService.isProtectedSessionAvailable()
}
getTitleOrProtected() {
return this.isContentAvailable() ? this.title : '[protected]';
}
/** @returns {Branch[]} */
getParentBranches() {
return this.parentBranches;
@@ -889,11 +893,13 @@ class Note extends AbstractEntity {
this.ancestorCache = [];
for (const parent of this.parents) {
if (!noteIds.has(parent.noteId)) {
this.ancestorCache.push(parent);
noteIds.add(parent.noteId);
if (noteIds.has(parent.noteId)) {
continue;
}
this.ancestorCache.push(parent);
noteIds.add(parent.noteId);
for (const ancestorNote of parent.getAncestors()) {
if (!noteIds.has(ancestorNote.noteId)) {
this.ancestorCache.push(ancestorNote);
@@ -1008,7 +1014,7 @@ class Note extends AbstractEntity {
}
}
else {
const Attribute = require("./attribute.js");
const Attribute = require("./attribute");
new Attribute({
noteId: this.noteId,
@@ -1040,7 +1046,7 @@ class Note extends AbstractEntity {
* @return {Attribute}
*/
addAttribute(type, name, value = "", isInheritable = false, position = 1000) {
const Attribute = require("./attribute.js");
const Attribute = require("./attribute");
return new Attribute({
noteId: this.noteId,
@@ -1214,9 +1220,7 @@ module.exports = Note;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -32,9 +32,9 @@ const protectedSessionService = require('../../services/protected_session');
const utils = require('../../services/utils');
const sql = require('../../services/sql');
const dateUtils = require('../../services/date_utils');
const becca = require('../becca.js');
const becca = require('../becca');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity.js");
const AbstractEntity = require("./abstract_entity");
/**
* NoteRevision represents snapshot of note's title and content at some point in the past.
@@ -230,9 +230,7 @@ module.exports = NoteRevision;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -28,8 +28,8 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
/**
* Option represents name-value pair, either directly configurable by the user or some system property.
@@ -81,9 +81,7 @@ module.exports = Option;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -28,8 +28,8 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
/**
* RecentNote represents recently visited note.
@@ -69,9 +69,7 @@ module.exports = RecentNote;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -1083,9 +1083,7 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -50,9 +50,7 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

File diff suppressed because it is too large Load Diff

View File

@@ -162,18 +162,18 @@ function BackendScriptApi(currentNote, apiParams) {
this.getNoteWithLabel = attributeService.getNoteWithLabel;
/**
* If there's no branch between note and parent note, create one. Otherwise do nothing.
* If there's no branch between note and parent note, create one. Otherwise, do nothing.
*
* @method
* @param {string} noteId
* @param {string} parentNoteId
* @param {string} prefix - if branch will be create between note and parent note, set this prefix
* @param {string} prefix - if branch will be created between note and parent note, set this prefix
* @returns {void}
*/
this.ensureNoteIsPresentInParent = cloningService.ensureNoteIsPresentInParent;
/**
* If there's a branch between note and parent note, remove it. Otherwise do nothing.
* If there's a branch between note and parent note, remove it. Otherwise, do nothing.
*
* @method
* @param {string} noteId
@@ -337,8 +337,18 @@ function BackendScriptApi(currentNote, apiParams) {
* @method
* @param {string} date in YYYY-MM-DD format
* @returns {Note|null}
* @deprecated use getDayNote instead
*/
this.getDateNote = dateNoteService.getDateNote;
this.getDateNote = dateNoteService.getDayNote;
/**
* Returns day note for given date. If such note doesn't exist, it is created.
*
* @method
* @param {string} date in YYYY-MM-DD format
* @returns {Note|null}
*/
this.getDayNote = dateNoteService.getDayNote;
/**
* Returns today's day note. If such note doesn't exist, it is created.
@@ -457,9 +467,7 @@ module.exports = BackendScriptApi;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -30,8 +30,6 @@
/**
* @module sql
*
* TODO: some methods (like getValue()) could use raw rows
*/
const log = require('./log');
@@ -42,6 +40,8 @@ const cls = require('./cls');
const dbConnection = new Database(dataDir.DOCUMENT_PATH);
dbConnection.pragma('journal_mode = WAL');
const LOG_ALL_QUERIES = false;
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `SIGTERM`].forEach(eventType => {
process.on(eventType, () => {
if (dbConnection) {
@@ -163,6 +163,10 @@ function getRawRows(query, params = []) {
}
function iterateRows(query, params = []) {
if (LOG_ALL_QUERIES) {
console.log(query);
}
return stmt(query).iterate(params);
}
@@ -185,11 +189,11 @@ function execute(query, params = []) {
return wrap(query, s => s.run(params));
}
function executeWithoutTransaction(query, params = []) {
dbConnection.run(query, params);
}
function executeMany(query, params) {
if (LOG_ALL_QUERIES) {
console.log(query);
}
while (params.length > 0) {
const curParams = params.slice(0, Math.min(params.length, PARAM_LIMIT));
params = params.slice(curParams.length);
@@ -210,6 +214,10 @@ function executeMany(query, params) {
}
function executeScript(query) {
if (LOG_ALL_QUERIES) {
console.log(query);
}
return dbConnection.exec(query);
}
@@ -217,6 +225,10 @@ function wrap(query, func) {
const startTimestamp = Date.now();
let result;
if (LOG_ALL_QUERIES) {
console.log(query);
}
try {
result = func(stmt(query));
}
@@ -359,7 +371,6 @@ module.exports = {
* @param {object[]} [params] - array of params if needed
*/
execute,
executeWithoutTransaction,
executeMany,
executeScript,
transactional,
@@ -376,9 +387,7 @@ module.exports = {
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="sql%250A%250ATODO_%2520some%2520methods%2520(like%2520getValue())%2520could%2520use%2520raw%2520rowsmodule_.html">sql
TODO: some methods (like getValue()) could use raw rows</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">

View File

@@ -1928,7 +1928,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line447">line 447</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line457">line 457</a>
</li></ul></dd>
@@ -2831,7 +2831,164 @@
<div class="description">
Returns date-note. If it doesn't exist, it is automatically created.
Returns day note for a given date. If it doesn't exist, it is automatically created.
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>date</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">e.g. "2019-04-29"</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>use getDayNote instead</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line399">line 399</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">Promise.&lt;<a href="NoteShort.html">NoteShort</a>></span>
</dd>
</dl>
<h4 class="name" id="getDayNote"><span class="type-signature"></span>getDayNote<span class="signature">(date)</span><span class="type-signature"> &rarr; {Promise.&lt;<a href="NoteShort.html">NoteShort</a>>}</span></h4>
<div class="description">
Returns day note for a given date. If it doesn't exist, it is automatically created.
</div>
@@ -2924,7 +3081,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line398">line 398</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line408">line 408</a>
</li></ul></dd>
@@ -3186,7 +3343,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line416">line 416</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line426">line 426</a>
</li></ul></dd>
@@ -3711,7 +3868,7 @@ otherwise (by e.g. createNoteLink())
<div class="description">
Returns date-note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
Returns day note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
</div>
@@ -3804,7 +3961,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line407">line 407</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line417">line 417</a>
</li></ul></dd>
@@ -3959,7 +4116,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line425">line 425</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line435">line 435</a>
</li></ul></dd>
@@ -4845,7 +5002,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line474">line 474</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line484">line 484</a>
</li></ul></dd>
@@ -4999,7 +5156,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line465">line 465</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line475">line 475</a>
</li></ul></dd>
@@ -5940,7 +6097,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line434">line 434</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line444">line 444</a>
</li></ul></dd>
@@ -6457,7 +6614,7 @@ Typical use case is when new note has been created, we should wait until it is s
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line458">line 458</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line468">line 468</a>
</li></ul></dd>

View File

@@ -818,7 +818,7 @@ class NoteShort {
const parentNote = froca.notes[parentNoteId];
if (!parentNote) {
if (!parentNote || parentNote.type === 'search') {
continue;
}

View File

@@ -417,16 +417,26 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
this.getTodayNote = dateNotesService.getTodayNote;
/**
* Returns date-note. If it doesn't exist, it is automatically created.
* Returns day note for a given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise&lt;NoteShort>}
* @deprecated use getDayNote instead
*/
this.getDateNote = dateNotesService.getDayNote;
/**
* Returns day note for a given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise&lt;NoteShort>}
*/
this.getDateNote = dateNotesService.getDateNote;
this.getDayNote = dateNotesService.getDayNote;
/**
* Returns date-note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
* Returns day note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"

View File

@@ -0,0 +1,78 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
CodeMirror.defineOption("placeholder", "", function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
cm.on("blur", onBlur);
cm.on("change", onChange);
cm.on("swapDoc", onChange);
CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function() { onComposition(cm) })
onChange(cm);
} else if (!val && prev) {
cm.off("blur", onBlur);
cm.off("change", onChange);
cm.off("swapDoc", onChange);
CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose)
clearPlaceholder(cm);
var wrapper = cm.getWrapperElement();
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "");
}
if (val && !cm.hasFocus()) onBlur(cm);
});
function clearPlaceholder(cm) {
if (cm.state.placeholder) {
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder);
cm.state.placeholder = null;
}
}
function setPlaceholder(cm) {
clearPlaceholder(cm);
var elt = cm.state.placeholder = document.createElement("pre");
elt.style.cssText = "height: 0; overflow: visible";
elt.style.direction = cm.getOption("direction");
elt.className = "CodeMirror-placeholder CodeMirror-line-like";
var placeHolder = cm.getOption("placeholder")
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder)
elt.appendChild(placeHolder)
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild);
}
function onComposition(cm) {
setTimeout(function() {
var empty = false
if (cm.lineCount() == 1) {
var input = cm.getInputField()
empty = input.nodeName == "TEXTAREA" ? !cm.getLine(0).length
: !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent)
}
if (empty) setPlaceholder(cm)
else clearPlaceholder(cm)
}, 20)
}
function onBlur(cm) {
if (isEmpty(cm)) setPlaceholder(cm);
}
function onChange(cm) {
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm);
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : "");
if (empty) setPlaceholder(cm);
else clearPlaceholder(cm);
}
function isEmpty(cm) {
return (cm.lineCount() === 1) && (cm.getLine(0) === "");
}
});

1228
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.49.3",
"version": "0.50.3",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -26,10 +26,9 @@
"dependencies": {
"archiver": "5.3.0",
"async-mutex": "0.3.2",
"axios": "0.24.0",
"axios": "0.25.0",
"better-sqlite3": "7.4.5",
"body-parser": "1.19.1",
"chokidar": "3.5.2",
"chokidar": "3.5.3",
"cls-hooked": "4.2.2",
"commonmark": "0.30.0",
"cookie-parser": "1.4.6",
@@ -40,32 +39,32 @@
"electron-dl": "3.3.0",
"electron-find": "1.0.7",
"electron-window-state": "5.0.3",
"@electron/remote": "2.0.1",
"@electron/remote": "2.0.8",
"express": "4.17.2",
"express-partial-content": "^1.0.2",
"express-rate-limit": "5.5.1",
"express-partial-content": "1.0.2",
"express-rate-limit": "6.2.0",
"express-session": "1.17.2",
"fs-extra": "10.0.0",
"helmet": "4.6.0",
"helmet": "5.0.2",
"html": "1.0.0",
"html2plaintext": "2.1.4",
"http-proxy-agent": "5.0.0",
"https-proxy-agent": "5.0.0",
"image-type": "4.1.0",
"ini": "2.0.0",
"is-animated": "^2.0.1",
"is-animated": "2.0.2",
"is-svg": "4.3.2",
"jimp": "0.16.1",
"joplin-turndown-plugin-gfm": "1.0.12",
"jsdom": "19.0.0",
"mime-types": "2.1.34",
"multer": "1.4.4",
"node-abi": "3.5.0",
"normalize-strings": "^1.1.1",
"node-abi": "3.8.0",
"normalize-strings": "1.1.1",
"open": "8.4.0",
"portscanner": "2.2.0",
"rand-token": "1.0.1",
"request": "^2.88.2",
"request": "2.88.2",
"rimraf": "3.0.2",
"sanitize-filename": "1.6.3",
"sanitize-html": "2.6.1",
@@ -73,27 +72,27 @@
"semver": "7.3.5",
"serve-favicon": "2.5.0",
"session-file-store": "1.5.0",
"stream-throttle": "^0.1.3",
"stream-throttle": "0.1.3",
"striptags": "3.2.0",
"tmp": "^0.2.1",
"tmp": "0.2.1",
"turndown": "7.1.1",
"unescape": "1.0.1",
"ws": "8.4.0",
"ws": "8.4.2",
"yauzl": "2.10.0"
},
"devDependencies": {
"cross-env": "7.0.3",
"electron": "16.0.6",
"electron": "16.1.0",
"electron-builder": "22.14.5",
"electron-packager": "15.4.0",
"electron-rebuild": "3.2.5",
"electron-rebuild": "3.2.7",
"esm": "3.2.25",
"jasmine": "3.10.0",
"jsdoc": "3.6.7",
"jasmine": "4.0.2",
"jsdoc": "3.6.10",
"lorem-ipsum": "2.0.4",
"rcedit": "3.0.1",
"webpack": "5.65.0",
"webpack-cli": "4.9.1"
"webpack": "5.68.0",
"webpack-cli": "4.9.2"
},
"optionalDependencies": {
"electron-installer-debian": "3.1.0"

View File

@@ -1,4 +1,4 @@
const lex = require('../../src/services/search/services/lex.js');
const lex = require('../../src/services/search/services/lex');
describe("Lexer fulltext", () => {
it("simple lexing", () => {

View File

@@ -1,7 +1,7 @@
const Note = require('../../src/becca/entities/note.js');
const Branch = require('../../src/becca/entities/branch.js');
const Attribute = require('../../src/becca/entities/attribute.js');
const becca = require('../../src/becca/becca.js');
const Note = require('../../src/becca/entities/note');
const Branch = require('../../src/becca/entities/branch');
const Attribute = require('../../src/becca/entities/attribute');
const becca = require('../../src/becca/becca');
const randtoken = require('rand-token').generator({source: 'crypto'});
/** @returns {Note} */

View File

@@ -1,4 +1,4 @@
const handleParens = require('../../src/services/search/services/handle_parens.js');
const handleParens = require('../../src/services/search/services/handle_parens');
describe("Parens handler", () => {
it("handles parens", () => {

View File

@@ -1,5 +1,5 @@
const SearchContext = require("../../src/services/search/search_context.js");
const parse = require('../../src/services/search/services/parse.js');
const SearchContext = require("../../src/services/search/search_context");
const parse = require('../../src/services/search/services/parse');
function tokens(toks, cur = 0) {
return toks.map(arg => {

View File

@@ -1,10 +1,10 @@
const searchService = require('../../src/services/search/services/search.js');
const Note = require('../../src/becca/entities/note.js');
const Branch = require('../../src/becca/entities/branch.js');
const SearchContext = require('../../src/services/search/search_context.js');
const dateUtils = require('../../src/services/date_utils.js');
const becca = require('../../src/becca/becca.js');
const {NoteBuilder, findNoteByTitle, note} = require('./note_cache_mocking.js');
const searchService = require('../../src/services/search/services/search');
const Note = require('../../src/becca/entities/note');
const Branch = require('../../src/becca/entities/branch');
const SearchContext = require('../../src/services/search/search_context');
const dateUtils = require('../../src/services/date_utils');
const becca = require('../../src/becca/becca');
const {NoteBuilder, findNoteByTitle, note} = require('./note_cache_mocking');
describe("Search", () => {
let rootNote;

View File

@@ -1,7 +1,7 @@
const {note} = require('./note_cache_mocking.js');
const ValueExtractor = require('../../src/services/search/value_extractor.js');
const becca = require('../../src/becca/becca.js');
const SearchContext = require("../../src/services/search/search_context.js");
const {note} = require('./note_cache_mocking');
const ValueExtractor = require('../../src/services/search/value_extractor');
const becca = require('../../src/becca/becca');
const SearchContext = require("../../src/services/search/search_context");
const dsc = new SearchContext();

View File

@@ -3,7 +3,6 @@ const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const helmet = require('helmet');
const session = require('express-session');
const FileStore = require('session-file-store')(session);
@@ -11,7 +10,7 @@ const sessionSecret = require('./services/session_secret');
const dataDir = require('./services/data_dir');
const utils = require('./services/utils');
require('./services/handlers');
require('./becca/becca_loader.js');
require('./becca/becca_loader');
const app = express();
@@ -20,13 +19,14 @@ app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(helmet({
hidePoweredBy: false, // deactivated because electron 4.0 crashes on this right after startup
hidePoweredBy: false, // errors out in electron
contentSecurityPolicy: false
}));
app.use(bodyParser.text({limit: '500mb'}));
app.use(bodyParser.json({limit: '500mb'}));
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.text({limit: '500mb'}));
app.use(express.json({limit: '500mb'}));
app.use(express.raw({limit: '500mb'}));
app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/libraries', express.static(path.join(__dirname, '..', 'libraries')));

View File

@@ -1,6 +1,6 @@
"use strict";
const sql = require("../services/sql.js");
const sql = require("../services/sql");
const NoteSet = require("../services/search/note_set");
/**
@@ -24,6 +24,8 @@ class Becca {
this.attributeIndex = {};
/** @type {Object.<String, Option>} */
this.options = {};
/** @type {Object.<String, EtapiToken>} */
this.etapiTokens = {};
this.loaded = false;
}
@@ -64,10 +66,12 @@ class Becca {
this.dirtyNoteSetCache();
}
/** @returns {Note|null} */
getNote(noteId) {
return this.notes[noteId];
}
/** @returns {Note[]} */
getNotes(noteIds, ignoreMissing = false) {
const filteredNotes = [];
@@ -88,29 +92,44 @@ class Becca {
return filteredNotes;
}
/** @returns {Branch|null} */
getBranch(branchId) {
return this.branches[branchId];
}
/** @returns {Attribute|null} */
getAttribute(attributeId) {
return this.attributes[attributeId];
}
/** @returns {Branch|null} */
getBranchFromChildAndParent(childNoteId, parentNoteId) {
return this.childParentToBranch[`${childNoteId}-${parentNoteId}`];
}
/** @returns {NoteRevision|null} */
getNoteRevision(noteRevisionId) {
const row = sql.getRow("SELECT * FROM note_revisions WHERE noteRevisionId = ?", [noteRevisionId]);
const NoteRevision = require("./entities/note_revision.js"); // avoiding circular dependency problems
const NoteRevision = require("./entities/note_revision"); // avoiding circular dependency problems
return row ? new NoteRevision(row) : null;
}
/** @returns {Option|null} */
getOption(name) {
return this.options[name];
}
/** @returns {EtapiToken[]} */
getEtapiTokens() {
return Object.values(this.etapiTokens);
}
/** @returns {EtapiToken|null} */
getEtapiToken(etapiTokenId) {
return this.etapiTokens[etapiTokenId];
}
getEntity(entityName, entityId) {
if (!entityName || !entityId) {
return null;
@@ -130,17 +149,19 @@ class Becca {
return this[camelCaseEntityName][entityId];
}
/** @returns {RecentNote[]} */
getRecentNotesFromQuery(query, params = []) {
const rows = sql.getRows(query, params);
const RecentNote = require("./entities/recent_note.js"); // avoiding circular dependency problems
const RecentNote = require("./entities/recent_note"); // avoiding circular dependency problems
return rows.map(row => new RecentNote(row));
}
/** @returns {NoteRevision[]} */
getNoteRevisionsFromQuery(query, params = []) {
const rows = sql.getRows(query, params);
const NoteRevision = require("./entities/note_revision.js"); // avoiding circular dependency problems
const NoteRevision = require("./entities/note_revision"); // avoiding circular dependency problems
return rows.map(row => new NoteRevision(row));
}

View File

@@ -9,6 +9,7 @@ const Note = require('./entities/note');
const Branch = require('./entities/branch');
const Attribute = require('./entities/attribute');
const Option = require('./entities/option');
const EtapiToken = require("./entities/etapi_token");
const cls = require("../services/cls");
const entityConstructor = require("../becca/entity_constructor");
@@ -45,6 +46,10 @@ function load() {
new Option(row);
}
for (const row of sql.getRows(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
new EtapiToken(row);
}
for (const noteId in becca.notes) {
becca.notes[noteId].sortParents();
}
@@ -75,7 +80,7 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({entity
return;
}
if (["notes", "branches", "attributes"].includes(entityName)) {
if (["notes", "branches", "attributes", "etapi_tokens"].includes(entityName)) {
const EntityClass = entityConstructor.getEntityFromEntityName(entityName);
const primaryKeyName = EntityClass.primaryKeyName;
@@ -112,6 +117,8 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENT
branchDeleted(entityId);
} else if (entityName === 'attributes') {
attributeDeleted(entityId);
} else if (entityName === 'etapi_tokens') {
etapiTokenDeleted(entityId);
}
});
@@ -220,6 +227,10 @@ function noteReorderingUpdated(branchIdList) {
}
}
function etapiTokenDeleted(etapiTokenId) {
delete becca.etapiTokens[etapiTokenId];
}
eventService.subscribeBeccaLoader(eventService.ENTER_PROTECTED_SESSION, () => {
try {
becca.decryptProtectedNotes();

View File

@@ -71,14 +71,7 @@ function getNoteTitle(childNoteId, parentNoteId) {
return "[error fetching title]";
}
let title;
if (childNote.isProtected) {
title = protectedSessionService.isProtectedSessionAvailable() ? childNote.title : '[protected]';
}
else {
title = childNote.title;
}
const title = childNote.getTitleOrProtected();
const branch = parentNote ? becca.getBranchFromChildAndParent(childNote.noteId, parentNote.noteId) : null;

View File

@@ -6,6 +6,7 @@ const entityChangesService = require('../../services/entity_changes');
const eventService = require("../../services/events");
const dateUtils = require("../../services/date_utils");
const cls = require("../../services/cls");
const log = require("../../services/log");
let becca = null;
@@ -40,7 +41,7 @@ class AbstractEntity {
get becca() {
if (!becca) {
becca = require('../becca.js');
becca = require('../becca');
}
return becca;
@@ -103,15 +104,38 @@ class AbstractEntity {
const entityId = this[this.constructor.primaryKeyName];
const entityName = this.constructor.entityName;
this.utcDateModified = dateUtils.utcNowDateTime();
sql.execute(`UPDATE ${entityName} SET isDeleted = 1, deleteId = ?, utcDateModified = ?
WHERE ${this.constructor.primaryKeyName} = ?`,
[deleteId, dateUtils.utcNowDateTime(), entityId]);
[deleteId, this.utcDateModified, entityId]);
if (this.dateModified) {
this.dateModified = dateUtils.localNowDateTime();
sql.execute(`UPDATE ${entityName} SET dateModified = ? WHERE ${this.constructor.primaryKeyName} = ?`,
[dateUtils.localNowDateTime(), entityId]);
[this.dateModified, entityId]);
}
log.info(`Marking ${entityName} ${entityId} as deleted`);
this.addEntityChange(true);
eventService.emit(eventService.ENTITY_DELETED, { entityName, entityId, entity: this });
}
markAsDeletedSimple() {
const entityId = this[this.constructor.primaryKeyName];
const entityName = this.constructor.entityName;
this.utcDateModified = dateUtils.utcNowDateTime();
sql.execute(`UPDATE ${entityName} SET isDeleted = 1, utcDateModified = ?
WHERE ${this.constructor.primaryKeyName} = ?`,
[this.utcDateModified, entityId]);
log.info(`Marking ${entityName} ${entityId} as deleted`);
this.addEntityChange(true);
eventService.emit(eventService.ENTITY_DELETED, { entityName, entityId, entity: this });

View File

@@ -1,34 +0,0 @@
"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
/**
* ApiToken is an entity representing token used to authenticate against Trilium API from client applications. Currently used only by Trilium Sender.
*/
class ApiToken extends AbstractEntity {
static get entityName() { return "api_tokens"; }
static get primaryKeyName() { return "apiTokenId"; }
static get hashedProperties() { return ["apiTokenId", "token", "utcDateCreated"]; }
constructor(row) {
super();
/** @type {string} */
this.apiTokenId = row.apiTokenId;
/** @type {string} */
this.token = row.token;
/** @type {string} */
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
}
getPojo() {
return {
apiTokenId: this.apiTokenId,
token: this.token,
utcDateCreated: this.utcDateCreated
}
}
}
module.exports = ApiToken;

View File

@@ -1,9 +1,9 @@
"use strict";
const Note = require('./note.js');
const AbstractEntity = require("./abstract_entity.js");
const sql = require("../../services/sql.js");
const dateUtils = require("../../services/date_utils.js");
const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
const promotedAttributeDefinitionParser = require("../../services/promoted_attribute_definition_parser");
/**
@@ -51,7 +51,7 @@ class Attribute extends AbstractEntity {
/** @type {int} */
this.position = position;
/** @type {string} */
this.value = value;
this.value = value || "";
/** @type {boolean} */
this.isInheritable = !!isInheritable;
/** @type {string} */

View File

@@ -1,9 +1,9 @@
"use strict";
const Note = require('./note.js');
const AbstractEntity = require("./abstract_entity.js");
const sql = require("../../services/sql.js");
const dateUtils = require("../../services/date_utils.js");
const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
/**
* Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple

View File

@@ -0,0 +1,76 @@
"use strict";
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
/**
* EtapiToken is an entity representing token used to authenticate against Trilium REST API from client applications.
* Used by:
* - Trilium Sender
* - ETAPI clients
*
* The format user is presented with is "<etapiTokenId>_<tokenHash>". This is also called "authToken" to distinguish it
* from tokenHash and token.
*/
class EtapiToken extends AbstractEntity {
static get entityName() { return "etapi_tokens"; }
static get primaryKeyName() { return "etapiTokenId"; }
static get hashedProperties() { return ["etapiTokenId", "name", "tokenHash", "utcDateCreated", "utcDateModified", "isDeleted"]; }
constructor(row) {
super();
if (!row) {
return;
}
this.updateFromRow(row);
this.init();
}
updateFromRow(row) {
/** @type {string} */
this.etapiTokenId = row.etapiTokenId;
/** @type {string} */
this.name = row.name;
/** @type {string} */
this.tokenHash = row.tokenHash;
/** @type {string} */
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
/** @type {string} */
this.utcDateModified = row.utcDateModified || this.utcDateCreated;
/** @type {boolean} */
this.isDeleted = !!row.isDeleted;
if (this.etapiTokenId) {
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
init() {
if (this.etapiTokenId) {
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
getPojo() {
return {
etapiTokenId: this.etapiTokenId,
name: this.name,
tokenHash: this.tokenHash,
utcDateCreated: this.utcDateCreated,
utcDateModified: this.utcDateModified,
isDeleted: this.isDeleted
}
}
beforeSaving() {
this.utcDateModified = dateUtils.utcNowDateTime();
super.beforeSaving();
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
module.exports = EtapiToken;

View File

@@ -6,8 +6,8 @@ const sql = require('../../services/sql');
const utils = require('../../services/utils');
const dateUtils = require('../../services/date_utils');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity.js");
const NoteRevision = require("./note_revision.js");
const AbstractEntity = require("./abstract_entity");
const NoteRevision = require("./note_revision");
const LABEL = 'label';
const RELATION = 'relation';
@@ -131,6 +131,10 @@ class Note extends AbstractEntity {
|| protectedSessionService.isProtectedSessionAvailable()
}
getTitleOrProtected() {
return this.isContentAvailable() ? this.title : '[protected]';
}
/** @returns {Branch[]} */
getParentBranches() {
return this.parentBranches;
@@ -861,11 +865,13 @@ class Note extends AbstractEntity {
this.ancestorCache = [];
for (const parent of this.parents) {
if (!noteIds.has(parent.noteId)) {
this.ancestorCache.push(parent);
noteIds.add(parent.noteId);
if (noteIds.has(parent.noteId)) {
continue;
}
this.ancestorCache.push(parent);
noteIds.add(parent.noteId);
for (const ancestorNote of parent.getAncestors()) {
if (!noteIds.has(ancestorNote.noteId)) {
this.ancestorCache.push(ancestorNote);
@@ -980,7 +986,7 @@ class Note extends AbstractEntity {
}
}
else {
const Attribute = require("./attribute.js");
const Attribute = require("./attribute");
new Attribute({
noteId: this.noteId,
@@ -1012,7 +1018,7 @@ class Note extends AbstractEntity {
* @return {Attribute}
*/
addAttribute(type, name, value = "", isInheritable = false, position = 1000) {
const Attribute = require("./attribute.js");
const Attribute = require("./attribute");
return new Attribute({
noteId: this.noteId,
@@ -1121,6 +1127,7 @@ class Note extends AbstractEntity {
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
try {
this.title = protectedSessionService.decryptString(this.title);
this.flatTextCache = null;
this.isDecrypted = true;
}

View File

@@ -4,9 +4,9 @@ const protectedSessionService = require('../../services/protected_session');
const utils = require('../../services/utils');
const sql = require('../../services/sql');
const dateUtils = require('../../services/date_utils');
const becca = require('../becca.js');
const becca = require('../becca');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity.js");
const AbstractEntity = require("./abstract_entity");
/**
* NoteRevision represents snapshot of note's title and content at some point in the past.

View File

@@ -1,7 +1,7 @@
"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
/**
* Option represents name-value pair, either directly configurable by the user or some system property.

View File

@@ -1,7 +1,7 @@
"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
/**
* RecentNote represents recently visited note.

View File

@@ -3,7 +3,7 @@ const NoteRevision = require('./entities/note_revision');
const Branch = require('./entities/branch');
const Attribute = require('./entities/attribute');
const RecentNote = require('./entities/recent_note');
const ApiToken = require('./entities/api_token');
const EtapiToken = require('./entities/etapi_token');
const Option = require('./entities/option');
const ENTITY_NAME_TO_ENTITY = {
@@ -14,7 +14,7 @@ const ENTITY_NAME_TO_ENTITY = {
"note_revisions": NoteRevision,
"note_revision_contents": NoteRevision,
"recent_notes": RecentNote,
"api_tokens": ApiToken,
"etapi_tokens": EtapiToken,
"options": Option
};

View File

@@ -1,4 +1,4 @@
const becca = require('./becca.js');
const becca = require('./becca');
const log = require('../services/log');
const beccaService = require('./becca_service.js');
const dateUtils = require('../services/date_utils');

75
src/etapi/attributes.js Normal file
View File

@@ -0,0 +1,75 @@
const becca = require("../becca/becca");
const eu = require("./etapi_utils");
const mappers = require("./mappers");
const attributeService = require("../services/attributes");
const v = require("./validators");
function register(router) {
eu.route(router, 'get', '/etapi/attributes/:attributeId', (req, res, next) => {
const attribute = eu.getAndCheckAttribute(req.params.attributeId);
res.json(mappers.mapAttributeToPojo(attribute));
});
const ALLOWED_PROPERTIES_FOR_CREATE_ATTRIBUTE = {
'attributeId': [v.mandatory, v.notNull, v.isValidEntityId],
'noteId': [v.mandatory, v.notNull, v.isNoteId],
'type': [v.mandatory, v.notNull, v.isAttributeType],
'name': [v.mandatory, v.notNull, v.isString],
'value': [v.notNull, v.isString],
'isInheritable': [v.notNull, v.isBoolean]
};
eu.route(router, 'post' ,'/etapi/attributes', (req, res, next) => {
if (req.body.type === 'relation') {
eu.getAndCheckNote(req.body.value);
}
const params = {};
eu.validateAndPatch(params, req.body, ALLOWED_PROPERTIES_FOR_CREATE_ATTRIBUTE);
try {
const attr = attributeService.createAttribute(params);
res.status(201).json(mappers.mapAttributeToPojo(attr));
}
catch (e) {
throw new eu.EtapiError(500, eu.GENERIC_CODE, e.message);
}
});
const ALLOWED_PROPERTIES_FOR_PATCH = {
'value': [v.notNull, v.isString]
};
eu.route(router, 'patch' ,'/etapi/attributes/:attributeId', (req, res, next) => {
const attribute = eu.getAndCheckAttribute(req.params.attributeId);
if (attribute.type === 'relation') {
eu.getAndCheckNote(req.body.value);
}
eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH);
attribute.save();
res.json(mappers.mapAttributeToPojo(attribute));
});
eu.route(router, 'delete' ,'/etapi/attributes/:attributeId', (req, res, next) => {
const attribute = becca.getAttribute(req.params.attributeId);
if (!attribute || attribute.isDeleted) {
return res.sendStatus(204);
}
attribute.markAsDeleted();
res.sendStatus(204);
});
}
module.exports = {
register
};

43
src/etapi/auth.js Normal file
View File

@@ -0,0 +1,43 @@
const becca = require("../becca/becca");
const eu = require("./etapi_utils");
const passwordEncryptionService = require("../services/password_encryption");
const etapiTokenService = require("../services/etapi_tokens");
function register(router) {
eu.NOT_AUTHENTICATED_ROUTE(router, 'post', '/etapi/auth/login', (req, res, next) => {
const {password, tokenName} = req.body;
if (!passwordEncryptionService.verifyPassword(password)) {
throw new eu.EtapiError(401, "WRONG_PASSWORD", "Wrong password.");
}
const {authToken} = etapiTokenService.createToken(tokenName || "ETAPI login");
res.status(201).json({
authToken
});
});
eu.route(router, 'post', '/etapi/auth/logout', (req, res, next) => {
const parsed = etapiTokenService.parseAuthToken(req.headers.authorization);
if (!parsed || !parsed.etapiTokenId) {
throw new eu.EtapiError(400, eu.GENERIC_CODE, "Cannot logout this token.");
}
const etapiToken = becca.getEtapiToken(parsed.etapiTokenId);
if (!etapiToken) {
// shouldn't happen since this already passed auth validation
throw new Error(`Cannot find the token ${parsed.etapiTokenId}.`);
}
etapiToken.markAsDeletedSimple();
res.sendStatus(204);
});
}
module.exports = {
register
}

90
src/etapi/branches.js Normal file
View File

@@ -0,0 +1,90 @@
const becca = require("../becca/becca");
const eu = require("./etapi_utils");
const mappers = require("./mappers");
const Branch = require("../becca/entities/branch");
const noteService = require("../services/notes");
const TaskContext = require("../services/task_context");
const entityChangesService = require("../services/entity_changes");
const v = require("./validators");
function register(router) {
eu.route(router, 'get', '/etapi/branches/:branchId', (req, res, next) => {
const branch = eu.getAndCheckBranch(req.params.branchId);
res.json(mappers.mapBranchToPojo(branch));
});
const ALLOWED_PROPERTIES_FOR_CREATE_BRANCH = {
'branchId': [v.mandatory, v.notNull, v.isValidEntityId],
'noteId': [v.mandatory, v.notNull, v.isNoteId],
'parentNoteId': [v.mandatory, v.notNull, v.isNoteId],
'notePosition': [v.notNull, v.isInteger],
'prefix': [v.isString],
'isExpanded': [v.notNull, v.isBoolean]
};
eu.route(router, 'post' ,'/etapi/branches', (req, res, next) => {
const params = {};
eu.validateAndPatch(params, req.body, ALLOWED_PROPERTIES_FOR_CREATE_BRANCH);
const existing = becca.getBranchFromChildAndParent(params.noteId, params.parentNoteId);
if (existing) {
existing.notePosition = params.notePosition;
existing.prefix = params.prefix;
existing.isExpanded = params.isExpanded;
existing.save();
return res.status(200).json(mappers.mapBranchToPojo(existing));
}
try {
const branch = new Branch(params).save();
res.status(201).json(mappers.mapBranchToPojo(branch));
}
catch (e) {
throw new eu.EtapiError(400, eu.GENERIC_CODE, e.message);
}
});
const ALLOWED_PROPERTIES_FOR_PATCH = {
'notePosition': [v.notNull, v.isInteger],
'prefix': [v.isString],
'isExpanded': [v.notNull, v.isBoolean]
};
eu.route(router, 'patch' ,'/etapi/branches/:branchId', (req, res, next) => {
const branch = eu.getAndCheckBranch(req.params.branchId);
eu.validateAndPatch(branch, req.body, ALLOWED_PROPERTIES_FOR_PATCH);
branch.save();
res.json(mappers.mapBranchToPojo(branch));
});
eu.route(router, 'delete' ,'/etapi/branches/:branchId', (req, res, next) => {
const branch = becca.getBranch(req.params.branchId);
if (!branch || branch.isDeleted) {
return res.sendStatus(204);
}
noteService.deleteBranch(branch, null, new TaskContext('no-progress-reporting'));
res.sendStatus(204);
});
eu.route(router, 'post' ,'/etapi/refresh-note-ordering/:parentNoteId', (req, res, next) => {
eu.getAndCheckNote(req.params.parentNoteId);
entityChangesService.addNoteReorderingEntityChange(req.params.parentNoteId, "etapi");
res.sendStatus(204);
});
}
module.exports = {
register
};

View File

@@ -0,0 +1,799 @@
openapi: "3.0.3"
info:
version: 1.0.0
title: ETAPI
description: External Trilium API
contact:
name: zadam
email: zadam.apps@gmail.com
url: https://github.com/zadam/trilium
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
- url: http://localhost:37740/etapi
- url: http://localhost:8080/etapi
security:
- EtapiTokenAuth: []
paths:
/create-note:
post:
description: Create a note and place it into the note tree
operationId: createNote
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateNoteDef'
responses:
'201':
description: note created
content:
application/json:
schema:
properties:
note:
$ref: '#/components/schemas/Note'
description: Created note
branch:
$ref: '#/components/schemas/Branch'
description: Created branch
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/notes:
get:
description: Search notes
operationId: searchNotes
parameters:
- name: search
in: query
required: true
description: search query string as described in https://github.com/zadam/trilium/wiki/Search
schema:
type: string
examples:
fulltext:
summary: Fulltext search for keywords (not exact match)
value: 'towers tolkien'
fulltextExactMatch:
summary: Fulltext search for exact match (notice the double quotes)
value: '"Two Towers"'
fulltextWithLabel:
summary: Fulltext search for keyword AND matching label
value: 'towers #book'
- name: fastSearch
in: query
required: false
description: enable fast search (fulltext doesn't look into content)
schema:
type: boolean
default: false
- name: includeArchivedNotes
in: query
required: false
description: search by default ignores archived notes. Set to 'true' to includes archived notes into search results.
schema:
type: boolean
default: false
- name: ancestorNoteId
in: query
required: false
description: search only in a subtree identified by the subtree noteId. By default whole tree is searched.
schema:
$ref: '#/components/schemas/EntityId'
- name: ancestorDepth
in: query
required: false
description: define how deep in the tree should the notes be searched
schema:
type: string
examples:
directChildren:
summary: depth of exactly 1 (direct children) to the ancestor (root if not set)
value: eq1
grandGrandChildren:
summary: depth of exactly 3 to the ancestor (root if not set)
value: eq3
lessThan4:
summary: depth less than 4 (so 1, 2, 3) to the ancestor (root if not set)
value: lt4
greaterThan2:
summary: depth greater than 2 (so 3, 4, 5, 6...) to the ancestor (root if not set)
value: gt4
- name: orderBy
in: query
required: false
description: name of the property/label to order search results by
schema:
type: string
example:
- title
- '#publicationDate'
- isProtected
- isArchived
- dateCreated
- dateModified
- utcDateCreated
- utcDateModified
- parentCount
- childrenCount
- attributeCount
- labelCount
- ownedLabelCount
- relationCount
- ownedRelationCount
- relationCountIncludingLinks
- ownedRelationCountIncludingLinks
- targetRelationCount
- targetRelationCountIncludingLinks
- contentSize
- noteSize
- revisionCount
- name: orderDirection
in: query
required: false
description: order direction, ascending or descending
schema:
type: string
default: asc
enum:
- asc
- desc
- name: limit
in: query
required: false
description: limit the number of results you want to receive
schema:
type: integer
example: 10
- name: debug
in: query
required: false
description: set to true to get debug information in the response (search query parsing)
schema:
type: boolean
default: false
responses:
'200':
description: search response
content:
application/json:
schema:
$ref: '#/components/schemas/SearchResponse'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/notes/{noteId}:
parameters:
- name: noteId
in: path
required: true
schema:
$ref: '#/components/schemas/EntityId'
get:
description: Returns a note identified by its ID
operationId: getNoteById
responses:
'200':
description: note response
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
description: patch a note identified by the noteId with changes in the body
operationId: patchNoteById
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
responses:
'200':
description: note updated
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
description: deletes a single note based on the noteId supplied
operationId: deleteNoteById
responses:
'204':
description: note deleted
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/branches/{branchId}:
parameters:
- name: branchId
in: path
required: true
schema:
$ref: '#/components/schemas/EntityId'
get:
description: Returns a branch identified by its ID
operationId: getBranchById
responses:
'200':
description: branch response
content:
application/json:
schema:
$ref: '#/components/schemas/Branch'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
description: >
Create a branch (clone a note to a different location in the tree).
In case there is a branch between parent note and child note already,
then this will update the existing branch with prefix, notePosition and isExpanded.
operationId: postBranch
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Branch'
responses:
'200':
description: branch updated (branch between parent note and child note already existed)
content:
application/json:
schema:
$ref: '#/components/schemas/Branch'
'201':
description: branch created
content:
application/json:
schema:
$ref: '#/components/schemas/Branch'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
description: patch a branch identified by the branchId with changes in the body
operationId: patchBranchById
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Branch'
responses:
'200':
description: branch updated
content:
application/json:
schema:
$ref: '#/components/schemas/Branch'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
description: >
deletes a branch based on the branchId supplied. If this is the last branch of the (child) note,
then the note is deleted as well.
operationId: deleteBranchById
responses:
'204':
description: branch deleted
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/attributes/{attributeId}:
parameters:
- name: attributeId
in: path
required: true
schema:
$ref: '#/components/schemas/EntityId'
get:
description: Returns an attribute identified by its ID
operationId: getAttributeById
responses:
'200':
description: attribute response
content:
application/json:
schema:
$ref: '#/components/schemas/Attribute'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
description: create an attribute for a given note
operationId: postAttribute
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Attribute'
responses:
'201':
description: attribute created
content:
application/json:
schema:
$ref: '#/components/schemas/Attribute'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
patch:
description: patch a attribute identified by the attributeId with changes in the body
operationId: patchAttributeById
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Attribute'
responses:
'200':
description: attribute updated
content:
application/json:
schema:
$ref: '#/components/schemas/Attribute'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
description: deletes a attribute based on the attributeId supplied.
operationId: deleteAttributeById
responses:
'204':
description: attribute deleted
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/refresh-note-ordering/{parentNoteId}:
parameters:
- name: parentNoteId
in: path
required: true
schema:
$ref: '#/components/schemas/EntityId'
post:
description: >
notePositions in branches are not automatically pushed to connected clients and need a specific instruction.
If you want your changes to be in effect immediately, call this service after setting branches' notePosition.
Note that you need to supply "parentNoteId" of branch(es) with changed positions.
operationId: postRefreshNoteOrdering
responses:
'204':
description: note ordering will be asynchronously updated in all connected clients
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/inbox/{date}:
get:
description: >
returns an "inbox" note, into which note can be created. Date will be used depending on whether the inbox
is a fixed note (identified with #inbox label) or a day note in a journal.
operationId: getInboxNote
parameters:
- name: date
in: path
required: true
schema:
type: string
format: date
example: 2022-02-22
responses:
'200':
description: inbox note
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/calendar/days/{date}:
get:
description: returns a day note for a given date. Gets created if doesn't exist.
operationId: getDayNote
parameters:
- name: date
in: path
required: true
schema:
type: string
format: date
example: 2022-02-22
responses:
'200':
description: day note
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/calendar/weeks/{date}:
get:
description: returns a week note for a given date. Gets created if doesn't exist.
operationId: getWeekNote
parameters:
- name: date
in: path
required: true
schema:
type: string
format: date
example: 2022-02-22
responses:
'200':
description: week note
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/calendar/months/{month}:
get:
description: returns a week note for a given date. Gets created if doesn't exist.
operationId: getMonthNote
parameters:
- name: month
in: path
required: true
schema:
type: string
pattern: '[0-9]{4}-[0-9]{2}'
example: 2022-02
responses:
'200':
description: month note
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/calendar/years/{year}:
get:
description: returns a week note for a given date. Gets created if doesn't exist.
operationId: getYearNote
parameters:
- name: year
in: path
required: true
schema:
type: string
pattern: '[0-9]{4}-[0-9]{2}'
example: 2022-02
responses:
'200':
description: year note
content:
application/json:
schema:
$ref: '#/components/schemas/Note'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/auth/login:
post:
description: get an ETAPI token based on password for further use with ETAPI
operationId: login
security: [] # no token based auth for login endpoint
requestBody:
required: true
content:
application/json:
schema:
properties:
password:
type: string
description: user's password used to e.g. login to Trilium server and/or protect notes
responses:
'201':
description: auth token
content:
application/json:
schema:
properties:
authToken:
type: string
example: Bc4bFn0Ffiok_4NpbVCDnFz7B2WU+pdhW8B5Ne3DiR5wXrEyqdjgRIsk=
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/auth/logout:
post:
description: logout (delete/deactivate) an ETAPI token
operationId: logout
responses:
'204':
description: logout successful
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
securitySchemes:
EtapiTokenAuth:
type: apiKey
in: header
name: Authorization
schemas:
CreateNoteDef:
type: object
required:
- parentNoteId
- title
- type
- content
properties:
parentNoteId:
$ref: '#/components/schemas/EntityId'
description: Note ID of the parent note in the tree
title:
type: string
type:
type: string
enum:
- text
- code
- file
- image
- search
- book
- relation-map
- render
mime:
type: string
description: this needs to be specified only for note types 'code', 'file', 'image'.
example: application/json
content:
type: string
notePosition:
type: integer
description: >
Position of the note in the parent. Normal ordering is 10, 20, 30 ...
So if you want to create a note on the first position, use e.g. 5, for second position 15, for last e.g. 1000000
prefix:
type: string
description: >
Prefix is branch (placement) specific title prefix for the note.
Let's say you have your note placed into two different places in the tree,
but you want to change the title a bit in one of the placements. For this you can use prefix.
isExpanded:
type: boolean
description: true if this note (as a folder) should appear expanded
noteId:
$ref: '#/components/schemas/EntityId'
description: DON'T specify unless you want to force a specific noteId
branchId:
$ref: '#/components/schemas/EntityId'
description: DON'T specify unless you want to force a specific branchId
Note:
type: object
properties:
noteId:
$ref: '#/components/schemas/EntityId'
readOnly: true
title:
type: string
type:
type: string
enum: [text, code, render, file, image, search, relation-map, book, note-map, mermaid]
mime:
type: string
isProtected:
type: boolean
readOnly: true
attributes:
$ref: '#/components/schemas/AttributeList'
readOnly: true
parentNoteIds:
$ref: '#/components/schemas/EntityIdList'
readOnly: true
childNoteIds:
$ref: '#/components/schemas/EntityIdList'
readOnly: true
parentBranchIds:
$ref: '#/components/schemas/EntityIdList'
readOnly: true
childBranchIds:
$ref: '#/components/schemas/EntityIdList'
readOnly: true
dateCreated:
$ref: '#/components/schemas/LocalDateTime'
readOnly: true
dateModified:
$ref: '#/components/schemas/LocalDateTime'
readOnly: true
utcDateCreated:
$ref: '#/components/schemas/UtcDateTime'
readOnly: true
utcDateModified:
$ref: '#/components/schemas/UtcDateTime'
readOnly: true
Branch:
type: object
description: Branch places the note into the tree, it represents the relationship between a parent note and child note
required:
- noteId
- parentNoteId
properties:
branchId:
$ref: '#/components/schemas/EntityId'
noteId:
$ref: '#/components/schemas/EntityId'
readOnly: true
description: identifies the child note
parentNoteId:
$ref: '#/components/schemas/EntityId'
readOnly: true
description: identifies the parent note
prefix:
type: string
notePosition:
type: integer
format: int32
isExpanded:
type: boolean
utcDateModified:
$ref: '#/components/schemas/UtcDateTime'
readOnly: true
Attribute:
type: object
description: Attribute (Label, Relation) is a key-value record attached to a note.
required:
- noteId
properties:
attributeId:
$ref: '#/components/schemas/EntityId'
noteId:
$ref: '#/components/schemas/EntityId'
readOnly: true
description: identifies the child note
type:
type: string
enum: [label, relation]
name:
type: string
pattern: '^[\p{L}\p{N}_:]+'
example: shareCss
value:
type: string
position:
type: integer
format: int32
isInheritable:
type: boolean
utcDateModified:
$ref: '#/components/schemas/UtcDateTime'
readOnly: true
AttributeList:
type: array
items:
$ref: '#/components/schemas/Attribute'
SearchResponse:
type: object
required:
- results
properties:
results:
type: array
items:
$ref: '#/components/schemas/Note'
debugInfo:
type: object
description: debugging info on parsing the search query enabled with &debug=true parameter
EntityId:
type: string
pattern: '[a-zA-Z0-9]{4,32}'
example: evnnmvHTCgIn
EntityIdList:
type: array
items:
$ref: '#/components/schemas/EntityId'
LocalDateTime:
type: string
pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}\+[0-9]{4}'
example: 2021-12-31 20:18:11.939+0100
UtcDateTime:
type: string
pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z'
example: 2021-12-31 19:18:11.939Z
Error:
type: object
required:
- status
- code
- message
properties:
status:
type: integer
format: int32
description: HTTP status, identical to the one given in HTTP response
example: 400
code:
type: string
description: stable string constant
example: NOTE_IS_PROTECTED
message:
type: string
description: Human readable error, potentially with more details,
example: Note 'evnnmvHTCgIn' is protected and cannot be modified through ETAPI

138
src/etapi/etapi_utils.js Normal file
View File

@@ -0,0 +1,138 @@
const cls = require("../services/cls");
const sql = require("../services/sql");
const log = require("../services/log");
const becca = require("../becca/becca");
const etapiTokenService = require("../services/etapi_tokens");
const config = require("../services/config");
const GENERIC_CODE = "GENERIC";
const noAuthentication = config.General && config.General.noAuthentication === true;
class EtapiError extends Error {
constructor(statusCode, code, message) {
super();
this.statusCode = statusCode;
this.code = code;
this.message = message;
}
}
function sendError(res, statusCode, code, message) {
return res
.set('Content-Type', 'application/json')
.status(statusCode)
.send(JSON.stringify({
"status": statusCode,
"code": code,
"message": message
}));
}
function checkEtapiAuth(req, res, next) {
if (noAuthentication || etapiTokenService.isValidAuthHeader(req.headers.authorization)) {
next();
}
else {
sendError(res, 401, "NOT_AUTHENTICATED", "Not authenticated");
}
}
function processRequest(req, res, routeHandler, next, method, path) {
try {
cls.namespace.bindEmitter(req);
cls.namespace.bindEmitter(res);
cls.init(() => {
cls.set('componentId', "etapi");
cls.set('localNowDateTime', req.headers['trilium-local-now-datetime']);
const cb = () => routeHandler(req, res, next);
return sql.transactional(cb);
});
} catch (e) {
log.error(`${method} ${path} threw exception ${e.message} with stacktrace: ${e.stack}`);
if (e instanceof EtapiError) {
sendError(res, e.statusCode, e.code, e.message);
} else {
sendError(res, 500, GENERIC_CODE, e.message);
}
}
}
function route(router, method, path, routeHandler) {
router[method](path, checkEtapiAuth, (req, res, next) => processRequest(req, res, routeHandler, next, method, path));
}
function NOT_AUTHENTICATED_ROUTE(router, method, path, routeHandler) {
router[method](path, (req, res, next) => processRequest(req, res, routeHandler, next, method, path));
}
function getAndCheckNote(noteId) {
const note = becca.getNote(noteId);
if (note) {
return note;
}
else {
throw new EtapiError(404, "NOTE_NOT_FOUND", `Note '${noteId}' not found`);
}
}
function getAndCheckBranch(branchId) {
const branch = becca.getBranch(branchId);
if (branch) {
return branch;
}
else {
throw new EtapiError(404, "BRANCH_NOT_FOUND", `Branch '${branchId}' not found`);
}
}
function getAndCheckAttribute(attributeId) {
const attribute = becca.getAttribute(attributeId);
if (attribute) {
return attribute;
}
else {
throw new EtapiError(404, "ATTRIBUTE_NOT_FOUND", `Attribute '${attributeId}' not found`);
}
}
function validateAndPatch(target, source, allowedProperties) {
for (const key of Object.keys(source)) {
if (!(key in allowedProperties)) {
throw new EtapiError(400, "PROPERTY_NOT_ALLOWED", `Property '${key}' is not allowed for PATCH.`);
}
else {
for (const validator of allowedProperties[key]) {
const validationResult = validator(source[key]);
if (validationResult) {
throw new EtapiError(400, "PROPERTY_VALIDATION_ERROR", `Validation failed on property '${key}': ${validationResult}`);
}
}
}
}
// validation passed, let's patch
for (const propName of Object.keys(source)) {
target[propName] = source[propName];
}
}
module.exports = {
EtapiError,
sendError,
route,
NOT_AUTHENTICATED_ROUTE,
GENERIC_CODE,
validateAndPatch,
getAndCheckNote,
getAndCheckBranch,
getAndCheckAttribute
}

49
src/etapi/mappers.js Normal file
View File

@@ -0,0 +1,49 @@
function mapNoteToPojo(note) {
return {
noteId: note.noteId,
isProtected: note.isProtected,
title: note.title,
type: note.type,
mime: note.mime,
dateCreated: note.dateCreated,
dateModified: note.dateModified,
utcDateCreated: note.utcDateCreated,
utcDateModified: note.utcDateModified,
parentNoteIds: note.getParentNotes().map(p => p.noteId),
childNoteIds: note.getChildNotes().map(ch => ch.noteId),
parentBranchIds: note.getParentBranches().map(p => p.branchId),
childBranchIds: note.getChildBranches().map(ch => ch.branchId),
attributes: note.getAttributes().map(attr => mapAttributeToPojo(attr))
};
}
function mapBranchToPojo(branch) {
return {
branchId: branch.branchId,
noteId: branch.noteId,
parentNoteId: branch.parentNoteId,
prefix: branch.prefix,
notePosition: branch.notePosition,
isExpanded: branch.isExpanded,
utcDateModified: branch.utcDateModified
};
}
function mapAttributeToPojo(attr) {
return {
attributeId: attr.attributeId,
noteId: attr.noteId,
type: attr.type,
name: attr.name,
value: attr.value,
position: attr.position,
isInheritable: attr.isInheritable,
utcDateModified: attr.utcDateModified
};
}
module.exports = {
mapNoteToPojo,
mapBranchToPojo,
mapAttributeToPojo
};

195
src/etapi/notes.js Normal file
View File

@@ -0,0 +1,195 @@
const becca = require("../becca/becca");
const utils = require("../services/utils");
const eu = require("./etapi_utils");
const mappers = require("./mappers");
const noteService = require("../services/notes");
const TaskContext = require("../services/task_context");
const v = require("./validators");
const searchService = require("../services/search/services/search");
const SearchContext = require("../services/search/search_context");
function register(router) {
eu.route(router, 'get', '/etapi/notes', (req, res, next) => {
const {search} = req.query;
if (!search?.trim()) {
throw new eu.EtapiError(400, 'SEARCH_QUERY_PARAM_MANDATORY', "'search' query parameter is mandatory");
}
const searchParams = parseSearchParams(req);
const searchContext = new SearchContext(searchParams);
const searchResults = searchService.findResultsWithQuery(search, searchContext);
const foundNotes = searchResults.map(sr => becca.notes[sr.noteId]);
const resp = {
results: foundNotes.map(note => mappers.mapNoteToPojo(note))
};
if (searchContext.debugInfo) {
resp.debugInfo = searchContext.debugInfo;
}
res.json(resp);
});
eu.route(router, 'get', '/etapi/notes/:noteId', (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
res.json(mappers.mapNoteToPojo(note));
});
const ALLOWED_PROPERTIES_FOR_CREATE_NOTE = {
'parentNoteId': [v.mandatory, v.notNull, v.isNoteId],
'title': [v.mandatory, v.notNull, v.isString],
'type': [v.mandatory, v.notNull, v.isNoteType],
'mime': [v.notNull, v.isString],
'content': [v.notNull, v.isString],
'notePosition': [v.notNull, v.isInteger],
'prefix': [v.notNull, v.isInteger],
'isExpanded': [v.notNull, v.isBoolean],
'noteId': [v.notNull, v.isValidEntityId],
'branchId': [v.notNull, v.isValidEntityId],
};
eu.route(router, 'post' ,'/etapi/create-note', (req, res, next) => {
const params = {};
eu.validateAndPatch(params, req.body, ALLOWED_PROPERTIES_FOR_CREATE_NOTE);
try {
const resp = noteService.createNewNote(params);
res.status(201).json({
note: mappers.mapNoteToPojo(resp.note),
branch: mappers.mapBranchToPojo(resp.branch)
});
}
catch (e) {
return eu.sendError(res, 500, eu.GENERIC_CODE, e.message);
}
});
const ALLOWED_PROPERTIES_FOR_PATCH = {
'title': [v.notNull, v.isString],
'type': [v.notNull, v.isString],
'mime': [v.notNull, v.isString]
};
eu.route(router, 'patch' ,'/etapi/notes/:noteId', (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId)
if (note.isProtected) {
throw new eu.EtapiError(400, "NOTE_IS_PROTECTED", `Note '${req.params.noteId}' is protected and cannot be modified through ETAPI`);
}
eu.validateAndPatch(note, req.body, ALLOWED_PROPERTIES_FOR_PATCH);
note.save();
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, 'delete' ,'/etapi/notes/:noteId', (req, res, next) => {
const {noteId} = req.params;
const note = becca.getNote(noteId);
if (!note || note.isDeleted) {
return res.sendStatus(204);
}
noteService.deleteNote(note, null, new TaskContext('no-progress-reporting'));
res.sendStatus(204);
});
eu.route(router, 'get', '/etapi/notes/:noteId/content', (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const filename = utils.formatDownloadTitle(note.title, note.type, note.mime);
res.setHeader('Content-Disposition', utils.getContentDisposition(filename));
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
res.setHeader('Content-Type', note.mime);
res.send(note.getContent());
});
eu.route(router, 'put', '/etapi/notes/:noteId/content', (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
note.setContent(req.body);
return res.sendStatus(204);
});
}
function parseSearchParams(req) {
const rawSearchParams = {
'fastSearch': parseBoolean(req.query, 'fastSearch'),
'includeArchivedNotes': parseBoolean(req.query, 'includeArchivedNotes'),
'ancestorNoteId': req.query['ancestorNoteId'],
'ancestorDepth': parseInteger(req.query, 'ancestorDepth'),
'orderBy': req.query['orderBy'],
'orderDirection': parseOrderDirection(req.query, 'orderDirection'),
'limit': parseInteger(req.query, 'limit'),
'debug': parseBoolean(req.query, 'debug')
};
const searchParams = {};
for (const paramName of Object.keys(rawSearchParams)) {
if (rawSearchParams[paramName] !== undefined) {
searchParams[paramName] = rawSearchParams[paramName];
}
}
return searchParams;
}
const SEARCH_PARAM_ERROR = "SEARCH_PARAM_VALIDATION_ERROR";
function parseBoolean(obj, name) {
if (!(name in obj)) {
return undefined;
}
if (!['true', 'false'].includes(obj[name])) {
throw new eu.EtapiError(400, SEARCH_PARAM_ERROR, `Cannot parse boolean '${name}' value '${obj[name]}, allowed values are 'true' and 'false'`);
}
return obj[name] === 'true';
}
function parseOrderDirection(obj, name) {
if (!(name in obj)) {
return undefined;
}
const integer = parseInt(obj[name]);
if (!['asc', 'desc'].includes(obj[name])) {
throw new eu.EtapiError(400, SEARCH_PARAM_ERROR, `Cannot parse order direction value '${obj[name]}, allowed values are 'asc' and 'desc'`);
}
return integer;
}
function parseInteger(obj, name) {
if (!(name in obj)) {
return undefined;
}
const integer = parseInt(obj[name]);
if (Number.isNaN(integer)) {
throw new eu.EtapiError(400, SEARCH_PARAM_ERROR, `Cannot parse integer '${name}' value '${obj[name]}`);
}
return integer;
}
module.exports = {
register
};

20
src/etapi/spec.js Normal file
View File

@@ -0,0 +1,20 @@
const fs = require('fs');
const path = require('path');
const specPath = path.join(__dirname, 'etapi.openapi.yaml');
let spec = null;
function register(router) {
router.get('/etapi/etapi.openapi.yaml', (req, res, next) => {
if (!spec) {
spec = fs.readFileSync(specPath, 'utf8');
}
res.header('Content-Type', 'text/plain'); // so that it displays in browser
res.status(200).send(spec);
});
}
module.exports = {
register
};

View File

@@ -0,0 +1,77 @@
const specialNotesService = require("../services/special_notes");
const dateNotesService = require("../services/date_notes");
const eu = require("./etapi_utils");
const mappers = require("./mappers");
const getDateInvalidError = date => new eu.EtapiError(400, "DATE_INVALID", `Date "${date}" is not valid.`);
const getMonthInvalidError = month => new eu.EtapiError(400, "MONTH_INVALID", `Month "${month}" is not valid.`);
const getYearInvalidError = year => new eu.EtapiError(400, "YEAR_INVALID", `Year "${year}" is not valid.`);
function isValidDate(date) {
if (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(date)) {
return false;
}
return !!Date.parse(date);
}
function register(router) {
eu.route(router, 'get', '/etapi/inbox/:date', (req, res, next) => {
const {date} = req.params;
if (!isValidDate(date)) {
throw getDateInvalidError(res, date);
}
const note = specialNotesService.getInboxNote(date);
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, 'get', '/etapi/calendar/days/:date', (req, res, next) => {
const {date} = req.params;
if (!isValidDate(date)) {
throw getDateInvalidError(res, date);
}
const note = dateNotesService.getDayNote(date);
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, 'get', '/etapi/calendar/weeks/:date', (req, res, next) => {
const {date} = req.params;
if (!isValidDate(date)) {
throw getDateInvalidError(res, date);
}
const note = dateNotesService.getWeekNote(date);
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, 'get', '/etapi/calendar/months/:month', (req, res, next) => {
const {month} = req.params;
if (!/[0-9]{4}-[0-9]{2}/.test(month)) {
throw getMonthInvalidError(res, month);
}
const note = dateNotesService.getMonthNote(month);
res.json(mappers.mapNoteToPojo(note));
});
eu.route(router, 'get', '/etapi/calendar/years/:year', (req, res, next) => {
const {year} = req.params;
if (!/[0-9]{4}/.test(year)) {
throw getYearInvalidError(res, year);
}
const note = dateNotesService.getYearNote(year);
res.json(mappers.mapNoteToPojo(note));
});
}
module.exports = {
register
};

101
src/etapi/validators.js Normal file
View File

@@ -0,0 +1,101 @@
const noteTypes = require("../services/note_types");
function mandatory(obj) {
if (obj === undefined ) {
return `mandatory, but not set`;
}
}
function notNull(obj) {
if (obj === null) {
return `cannot be null`;
}
}
function isString(obj) {
if (obj === undefined || obj === null) {
return;
}
if (typeof obj !== 'string') {
return `'${obj}' is not a string`;
}
}
function isBoolean(obj) {
if (obj === undefined || obj === null) {
return;
}
if (typeof obj !== 'boolean') {
return `'${obj}' is not a boolean`;
}
}
function isInteger(obj) {
if (obj === undefined || obj === null) {
return;
}
if (!Number.isInteger(obj)) {
return `'${obj}' is not an integer`;
}
}
function isNoteId(obj) {
if (obj === undefined || obj === null) {
return;
}
const becca = require('../becca/becca');
if (typeof obj !== 'string') {
return `'${obj}' is not a valid noteId`;
}
if (!(obj in becca.notes)) {
return `Note '${obj}' does not exist`;
}
}
function isNoteType(obj) {
if (obj === undefined || obj === null) {
return;
}
if (!noteTypes.includes(obj)) {
return `'${obj}' is not a valid note type, allowed types are: ` + noteTypes.join(", ");
}
}
function isAttributeType(obj) {
if (obj === undefined || obj === null) {
return;
}
if (!['label', 'relation'].includes(obj)) {
return `'${obj}' is not a valid attribute type, allowed types are: label, relation`;
}
}
function isValidEntityId(obj) {
if (obj === undefined || obj === null) {
return;
}
if (typeof obj !== 'string' || !/^[A-Za-z0-9]{4,32}$/.test(obj)) {
return `'${obj}' is not a valid entityId. Only alphanumeric characters are allowed of length 4 to 32.`;
}
}
module.exports = {
mandatory,
notNull,
isString,
isBoolean,
isInteger,
isNoteId,
isNoteType,
isAttributeType,
isValidEntityId
};

View File

@@ -5,7 +5,7 @@ import utils from "../services/utils.js";
const $dialog = $("#options-dialog");
export async function showDialog() {
export async function showDialog(openTab) {
const options = await server.get('options');
utils.openDialog($dialog);
@@ -14,7 +14,8 @@ export async function showDialog() {
import('./options/appearance.js'),
import('./options/shortcuts.js'),
import('./options/code_notes.js'),
import('./options/credentials.js'),
import('./options/password.js'),
import('./options/etapi.js'),
import('./options/backup.js'),
import('./options/sync.js'),
import('./options/other.js'),
@@ -26,4 +27,8 @@ export async function showDialog() {
tab.optionsLoaded(options)
}
});
if (openTab) {
$(`.nav-link[href='#options-${openTab}']`).trigger("click");
}
}

View File

@@ -13,6 +13,12 @@ const TPL = `
<br/>
<br/>
<h4>Database integrity check</h4>
<p>This will check that the database is not corrupted on the SQLite level. It might take some time, depending on the DB size.</p>
<button id="check-integrity-button" class="btn">Check database integrity</button><br/><br/>
<h4>Consistency checks</h4>
<button id="find-and-fix-consistency-issues-button" class="btn">Find and fix consistency issues</button><br/><br/>
@@ -37,9 +43,9 @@ export default class AdvancedOptions {
this.$forceFullSyncButton = $("#force-full-sync-button");
this.$fillEntityChangesButton = $("#fill-entity-changes-button");
this.$anonymizeButton = $("#anonymize-button");
this.$backupDatabaseButton = $("#backup-database-button");
this.$vacuumDatabaseButton = $("#vacuum-database-button");
this.$findAndFixConsistencyIssuesButton = $("#find-and-fix-consistency-issues-button");
this.$checkIntegrityButton = $("#check-integrity-button");
this.$forceFullSyncButton.on('click', async () => {
await server.post('sync/force-full-sync');
@@ -75,5 +81,16 @@ export default class AdvancedOptions {
toastService.showMessage("Consistency issues should be fixed.");
});
this.$checkIntegrityButton.on('click', async () => {
const {results} = await server.get('database/check-integrity');
if (results.length === 1 && results[0].integrity_check === "ok") {
toastService.showMessage("Integrity check succeeded - no problems found.");
}
else {
toastService.showMessage("Integrity check failed: " + JSON.stringify(results, null, 2), 15000);
}
});
}
}

View File

@@ -0,0 +1,128 @@
import server from "../../services/server.js";
import utils from "../../services/utils.js";
const TPL = `
<h4>ETAPI</h4>
<p>ETAPI is a REST API used to access Trilium instance programmatically, without UI. <br/>
See more details on <a href="https://github.com/zadam/trilium/wiki/ETAPI">wiki</a> and <a onclick="window.open('etapi/etapi.openapi.yaml')" href="etapi/etapi.openapi.yaml">ETAPI OpenAPI spec</a>.</p>
<button type="button" class="btn btn-sm" id="create-etapi-token">Create new ETAPI token</button>
<br/><br/>
<h5>Existing tokens</h5>
<div id="no-tokens-yet">There are no tokens yet. Click on the button above to create one.</div>
<div style="overflow: auto; height: 500px;">
<table id="tokens-table" class="table table-stripped">
<thead>
<tr>
<th>Token name</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<style>
.token-table-button {
display: inline-block;
cursor: pointer;
padding: 3px;
margin-right: 20px;
font-size: large;
border: 1px solid transparent;
border-radius: 5px;
}
.token-table-button:hover {
border: 1px solid var(--main-border-color);
}
</style>
`;
export default class EtapiOptions {
constructor() {
$("#options-etapi").html(TPL);
$("#create-etapi-token").on("click", async () => {
const promptDialog = await import('../../dialogs/prompt.js');
const tokenName = await promptDialog.ask({
title: "New ETAPI token",
message: "Please enter new token's name",
defaultValue: "new token"
});
if (!tokenName.trim()) {
alert("Token name can't be empty");
return;
}
const {authToken} = await server.post('etapi-tokens', {tokenName});
await promptDialog.ask({
title: "ETAPI token created",
message: 'Copy the created token into clipboard. Trilium stores the token hashed and this is the last time you see it.',
defaultValue: authToken
});
this.refreshTokens();
});
this.refreshTokens();
}
async refreshTokens() {
const $noTokensYet = $("#no-tokens-yet");
const $tokensTable = $("#tokens-table");
const tokens = await server.get('etapi-tokens');
$noTokensYet.toggle(tokens.length === 0);
$tokensTable.toggle(tokens.length > 0);
const $tokensTableBody = $tokensTable.find("tbody");
$tokensTableBody.empty();
for (const token of tokens) {
$tokensTableBody.append(
$("<tr>")
.append($("<td>").text(token.name))
.append($("<td>").text(token.utcDateCreated))
.append($("<td>").append(
$('<span class="bx bx-pen token-table-button" title="Rename this token"></span>')
.on("click", () => this.renameToken(token.etapiTokenId, token.name)),
$('<span class="bx bx-trash token-table-button" title="Delete / deactive this token"></span>')
.on("click", () => this.deleteToken(token.etapiTokenId, token.name))
))
);
}
}
async renameToken(etapiTokenId, oldName) {
const promptDialog = await import('../../dialogs/prompt.js');
const tokenName = await promptDialog.ask({
title: "Rename token",
message: "Please enter new token's name",
defaultValue: oldName
});
await server.patch(`etapi-tokens/${etapiTokenId}`, {name: tokenName});
this.refreshTokens();
}
async deleteToken(etapiTokenId, name) {
if (!confirm(`Are you sure you want to delete ETAPI token "${name}"?`)) {
return;
}
await server.remove(`etapi-tokens/${etapiTokenId}`);
this.refreshTokens();
}
}

View File

@@ -3,18 +3,16 @@ import protectedSessionHolder from "../../services/protected_session_holder.js";
import toastService from "../../services/toast.js";
const TPL = `
<h3>Username</h3>
<p>Your username is <strong id="credentials-username"></strong>.</p>
<h3>Change password</h3>
<h3 id="password-heading"></h3>
<div class="alert alert-warning" role="alert" style="font-weight: bold; color: red !important;">
Please take care to remember your new password. Password is used to encrypt protected notes. If you forget your password, then all your protected notes are forever lost with no recovery options.
Please take care to remember your new password. Password is used to encrypt protected notes.
If you forget your password, then all your protected notes are forever lost.
In case you did forget your password, <a id="reset-password-button" href="javascript:">click here to reset it</a>.
</div>
<form id="change-password-form">
<div class="form-group">
<div class="form-group" id="old-password-form-group">
<label for="old-password">Old password</label>
<input class="form-control" id="old-password" type="password">
</div>
@@ -29,24 +27,41 @@ const TPL = `
<input class="form-control" id="new-password2" type="password">
</div>
<button class="btn btn-primary">Change password</button>
<button class="btn btn-primary" id="save-password-button">Change password</button>
</form>`;
export default class ChangePasswordOptions {
constructor() {
$("#options-credentials").html(TPL);
$("#options-password").html(TPL);
this.$username = $("#credentials-username");
this.$passwordHeading = $("#password-heading");
this.$form = $("#change-password-form");
this.$oldPassword = $("#old-password");
this.$newPassword1 = $("#new-password1");
this.$newPassword2 = $("#new-password2");
this.$savePasswordButton = $("#save-password-button");
this.$resetPasswordButton = $("#reset-password-button");
this.$resetPasswordButton.on("click", async () => {
if (confirm("By resetting the password you will forever lose access to all your existing protected notes. Do you really want to reset the password?")) {
await server.post("password/reset?really=yesIReallyWantToResetPasswordAndLoseAccessToMyProtectedNotes");
const options = await server.get('options');
this.optionsLoaded(options);
alert("Password has been reset. Please set new password");
}
});
this.$form.on('submit', () => this.save());
}
optionsLoaded(options) {
this.$username.text(options.username);
const isPasswordSet = options.isPasswordSet === 'true';
$("#old-password-form-group").toggle(isPasswordSet);
this.$passwordHeading.text(isPasswordSet ? 'Change password' : 'Set password');
this.$savePasswordButton.text(isPasswordSet ? 'Change password' : 'Set password');
}
save() {

View File

@@ -0,0 +1,13 @@
import utils from "../services/utils.js";
import appContext from "../services/app_context.js";
export function show() {
const $dialog = $("#password-not-set-dialog");
const $openPasswordOptionsButton = $("#open-password-options-button");
utils.openDialog($dialog);
$openPasswordOptionsButton.on("click", () => {
appContext.triggerCommand("showOptions", { openTab: 'password' });
});
}

View File

@@ -11,9 +11,11 @@ const $form = $("#prompt-dialog-form");
let resolve;
let shownCb;
export function ask({ message, defaultValue, shown }) {
export function ask({ title, message, defaultValue, shown }) {
shownCb = shown;
$("#prompt-title").text(title || "Prompt");
$question = $("<label>")
.prop("for", "prompt-dialog-answer")
.text(message);
@@ -30,7 +32,7 @@ export function ask({ message, defaultValue, shown }) {
.append($question)
.append($answer));
utils.openDialog($dialog);
utils.openDialog($dialog, false);
return new Promise((res, rej) => { resolve = res; });
}
@@ -49,7 +51,8 @@ $dialog.on("hidden.bs.modal", () => {
}
});
$form.on('submit', () => {
$form.on('submit', e => {
e.preventDefault();
resolve($answer.val());
$dialog.modal('hide');

View File

@@ -12,7 +12,7 @@ export function show() {
}
export function close() {
// this may fal if the dialog has not been previously opened (not sure if still true with Bootstrap modal)
// this may fail if the dialog has not been previously opened (not sure if still true with Bootstrap modal)
try {
$dialog.modal('hide');
}

View File

@@ -790,7 +790,7 @@ class NoteShort {
const parentNote = froca.notes[parentNoteId];
if (!parentNote) {
if (!parentNote || parentNote.type === 'search') {
continue;
}

View File

@@ -81,6 +81,7 @@ async function renderAttributes(attributes, renderIsInheritable) {
const HIDDEN_ATTRIBUTES = [
'originalFileName',
'fileSize',
'template',
'cssClass',
'iconClass',

View File

@@ -11,12 +11,12 @@ async function getInboxNote() {
/** @returns {NoteShort} */
async function getTodayNote() {
return await getDateNote(dayjs().format("YYYY-MM-DD"));
return await getDayNote(dayjs().format("YYYY-MM-DD"));
}
/** @returns {NoteShort} */
async function getDateNote(date) {
const note = await server.get('special-notes/date/' + date, "date-note");
async function getDayNote(date) {
const note = await server.get('special-notes/days/' + date, "date-note");
await ws.waitForMaxKnownEntityChangeId();
@@ -25,7 +25,7 @@ async function getDateNote(date) {
/** @returns {NoteShort} */
async function getWeekNote(date) {
const note = await server.get('special-notes/week/' + date, "date-note");
const note = await server.get('special-notes/weeks/' + date, "date-note");
await ws.waitForMaxKnownEntityChangeId();
@@ -34,7 +34,7 @@ async function getWeekNote(date) {
/** @returns {NoteShort} */
async function getMonthNote(month) {
const note = await server.get('special-notes/month/' + month, "date-note");
const note = await server.get('special-notes/months/' + month, "date-note");
await ws.waitForMaxKnownEntityChangeId();
@@ -43,7 +43,7 @@ async function getMonthNote(month) {
/** @returns {NoteShort} */
async function getYearNote(year) {
const note = await server.get('special-notes/year/' + year, "date-note");
const note = await server.get('special-notes/years/' + year, "date-note");
await ws.waitForMaxKnownEntityChangeId();
@@ -71,7 +71,7 @@ async function createSearchNote(opts = {}) {
export default {
getInboxNote,
getTodayNote,
getDateNote,
getDayNote,
getWeekNote,
getMonthNote,
getYearNote,

View File

@@ -22,9 +22,9 @@ async function processEntityChanges(entityChanges) {
} else if (ec.entityName === 'note_contents') {
delete froca.noteComplementPromises[ec.entityId];
loadResults.addNoteContent(ec.entityId, ec.sourceId);
loadResults.addNoteContent(ec.entityId, ec.componentId);
} else if (ec.entityName === 'note_revisions') {
loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.sourceId);
loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId);
} else if (ec.entityName === 'note_revision_contents') {
// this should change only when toggling isProtected, ignore
} else if (ec.entityName === 'options') {
@@ -36,6 +36,9 @@ async function processEntityChanges(entityChanges) {
loadResults.addOption(ec.entity.name);
}
else if (ec.entityName === 'etapi_tokens') {
// NOOP
}
else {
throw new Error(`Unknown entityName ${ec.entityName}`);
}
@@ -87,7 +90,7 @@ function processNoteChange(loadResults, ec) {
return;
}
loadResults.addNote(ec.entityId, ec.sourceId);
loadResults.addNote(ec.entityId, ec.componentId);
if (ec.isErased && ec.entityId in froca.notes) {
utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`);
@@ -125,7 +128,7 @@ function processBranchChange(loadResults, ec) {
delete parentNote.childToBranch[branch.noteId];
}
loadResults.addBranch(ec.entityId, ec.sourceId);
loadResults.addBranch(ec.entityId, ec.componentId);
delete froca.branches[ec.entityId];
}
@@ -133,7 +136,7 @@ function processBranchChange(loadResults, ec) {
return;
}
loadResults.addBranch(ec.entityId, ec.sourceId);
loadResults.addBranch(ec.entityId, ec.componentId);
const childNote = froca.notes[ec.entity.noteId];
const parentNote = froca.notes[ec.entity.parentNoteId];
@@ -175,7 +178,7 @@ function processNoteReordering(loadResults, ec) {
}
}
loadResults.addNoteReordering(ec.entityId, ec.sourceId);
loadResults.addNoteReordering(ec.entityId, ec.componentId);
}
function processAttributeChange(loadResults, ec) {
@@ -199,7 +202,7 @@ function processAttributeChange(loadResults, ec) {
targetNote.targetRelations = targetNote.targetRelations.filter(attributeId => attributeId !== attribute.attributeId);
}
loadResults.addAttribute(ec.entityId, ec.sourceId);
loadResults.addAttribute(ec.entityId, ec.componentId);
delete froca.attributes[ec.entityId];
}
@@ -207,7 +210,7 @@ function processAttributeChange(loadResults, ec) {
return;
}
loadResults.addAttribute(ec.entityId, ec.sourceId);
loadResults.addAttribute(ec.entityId, ec.componentId);
const sourceNote = froca.notes[ec.entity.noteId];
const targetNote = ec.entity.type === 'relation' && froca.notes[ec.entity.value];

View File

@@ -389,16 +389,26 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
this.getTodayNote = dateNotesService.getTodayNote;
/**
* Returns date-note. If it doesn't exist, it is automatically created.
* Returns day note for a given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise<NoteShort>}
* @deprecated use getDayNote instead
*/
this.getDateNote = dateNotesService.getDayNote;
/**
* Returns day note for a given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise<NoteShort>}
*/
this.getDateNote = dateNotesService.getDateNote;
this.getDayNote = dateNotesService.getDayNote;
/**
* Returns date-note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
* Returns day note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"

View File

@@ -3,16 +3,17 @@ const CKEDITOR = {"js": ["libraries/ckeditor/ckeditor.js"]};
const CODE_MIRROR = {
js: [
"libraries/codemirror/codemirror.js",
"libraries/codemirror/addon/mode/loadmode.js",
"libraries/codemirror/addon/mode/simple.js",
"libraries/codemirror/addon/fold/xml-fold.js",
"libraries/codemirror/addon/display/placeholder.js",
"libraries/codemirror/addon/edit/matchbrackets.js",
"libraries/codemirror/addon/edit/matchtags.js",
"libraries/codemirror/addon/fold/xml-fold.js",
"libraries/codemirror/addon/lint/lint.js",
"libraries/codemirror/addon/lint/eslint.js",
"libraries/codemirror/addon/mode/loadmode.js",
"libraries/codemirror/addon/mode/simple.js",
"libraries/codemirror/addon/search/match-highlighter.js",
"libraries/codemirror/mode/meta.js",
"libraries/codemirror/keymap/vim.js",
"libraries/codemirror/addon/lint/lint.js",
"libraries/codemirror/addon/lint/eslint.js"
"libraries/codemirror/keymap/vim.js"
],
css: [
"libraries/codemirror/codemirror.css",

Some files were not shown because too many files have changed in this diff Show More