mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	Compare commits
	
		
			16 Commits
		
	
	
		
			v0.61.8-be
			...
			v0.61.9-be
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d09d3f5a96 | ||
|  | 3d15aeae58 | ||
|  | 9765892d18 | ||
|  | 78f8a37587 | ||
|  | 86d62866f2 | ||
|  | 1dc3fafcbf | ||
|  | 7f06952d9e | ||
|  | 78b6614eea | ||
|  | 9665e872c2 | ||
|  | 9db0a062ed | ||
|  | 055bb39e4d | ||
|  | 1261a06a30 | ||
|  | 91eb3c45d5 | ||
|  | 3944235592 | ||
|  | 5be61e6142 | ||
|  | 62ccf798ee | 
							
								
								
									
										0
									
								
								bin/create-anonymization-script.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								bin/create-anonymization-script.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,160 +1,42 @@ | |||||||
|  |  | ||||||
| UPDATE etapi_tokens SET tokenHash = 'API token hash value'; | UPDATE etapi_tokens SET tokenHash = 'API token hash value'; | ||||||
| UPDATE notes SET title = 'title' WHERE noteId != 'root' AND noteId NOT LIKE '\_%' ESCAPE '\'; | UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share'); | ||||||
| UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; | UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; | ||||||
| UPDATE revisions SET title = 'title'; | UPDATE revisions SET title = 'title'; | ||||||
|  |  | ||||||
| UPDATE attributes SET name = 'name', value = 'value' | UPDATE attributes SET name  = 'name', value = 'value' WHERE type = 'label' | ||||||
|                   WHERE type = 'label' |   AND name NOT IN | ||||||
|                     AND name NOT IN ('inbox', |       ('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', | ||||||
|                                      'disableVersioning', |        'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', | ||||||
|                                      'calendarRoot', |        'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', | ||||||
|                                      'archived', |        'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'revisionsWidgetDisabled', | ||||||
|                                      'excludeFromExport', |        'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', | ||||||
|                                      'disableInclusion', |        'workspaceTabBackgroundColor', 'workspaceCalendarRoot', 'workspaceTemplate', 'searchHome', 'workspaceInbox', | ||||||
|                                      'appCss', |        'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', | ||||||
|                                      'appTheme', |        'bookmarkFolder', 'sorted', 'sortDirection', 'sortFoldersFirst', 'sortNatural', 'sortLocale', 'top', | ||||||
|                                      'hidePromotedAttributes', |        'fullContentWidth', 'shareHiddenFromTree', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', | ||||||
|                                      'readOnly', |        'shareRaw', 'shareDisallowRobotIndexing', 'shareIndex', 'displayRelations', 'hideRelations', 'titleTemplate', | ||||||
|                                      'autoReadOnlyDisabled', |        'template', 'toc', 'color', 'keepCurrentHoisting', 'executeButton', 'executeDescription', 'newNotesOnTop', | ||||||
|                                      'cssClass', |        'clipperInbox', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', | ||||||
|                                      'iconClass', |        'runOnNoteTitleChange', 'runOnNoteChange', 'runOnNoteContentChange', 'runOnNoteDeletion', 'runOnBranchCreation', | ||||||
|                                      'keyboardShortcut', |        'runOnBranchDeletion', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', | ||||||
|                                      'run', |        'inherit', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon'); | ||||||
|                                      'runOnInstance', | UPDATE attributes SET name = 'name' WHERE type = 'relation' | ||||||
|                                      'runAtHour', |   AND name NOT IN | ||||||
|                                      'customRequestHandler', |       ('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', | ||||||
|                                      'customResourceProvider', |        'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', | ||||||
|                                      'widget', |        'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', | ||||||
|                                      'noteInfoWidgetDisabled', |        'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'revisionsWidgetDisabled', | ||||||
|                                      'linkMapWidgetDisabled', |        'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', | ||||||
|                                      'revisionsWidgetDisabled', |        'workspaceTabBackgroundColor', 'workspaceCalendarRoot', 'workspaceTemplate', 'searchHome', 'workspaceInbox', | ||||||
|                                      'whatLinksHereWidgetDisabled', |        'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', | ||||||
|                                      'similarNotesWidgetDisabled', |        'bookmarkFolder', 'sorted', 'sortDirection', 'sortFoldersFirst', 'sortNatural', 'sortLocale', 'top', | ||||||
|                                      'workspace', |        'fullContentWidth', 'shareHiddenFromTree', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', | ||||||
|                                      'workspaceIconClass', |        'shareRaw', 'shareDisallowRobotIndexing', 'shareIndex', 'displayRelations', 'hideRelations', 'titleTemplate', | ||||||
|                                      'workspaceTabBackgroundColor', |        'template', 'toc', 'color', 'keepCurrentHoisting', 'executeButton', 'executeDescription', 'newNotesOnTop', | ||||||
|                                      'searchHome', |        'clipperInbox', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', | ||||||
|                                      'workspaceInbox', |        'runOnNoteTitleChange', 'runOnNoteChange', 'runOnNoteContentChange', 'runOnNoteDeletion', 'runOnBranchCreation', | ||||||
|                                      'workspaceSearchHome', |        'runOnBranchDeletion', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', | ||||||
|                                      'sqlConsoleHome', |        'inherit', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon'); | ||||||
|                                      'datePattern', |  | ||||||
|                                      'pageSize', |  | ||||||
|                                      'viewType', |  | ||||||
|                                      'mapRootNoteId', |  | ||||||
|                                      'bookmarkFolder', |  | ||||||
|                                      'sorted', |  | ||||||
|                                      'top', |  | ||||||
|                                      'fullContentWidth', |  | ||||||
|                                      'shareHiddenFromTree', |  | ||||||
|                                      'shareAlias', |  | ||||||
|                                      'shareOmitDefaultCss', |  | ||||||
|                                      'shareRoot', |  | ||||||
|                                      'internalLink', |  | ||||||
|                                      'imageLink', |  | ||||||
|                                      'relationMapLink', |  | ||||||
|                                      'includeMapLink', |  | ||||||
|                                      'runOnNoteCreation', |  | ||||||
|                                      'runOnNoteTitleChange', |  | ||||||
|                                      'runOnNoteContentChange', |  | ||||||
|                                      'runOnNoteChange', |  | ||||||
|                                      'runOnChildNoteCreation', |  | ||||||
|                                      'runOnAttributeCreation', |  | ||||||
|                                      'runOnAttributeChange', |  | ||||||
|                                      'template', |  | ||||||
|                                      'inherit', |  | ||||||
|                                      'widget', |  | ||||||
|                                      'renderNote', |  | ||||||
|                                      'shareCss', |  | ||||||
|                                      'shareJs', |  | ||||||
|                                      'shareFavicon', |  | ||||||
|                                      'executeButton', |  | ||||||
|                                      'keepCurrentHoisting', |  | ||||||
|                                      'color', |  | ||||||
|                                      'toc', |  | ||||||
|                                      'excludeFromNoteMap', |  | ||||||
|                                      'docName', |  | ||||||
|                                      'launcherType', |  | ||||||
|                                      'builtinWidget', |  | ||||||
|                                      'baseSize', |  | ||||||
|                                      'growthFactor' |  | ||||||
|                       ); |  | ||||||
|  |  | ||||||
| UPDATE attributes SET name = 'name' |  | ||||||
|                     AND name NOT IN ('inbox', |  | ||||||
|                                      'disableVersioning', |  | ||||||
|                                      'calendarRoot', |  | ||||||
|                                      'archived', |  | ||||||
|                                      'excludeFromExport', |  | ||||||
|                                      'disableInclusion', |  | ||||||
|                                      'appCss', |  | ||||||
|                                      'appTheme', |  | ||||||
|                                      'hidePromotedAttributes', |  | ||||||
|                                      'readOnly', |  | ||||||
|                                      'autoReadOnlyDisabled', |  | ||||||
|                                      'cssClass', |  | ||||||
|                                      'iconClass', |  | ||||||
|                                      'keyboardShortcut', |  | ||||||
|                                      'run', |  | ||||||
|                                      'runOnInstance', |  | ||||||
|                                      'runAtHour', |  | ||||||
|                                      'customRequestHandler', |  | ||||||
|                                      'customResourceProvider', |  | ||||||
|                                      'widget', |  | ||||||
|                                      'noteInfoWidgetDisabled', |  | ||||||
|                                      'linkMapWidgetDisabled', |  | ||||||
|                                      'revisionsWidgetDisabled', |  | ||||||
|                                      'whatLinksHereWidgetDisabled', |  | ||||||
|                                      'similarNotesWidgetDisabled', |  | ||||||
|                                      'workspace', |  | ||||||
|                                      'workspaceIconClass', |  | ||||||
|                                      'workspaceTabBackgroundColor', |  | ||||||
|                                      'searchHome', |  | ||||||
|                                      'workspaceInbox', |  | ||||||
|                                      'workspaceSearchHome', |  | ||||||
|                                      'sqlConsoleHome', |  | ||||||
|                                      'datePattern', |  | ||||||
|                                      'pageSize', |  | ||||||
|                                      'viewType', |  | ||||||
|                                      'mapRootNoteId', |  | ||||||
|                                      'bookmarkFolder', |  | ||||||
|                                      'sorted', |  | ||||||
|                                      'top', |  | ||||||
|                                      'fullContentWidth', |  | ||||||
|                                      'shareHiddenFromTree', |  | ||||||
|                                      'shareAlias', |  | ||||||
|                                      'shareOmitDefaultCss', |  | ||||||
|                                      'shareRoot', |  | ||||||
|                                      'internalLink', |  | ||||||
|                                      'imageLink', |  | ||||||
|                                      'relationMapLink', |  | ||||||
|                                      'includeMapLink', |  | ||||||
|                                      'runOnNoteCreation', |  | ||||||
|                                      'runOnNoteTitleChange', |  | ||||||
|                                      'runOnNoteContentChange', |  | ||||||
|                                      'runOnNoteChange', |  | ||||||
|                                      'runOnChildNoteCreation', |  | ||||||
|                                      'runOnAttributeCreation', |  | ||||||
|                                      'runOnAttributeChange', |  | ||||||
|                                      'template', |  | ||||||
|                                      'inherit', |  | ||||||
|                                      'widget', |  | ||||||
|                                      'renderNote', |  | ||||||
|                                      'shareCss', |  | ||||||
|                                      'shareJs', |  | ||||||
|                                      'shareFavicon', |  | ||||||
|                                      'executeButton', |  | ||||||
|                                      'keepCurrentHoisting', |  | ||||||
|                                      'color', |  | ||||||
|                                      'toc', |  | ||||||
|                                      'excludeFromNoteMap', |  | ||||||
|                                      'docName', |  | ||||||
|                                      'launcherType', |  | ||||||
|                                      'builtinWidget', |  | ||||||
|                                      'baseSize', |  | ||||||
|                                      'growthFactor' |  | ||||||
|                                     ); |  | ||||||
|  |  | ||||||
| UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL AND prefix != 'recovered'; | UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL AND prefix != 'recovered'; | ||||||
| UPDATE options SET value = 'anonymized' WHERE name IN | UPDATE options SET value = 'anonymized' WHERE name IN | ||||||
|       ('documentId', 'documentSecret', 'encryptedDataKey', |       ('documentId', 'documentSecret', 'encryptedDataKey', | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								db/migrations/0226__rename_noteSize_label.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								db/migrations/0226__rename_noteSize_label.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | UPDATE attributes SET value = 'contentAndAttachmentsAndRevisionsSize' WHERE name = 'orderBy' AND value = 'noteSize'; | ||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | # Running `docker-compose up` will create/use the "trilium-data" directory in the user home | ||||||
|  | # Run `TRILIUM_DATA_DIR=/path/of/your/choice docker-compose up` to set a different directory | ||||||
| version: '2.1' | version: '2.1' | ||||||
| services: | services: | ||||||
|   trilium: |   trilium: | ||||||
| @@ -8,7 +10,7 @@ services: | |||||||
|     ports: |     ports: | ||||||
|       - "8080:8080" |       - "8080:8080" | ||||||
|     volumes: |     volumes: | ||||||
|       - trilium:/home/node/trilium-data |       - ${TRILIUM_DATA_DIR:-~/trilium-data}:/home/node/trilium-data | ||||||
|  |  | ||||||
| volumes: | volumes: | ||||||
|   trilium: |   trilium: | ||||||
|   | |||||||
							
								
								
									
										148
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										148
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "version": "0.61.7-beta", |   "version": "0.61.8-beta", | ||||||
|   "lockfileVersion": 2, |   "lockfileVersion": 2, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "trilium", |       "name": "trilium", | ||||||
|       "version": "0.61.7-beta", |       "version": "0.61.8-beta", | ||||||
|       "hasInstallScript": true, |       "hasInstallScript": true, | ||||||
|       "license": "AGPL-3.0-only", |       "license": "AGPL-3.0-only", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
| @@ -47,7 +47,7 @@ | |||||||
|         "jimp": "0.22.10", |         "jimp": "0.22.10", | ||||||
|         "joplin-turndown-plugin-gfm": "1.0.12", |         "joplin-turndown-plugin-gfm": "1.0.12", | ||||||
|         "jsdom": "22.1.0", |         "jsdom": "22.1.0", | ||||||
|         "marked": "9.0.3", |         "marked": "9.1.0", | ||||||
|         "mime-types": "2.1.35", |         "mime-types": "2.1.35", | ||||||
|         "multer": "1.4.5-lts.1", |         "multer": "1.4.5-lts.1", | ||||||
|         "node-abi": "3.47.0", |         "node-abi": "3.47.0", | ||||||
| @@ -57,11 +57,11 @@ | |||||||
|         "react": "18.2.0", |         "react": "18.2.0", | ||||||
|         "react-dom": "18.2.0", |         "react-dom": "18.2.0", | ||||||
|         "request": "2.88.2", |         "request": "2.88.2", | ||||||
|         "rimraf": "5.0.1", |         "rimraf": "5.0.5", | ||||||
|         "safe-compare": "1.1.4", |         "safe-compare": "1.1.4", | ||||||
|         "sanitize-filename": "1.6.3", |         "sanitize-filename": "1.6.3", | ||||||
|         "sanitize-html": "2.11.0", |         "sanitize-html": "2.11.0", | ||||||
|         "sax": "1.2.4", |         "sax": "1.3.0", | ||||||
|         "semver": "7.5.4", |         "semver": "7.5.4", | ||||||
|         "serve-favicon": "2.5.0", |         "serve-favicon": "2.5.0", | ||||||
|         "session-file-store": "1.5.0", |         "session-file-store": "1.5.0", | ||||||
| @@ -79,7 +79,7 @@ | |||||||
|       }, |       }, | ||||||
|       "devDependencies": { |       "devDependencies": { | ||||||
|         "cross-env": "7.0.3", |         "cross-env": "7.0.3", | ||||||
|         "electron": "25.8.3", |         "electron": "25.9.0", | ||||||
|         "electron-builder": "24.6.4", |         "electron-builder": "24.6.4", | ||||||
|         "electron-packager": "17.1.2", |         "electron-packager": "17.1.2", | ||||||
|         "electron-rebuild": "3.2.9", |         "electron-rebuild": "3.2.9", | ||||||
| @@ -4276,9 +4276,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/electron": { |     "node_modules/electron": { | ||||||
|       "version": "25.8.3", |       "version": "25.9.0", | ||||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-25.8.3.tgz", |       "resolved": "https://registry.npmjs.org/electron/-/electron-25.9.0.tgz", | ||||||
|       "integrity": "sha512-BdcTIrhQIf6YgsihCXYh3DgKobtLaNcFb1B5C/5euepxxXQ7qmTWC6WgNUm+IntLOFEDQO926rvm2nhRdSN+Nw==", |       "integrity": "sha512-wgscxf2ORHL/8mAQfy7l9rVDG//wrG9RUQndG508kCCMHRq9deFyZ4psOMzySheBRSfGMcFoRFYSlkAeZr8cFg==", | ||||||
|       "hasInstallScript": true, |       "hasInstallScript": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@electron/get": "^2.0.0", |         "@electron/get": "^2.0.0", | ||||||
| @@ -7697,9 +7697,9 @@ | |||||||
|       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" |       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" | ||||||
|     }, |     }, | ||||||
|     "node_modules/jackspeak": { |     "node_modules/jackspeak": { | ||||||
|       "version": "2.2.1", |       "version": "2.3.6", | ||||||
|       "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", |       "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", | ||||||
|       "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", |       "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@isaacs/cliui": "^8.0.2" |         "@isaacs/cliui": "^8.0.2" | ||||||
|       }, |       }, | ||||||
| @@ -8946,9 +8946,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/marked": { |     "node_modules/marked": { | ||||||
|       "version": "9.0.3", |       "version": "9.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/marked/-/marked-9.0.3.tgz", |       "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.0.tgz", | ||||||
|       "integrity": "sha512-pI/k4nzBG1PEq1J3XFEHxVvjicfjl8rgaMaqclouGSMPhk7Q3Ejb2ZRxx/ZQOcQ1909HzVoWCFYq6oLgtL4BpQ==", |       "integrity": "sha512-VZjm0PM5DMv7WodqOUps3g6Q7dmxs9YGiFUZ7a2majzQTTCgX+6S6NAJHPvOhgFBzYz8s4QZKWWMfZKFmsfOgA==", | ||||||
|       "bin": { |       "bin": { | ||||||
|         "marked": "bin/marked.js" |         "marked": "bin/marked.js" | ||||||
|       }, |       }, | ||||||
| @@ -10106,12 +10106,12 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "node_modules/path-scurry": { |     "node_modules/path-scurry": { | ||||||
|       "version": "1.9.2", |       "version": "1.10.1", | ||||||
|       "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", |       "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", | ||||||
|       "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", |       "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "lru-cache": "^9.1.1", |         "lru-cache": "^9.1.1 || ^10.0.0", | ||||||
|         "minipass": "^5.0.0 || ^6.0.2" |         "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=16 || 14 >=14.17" |         "node": ">=16 || 14 >=14.17" | ||||||
| @@ -10947,14 +10947,14 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "node_modules/rimraf": { |     "node_modules/rimraf": { | ||||||
|       "version": "5.0.1", |       "version": "5.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", |       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", | ||||||
|       "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", |       "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "glob": "^10.2.5" |         "glob": "^10.3.7" | ||||||
|       }, |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "rimraf": "dist/cjs/src/bin.js" |         "rimraf": "dist/esm/bin.mjs" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=14" |         "node": ">=14" | ||||||
| @@ -10972,18 +10972,18 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/rimraf/node_modules/glob": { |     "node_modules/rimraf/node_modules/glob": { | ||||||
|       "version": "10.2.6", |       "version": "10.3.10", | ||||||
|       "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.6.tgz", |       "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", | ||||||
|       "integrity": "sha512-U/rnDpXJGF414QQQZv5uVsabTVxMSwzS5CH0p3DRCIV6ownl4f7PzGnkGmvlum2wB+9RlJWJZ6ACU1INnBqiPA==", |       "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "foreground-child": "^3.1.0", |         "foreground-child": "^3.1.0", | ||||||
|         "jackspeak": "^2.0.3", |         "jackspeak": "^2.3.5", | ||||||
|         "minimatch": "^9.0.1", |         "minimatch": "^9.0.1", | ||||||
|         "minipass": "^5.0.0 || ^6.0.2", |         "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", | ||||||
|         "path-scurry": "^1.7.0" |         "path-scurry": "^1.10.1" | ||||||
|       }, |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "glob": "dist/cjs/src/bin.js" |         "glob": "dist/esm/bin.mjs" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=16 || 14 >=14.17" |         "node": ">=16 || 14 >=14.17" | ||||||
| @@ -10993,9 +10993,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/rimraf/node_modules/minimatch": { |     "node_modules/rimraf/node_modules/minimatch": { | ||||||
|       "version": "9.0.1", |       "version": "9.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", |       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", | ||||||
|       "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", |       "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "brace-expansion": "^2.0.1" |         "brace-expansion": "^2.0.1" | ||||||
|       }, |       }, | ||||||
| @@ -11007,9 +11007,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/rimraf/node_modules/minipass": { |     "node_modules/rimraf/node_modules/minipass": { | ||||||
|       "version": "6.0.2", |       "version": "7.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", |       "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", | ||||||
|       "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", |       "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=16 || 14 >=14.17" |         "node": ">=16 || 14 >=14.17" | ||||||
|       } |       } | ||||||
| @@ -11290,9 +11290,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/sax": { |     "node_modules/sax": { | ||||||
|       "version": "1.2.4", |       "version": "1.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", |       "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", | ||||||
|       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" |       "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" | ||||||
|     }, |     }, | ||||||
|     "node_modules/saxes": { |     "node_modules/saxes": { | ||||||
|       "version": "6.0.0", |       "version": "6.0.0", | ||||||
| @@ -16542,9 +16542,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "electron": { |     "electron": { | ||||||
|       "version": "25.8.3", |       "version": "25.9.0", | ||||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-25.8.3.tgz", |       "resolved": "https://registry.npmjs.org/electron/-/electron-25.9.0.tgz", | ||||||
|       "integrity": "sha512-BdcTIrhQIf6YgsihCXYh3DgKobtLaNcFb1B5C/5euepxxXQ7qmTWC6WgNUm+IntLOFEDQO926rvm2nhRdSN+Nw==", |       "integrity": "sha512-wgscxf2ORHL/8mAQfy7l9rVDG//wrG9RUQndG508kCCMHRq9deFyZ4psOMzySheBRSfGMcFoRFYSlkAeZr8cFg==", | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@electron/get": "^2.0.0", |         "@electron/get": "^2.0.0", | ||||||
|         "@types/node": "^18.11.18", |         "@types/node": "^18.11.18", | ||||||
| @@ -19062,9 +19062,9 @@ | |||||||
|       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" |       "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" | ||||||
|     }, |     }, | ||||||
|     "jackspeak": { |     "jackspeak": { | ||||||
|       "version": "2.2.1", |       "version": "2.3.6", | ||||||
|       "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", |       "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", | ||||||
|       "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", |       "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@isaacs/cliui": "^8.0.2", |         "@isaacs/cliui": "^8.0.2", | ||||||
|         "@pkgjs/parseargs": "^0.11.0" |         "@pkgjs/parseargs": "^0.11.0" | ||||||
| @@ -19990,9 +19990,9 @@ | |||||||
|       "requires": {} |       "requires": {} | ||||||
|     }, |     }, | ||||||
|     "marked": { |     "marked": { | ||||||
|       "version": "9.0.3", |       "version": "9.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/marked/-/marked-9.0.3.tgz", |       "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.0.tgz", | ||||||
|       "integrity": "sha512-pI/k4nzBG1PEq1J3XFEHxVvjicfjl8rgaMaqclouGSMPhk7Q3Ejb2ZRxx/ZQOcQ1909HzVoWCFYq6oLgtL4BpQ==" |       "integrity": "sha512-VZjm0PM5DMv7WodqOUps3g6Q7dmxs9YGiFUZ7a2majzQTTCgX+6S6NAJHPvOhgFBzYz8s4QZKWWMfZKFmsfOgA==" | ||||||
|     }, |     }, | ||||||
|     "matcher": { |     "matcher": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
| @@ -20873,12 +20873,12 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "path-scurry": { |     "path-scurry": { | ||||||
|       "version": "1.9.2", |       "version": "1.10.1", | ||||||
|       "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", |       "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", | ||||||
|       "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", |       "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", | ||||||
|       "requires": { |       "requires": { | ||||||
|         "lru-cache": "^9.1.1", |         "lru-cache": "^9.1.1 || ^10.0.0", | ||||||
|         "minipass": "^5.0.0 || ^6.0.2" |         "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" | ||||||
|       }, |       }, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "lru-cache": { |         "lru-cache": { | ||||||
| @@ -21498,11 +21498,11 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "rimraf": { |     "rimraf": { | ||||||
|       "version": "5.0.1", |       "version": "5.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", |       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", | ||||||
|       "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", |       "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", | ||||||
|       "requires": { |       "requires": { | ||||||
|         "glob": "^10.2.5" |         "glob": "^10.3.7" | ||||||
|       }, |       }, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "brace-expansion": { |         "brace-expansion": { | ||||||
| @@ -21514,29 +21514,29 @@ | |||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         "glob": { |         "glob": { | ||||||
|           "version": "10.2.6", |           "version": "10.3.10", | ||||||
|           "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.6.tgz", |           "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", | ||||||
|           "integrity": "sha512-U/rnDpXJGF414QQQZv5uVsabTVxMSwzS5CH0p3DRCIV6ownl4f7PzGnkGmvlum2wB+9RlJWJZ6ACU1INnBqiPA==", |           "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", | ||||||
|           "requires": { |           "requires": { | ||||||
|             "foreground-child": "^3.1.0", |             "foreground-child": "^3.1.0", | ||||||
|             "jackspeak": "^2.0.3", |             "jackspeak": "^2.3.5", | ||||||
|             "minimatch": "^9.0.1", |             "minimatch": "^9.0.1", | ||||||
|             "minipass": "^5.0.0 || ^6.0.2", |             "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", | ||||||
|             "path-scurry": "^1.7.0" |             "path-scurry": "^1.10.1" | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         "minimatch": { |         "minimatch": { | ||||||
|           "version": "9.0.1", |           "version": "9.0.3", | ||||||
|           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", |           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", | ||||||
|           "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", |           "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", | ||||||
|           "requires": { |           "requires": { | ||||||
|             "brace-expansion": "^2.0.1" |             "brace-expansion": "^2.0.1" | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         "minipass": { |         "minipass": { | ||||||
|           "version": "6.0.2", |           "version": "7.0.4", | ||||||
|           "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", |           "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", | ||||||
|           "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==" |           "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
| @@ -21736,9 +21736,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "sax": { |     "sax": { | ||||||
|       "version": "1.2.4", |       "version": "1.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", |       "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", | ||||||
|       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" |       "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" | ||||||
|     }, |     }, | ||||||
|     "saxes": { |     "saxes": { | ||||||
|       "version": "6.0.0", |       "version": "6.0.0", | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "Trilium Notes", |   "productName": "Trilium Notes", | ||||||
|   "description": "Trilium Notes", |   "description": "Trilium Notes", | ||||||
|   "version": "0.61.8-beta", |   "version": "0.61.9-beta", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "electron.js", |   "main": "electron.js", | ||||||
|   "bin": { |   "bin": { | ||||||
| @@ -68,7 +68,7 @@ | |||||||
|     "jimp": "0.22.10", |     "jimp": "0.22.10", | ||||||
|     "joplin-turndown-plugin-gfm": "1.0.12", |     "joplin-turndown-plugin-gfm": "1.0.12", | ||||||
|     "jsdom": "22.1.0", |     "jsdom": "22.1.0", | ||||||
|     "marked": "9.0.3", |     "marked": "9.1.0", | ||||||
|     "mime-types": "2.1.35", |     "mime-types": "2.1.35", | ||||||
|     "multer": "1.4.5-lts.1", |     "multer": "1.4.5-lts.1", | ||||||
|     "node-abi": "3.47.0", |     "node-abi": "3.47.0", | ||||||
| @@ -78,11 +78,11 @@ | |||||||
|     "react": "18.2.0", |     "react": "18.2.0", | ||||||
|     "react-dom": "18.2.0", |     "react-dom": "18.2.0", | ||||||
|     "request": "2.88.2", |     "request": "2.88.2", | ||||||
|     "rimraf": "5.0.1", |     "rimraf": "5.0.5", | ||||||
|     "safe-compare": "1.1.4", |     "safe-compare": "1.1.4", | ||||||
|     "sanitize-filename": "1.6.3", |     "sanitize-filename": "1.6.3", | ||||||
|     "sanitize-html": "2.11.0", |     "sanitize-html": "2.11.0", | ||||||
|     "sax": "1.2.4", |     "sax": "1.3.0", | ||||||
|     "semver": "7.5.4", |     "semver": "7.5.4", | ||||||
|     "serve-favicon": "2.5.0", |     "serve-favicon": "2.5.0", | ||||||
|     "session-file-store": "1.5.0", |     "session-file-store": "1.5.0", | ||||||
| @@ -97,7 +97,7 @@ | |||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "cross-env": "7.0.3", |     "cross-env": "7.0.3", | ||||||
|     "electron": "25.8.3", |     "electron": "25.9.0", | ||||||
|     "electron-builder": "24.6.4", |     "electron-builder": "24.6.4", | ||||||
|     "electron-packager": "17.1.2", |     "electron-packager": "17.1.2", | ||||||
|     "electron-rebuild": "3.2.9", |     "electron-rebuild": "3.2.9", | ||||||
|   | |||||||
| @@ -132,11 +132,17 @@ class BNote extends AbstractBeccaEntity { | |||||||
|          */ |          */ | ||||||
|         this.contentSize = null; |         this.contentSize = null; | ||||||
|         /** |         /** | ||||||
|          * size of the content and note revision contents in bytes |          * size of the note content, attachment contents in bytes | ||||||
|          * @type {int|null} |          * @type {int|null} | ||||||
|          * @private |          * @private | ||||||
|          */ |          */ | ||||||
|         this.noteSize = null; |         this.contentAndAttachmentsSize = null; | ||||||
|  |         /** | ||||||
|  |          * size of the note content, attachment contents and revision contents in bytes | ||||||
|  |          * @type {int|null} | ||||||
|  |          * @private | ||||||
|  |          */ | ||||||
|  |         this.contentAndAttachmentsAndRevisionsSize = null; | ||||||
|         /** |         /** | ||||||
|          * number of note revisions for this note |          * number of note revisions for this note | ||||||
|          * @type {int|null} |          * @type {int|null} | ||||||
| @@ -1607,16 +1613,12 @@ class BNote extends AbstractBeccaEntity { | |||||||
|  |  | ||||||
|             revision.save(); // to generate revisionId, which is then used to save attachments |             revision.save(); // to generate revisionId, which is then used to save attachments | ||||||
|  |  | ||||||
|             if (this.type === 'text') { |  | ||||||
|             for (const noteAttachment of this.getAttachments()) { |             for (const noteAttachment of this.getAttachments()) { | ||||||
|                     if (noteAttachment.utcDateScheduledForErasureSince) { |  | ||||||
|                         continue; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 const revisionAttachment = noteAttachment.copy(); |                 const revisionAttachment = noteAttachment.copy(); | ||||||
|                 revisionAttachment.ownerId = revision.revisionId; |                 revisionAttachment.ownerId = revision.revisionId; | ||||||
|                 revisionAttachment.setContent(noteAttachment.getContent(), {forceSave: true}); |                 revisionAttachment.setContent(noteAttachment.getContent(), {forceSave: true}); | ||||||
|  |  | ||||||
|  |                 if (this.type === 'text') { | ||||||
|                     // content is rewritten to point to the revision attachments |                     // content is rewritten to point to the revision attachments | ||||||
|                     noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`, |                     noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`, | ||||||
|                         `attachments/${revisionAttachment.attachmentId}`); |                         `attachments/${revisionAttachment.attachmentId}`); | ||||||
|   | |||||||
| @@ -86,6 +86,29 @@ class BRevision extends AbstractBeccaEntity { | |||||||
|         return this._getContent(); |         return this._getContent(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @returns {*} | ||||||
|  |      * @throws Error in case of invalid JSON */ | ||||||
|  |     getJsonContent() { | ||||||
|  |         const content = this.getContent(); | ||||||
|  |  | ||||||
|  |         if (!content || !content.trim()) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return JSON.parse(content); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {*|null} valid object or null if the content cannot be parsed as JSON */ | ||||||
|  |     getJsonContentSafely() { | ||||||
|  |         try { | ||||||
|  |             return this.getJsonContent(); | ||||||
|  |         } | ||||||
|  |         catch (e) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * @param content |      * @param content | ||||||
|      * @param {object} [opts] |      * @param {object} [opts] | ||||||
| @@ -105,6 +128,45 @@ class BRevision extends AbstractBeccaEntity { | |||||||
|             .map(row => new BAttachment(row)); |             .map(row => new BAttachment(row)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** @returns {BAttachment|null} */ | ||||||
|  |     getAttachmentById(attachmentId, opts = {}) { | ||||||
|  |         opts.includeContentLength = !!opts.includeContentLength; | ||||||
|  |  | ||||||
|  |         const query = opts.includeContentLength | ||||||
|  |             ? `SELECT attachments.*, LENGTH(blobs.content) AS contentLength | ||||||
|  |                FROM attachments  | ||||||
|  |                JOIN blobs USING (blobId)  | ||||||
|  |                WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0` | ||||||
|  |             : `SELECT * FROM attachments WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`; | ||||||
|  |  | ||||||
|  |         return sql.getRows(query, [this.revisionId, attachmentId]) | ||||||
|  |             .map(row => new BAttachment(row))[0]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {BAttachment[]} */ | ||||||
|  |     getAttachmentsByRole(role) { | ||||||
|  |         return sql.getRows(` | ||||||
|  |                 SELECT attachments.* | ||||||
|  |                 FROM attachments  | ||||||
|  |                 WHERE ownerId = ?  | ||||||
|  |                   AND role = ? | ||||||
|  |                   AND isDeleted = 0 | ||||||
|  |                 ORDER BY position`, [this.revisionId, role]) | ||||||
|  |             .map(row => new BAttachment(row)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {BAttachment} */ | ||||||
|  |     getAttachmentByTitle(title) { | ||||||
|  |         return sql.getRows(` | ||||||
|  |                 SELECT attachments.* | ||||||
|  |                 FROM attachments  | ||||||
|  |                 WHERE ownerId = ?  | ||||||
|  |                   AND title = ? | ||||||
|  |                   AND isDeleted = 0 | ||||||
|  |                 ORDER BY position`, [this.revisionId, title]) | ||||||
|  |             .map(row => new BAttachment(row))[0]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     beforeSaving() { |     beforeSaving() { | ||||||
|         super.beforeSaving(); |         super.beforeSaving(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -127,7 +127,8 @@ paths: | |||||||
|             - targetRelationCount |             - targetRelationCount | ||||||
|             - targetRelationCountIncludingLinks |             - targetRelationCountIncludingLinks | ||||||
|             - contentSize |             - contentSize | ||||||
|             - noteSize |             - contentAndAttachmentsSize | ||||||
|  |             - contentAndAttachmentsAndRevisionsSize | ||||||
|             - revisionCount |             - revisionCount | ||||||
|         - name: orderDirection |         - name: orderDirection | ||||||
|           in: query |           in: query | ||||||
|   | |||||||
| @@ -32,8 +32,8 @@ export default class LauncherContextMenu { | |||||||
|         const isVisibleItem = parentNoteId === '_lbVisibleLaunchers'; |         const isVisibleItem = parentNoteId === '_lbVisibleLaunchers'; | ||||||
|         const isAvailableItem = parentNoteId === '_lbAvailableLaunchers'; |         const isAvailableItem = parentNoteId === '_lbAvailableLaunchers'; | ||||||
|         const isItem = isVisibleItem || isAvailableItem; |         const isItem = isVisibleItem || isAvailableItem; | ||||||
|         const canBeDeleted = !note.isLaunchBarConfig(); |         const canBeDeleted = !note.noteId.startsWith("_"); // fixed notes can't be deleted | ||||||
|         const canBeReset = note.isLaunchBarConfig(); |         const canBeReset = !canBeDeleted && note.isLaunchBarConfig();; | ||||||
|  |  | ||||||
|         return [ |         return [ | ||||||
|             (isVisibleRoot || isAvailableRoot) ? { title: 'Add a note launcher', command: 'addNoteLauncher', uiIcon: "bx bx-plus" } : null, |             (isVisibleRoot || isAvailableRoot) ? { title: 'Add a note launcher', command: 'addNoteLauncher', uiIcon: "bx bx-plus" } : null, | ||||||
|   | |||||||
| @@ -252,11 +252,15 @@ class NoteListRenderer { | |||||||
|             if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(this.page - i) <= 2) { |             if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(this.page - i) <= 2) { | ||||||
|                 lastPrinted = true; |                 lastPrinted = true; | ||||||
|  |  | ||||||
|  |                 const startIndex = (i - 1) * this.pageSize + 1; | ||||||
|  |                 const endIndex = Math.min(this.noteIds.length, i * this.pageSize); | ||||||
|  |  | ||||||
|                 $pager.append( |                 $pager.append( | ||||||
|                     i === this.page |                     i === this.page | ||||||
|                         ? $('<span>').text(i).css('text-decoration', 'underline').css('font-weight', "bold") |                         ? $('<span>').text(i).css('text-decoration', 'underline').css('font-weight', "bold") | ||||||
|                         : $('<a href="javascript:">') |                         : $('<a href="javascript:">') | ||||||
|                             .text(i) |                             .text(i) | ||||||
|  |                             .attr("title", `Page of ${startIndex} - ${endIndex}`) | ||||||
|                             .on('click', () => { |                             .on('click', () => { | ||||||
|                                 this.page = i; |                                 this.page = i; | ||||||
|                                 this.renderList(); |                                 this.renderList(); | ||||||
| @@ -270,6 +274,9 @@ class NoteListRenderer { | |||||||
|                 lastPrinted = false; |                 lastPrinted = false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // no need to distinguish "note" vs "notes" since in case of one result, there's no paging at all | ||||||
|  |         $pager.append(`<span class="note-list-pager-total-count">(${this.noteIds.length} notes)</span>`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async renderNote(note, expand = false) { |     async renderNote(note, expand = false) { | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ const TPL = ` | |||||||
|         <a class="dropdown-item export-note-button">Export note</a> |         <a class="dropdown-item export-note-button">Export note</a> | ||||||
|         <a class="dropdown-item delete-note-button">Delete note</a> |         <a class="dropdown-item delete-note-button">Delete note</a> | ||||||
|         <a data-trigger-command="printActiveNote" class="dropdown-item print-active-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a> |         <a data-trigger-command="printActiveNote" class="dropdown-item print-active-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a> | ||||||
|  |         <a data-trigger-command="forceSaveRevision" class="dropdown-item save-revision-button"><kbd data-command="forceSaveRevision"></kbd> Save revision</a> | ||||||
|     </div> |     </div> | ||||||
| </div>`; | </div>`; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -274,26 +274,11 @@ export default class RevisionsDialog extends BasicWidget { | |||||||
|  |  | ||||||
|             this.$content.html($table); |             this.$content.html($table); | ||||||
|         } else if (revisionItem.type === 'canvas') { |         } else if (revisionItem.type === 'canvas') { | ||||||
|             /** |             const sanitizedTitle = revisionItem.title.replace(/[^a-z0-9-.]/gi, ""); | ||||||
|              * FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com |  | ||||||
|              *        REMOVE external dependency!!!! This is defined in the svg in defs.style |  | ||||||
|              */ |  | ||||||
|             const content = fullRevision.content; |  | ||||||
|  |  | ||||||
|             try { |             this.$content.html($("<img>") | ||||||
|                 const data = JSON.parse(content) |                 .attr("src", `api/revisions/${revisionItem.revisionId}/image/${sanitizedTitle}?${Math.random()}`) | ||||||
|                 const svg = data.svg || "no svg present." |                 .css("max-width", "100%")); | ||||||
|  |  | ||||||
|                 /** |  | ||||||
|                  * maxWidth: 100% use full width of container but do not enlarge! |  | ||||||
|                  * height:auto to ensure that height scales with width |  | ||||||
|                  */ |  | ||||||
|                 const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"}); |  | ||||||
|                 this.$content.html($('<div>').append($svgHtml)); |  | ||||||
|             } catch (err) { |  | ||||||
|                 console.error("error parsing fullRevision.content as JSON", fullRevision.content, err); |  | ||||||
|                 this.$content.html($("<div>").text("Error parsing content. Please check console.error() for more details.")); |  | ||||||
|             } |  | ||||||
|         } else { |         } else { | ||||||
|             this.$content.text("Preview isn't available for this note type."); |             this.$content.text("Preview isn't available for this note type."); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -14,7 +14,8 @@ const TPL = ` | |||||||
|             <option value="dateCreated">Date created</option> |             <option value="dateCreated">Date created</option> | ||||||
|             <option value="dateModified">Date of last modification</option> |             <option value="dateModified">Date of last modification</option> | ||||||
|             <option value="contentSize">Note content size</option> |             <option value="contentSize">Note content size</option> | ||||||
|             <option value="noteSize">Note content size including revisions</option> |             <option value="contentAndAttachmentsSize">Note content size including attachments</option> | ||||||
|  |             <option value="contentAndAttachmentsAndRevisionsSize">Note content size including attachments and revisions</option> | ||||||
|             <option value="revisionCount">Number of revisions</option> |             <option value="revisionCount">Number of revisions</option> | ||||||
|             <option value="childrenCount">Number of children notes</option> |             <option value="childrenCount">Number of children notes</option> | ||||||
|             <option value="parentCount">Number of clones</option> |             <option value="parentCount">Number of clones</option> | ||||||
|   | |||||||
| @@ -209,7 +209,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | |||||||
|                 }; |                 }; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             const {elements, files, appState} = content; |             const {elements, files, appState = {}} = content; | ||||||
|  |  | ||||||
|             appState.theme = this.themeStyle; |             appState.theme = this.themeStyle; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,14 +5,27 @@ const becca = require('../../becca/becca'); | |||||||
| const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR; | const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR; | ||||||
| const fs = require('fs'); | const fs = require('fs'); | ||||||
|  |  | ||||||
| function returnImage(req, res) { | function returnImageFromNote(req, res) { | ||||||
|     const image = becca.getNote(req.params.noteId); |     const image = becca.getNote(req.params.noteId); | ||||||
|  |  | ||||||
|  |     return returnImageInt(image, res); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function returnImageFromRevision(req, res) { | ||||||
|  |     const image = becca.getRevision(req.params.revisionId); | ||||||
|  |  | ||||||
|  |     return returnImageInt(image, res); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @param {BNote|BRevision} image | ||||||
|  |  * @param res | ||||||
|  |  */ | ||||||
|  | function returnImageInt(image, res) { | ||||||
|     if (!image) { |     if (!image) { | ||||||
|         res.set('Content-Type', 'image/png'); |         res.set('Content-Type', 'image/png'); | ||||||
|         return res.send(fs.readFileSync(`${RESOURCE_DIR}/db/image-deleted.png`)); |         return res.send(fs.readFileSync(`${RESOURCE_DIR}/db/image-deleted.png`)); | ||||||
|     } |     } else if (!["image", "canvas"].includes(image.type)) { | ||||||
|     else if (!["image", "canvas"].includes(image.type)){ |  | ||||||
|         return res.sendStatus(400); |         return res.sendStatus(400); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -84,7 +97,8 @@ function updateImage(req) { | |||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     returnImage, |     returnImageFromNote, | ||||||
|  |     returnImageFromRevision, | ||||||
|     returnAttachedImage, |     returnAttachedImage, | ||||||
|     updateImage |     updateImage | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -181,6 +181,8 @@ function register(app) { | |||||||
|     apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob); |     apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob); | ||||||
|     apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision); |     apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision); | ||||||
|     apiRoute(PST, '/api/revisions/:revisionId/restore', revisionsApiRoute.restoreRevision); |     apiRoute(PST, '/api/revisions/:revisionId/restore', revisionsApiRoute.restoreRevision); | ||||||
|  |     route(GET, '/api/revisions/:revisionId/image/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImageFromRevision); | ||||||
|  |  | ||||||
|     route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision); |     route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -200,7 +202,7 @@ function register(app) { | |||||||
|     apiRoute(GET, '/api/attribute-values/:attributeName', attributesRoute.getValuesForAttribute); |     apiRoute(GET, '/api/attribute-values/:attributeName', attributesRoute.getValuesForAttribute); | ||||||
|  |  | ||||||
|     // :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename |     // :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename | ||||||
|     route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage); |     route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImageFromNote); | ||||||
|     route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], imageRoute.updateImage, apiResultHandler); |     route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], imageRoute.updateImage, apiResultHandler); | ||||||
|  |  | ||||||
|     apiRoute(GET, '/api/options', optionsApiRoute.getOptions); |     apiRoute(GET, '/api/options', optionsApiRoute.getOptions); | ||||||
|   | |||||||
| @@ -7,8 +7,9 @@ const sql = require("./sql"); | |||||||
|  |  | ||||||
| function getFullAnonymizationScript() { | function getFullAnonymizationScript() { | ||||||
|     // we want to delete all non-builtin attributes because they can contain sensitive names and values |     // we want to delete all non-builtin attributes because they can contain sensitive names and values | ||||||
| // on the other hand builtin/system attrs should not contain any sensitive info |     // on the other hand builtin/system attrs should not contain any sensitive info | ||||||
|     const builtinAttrNames = BUILTIN_ATTRIBUTES |     const builtinAttrNames = BUILTIN_ATTRIBUTES | ||||||
|  |         .filter(attr => !["shareCredentials", "shareAlias"].includes(attr.name)) | ||||||
|         .map(attr => `'${attr.name}'`).join(', '); |         .map(attr => `'${attr.name}'`).join(', '); | ||||||
|  |  | ||||||
|     const anonymizeScript = ` |     const anonymizeScript = ` | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ const build = require('./build'); | |||||||
| const packageJson = require('../../package'); | const packageJson = require('../../package'); | ||||||
| const {TRILIUM_DATA_DIR} = require('./data_dir'); | const {TRILIUM_DATA_DIR} = require('./data_dir'); | ||||||
|  |  | ||||||
| const APP_DB_VERSION = 225; | const APP_DB_VERSION = 226; | ||||||
| const SYNC_VERSION = 31; | const SYNC_VERSION = 31; | ||||||
| const CLIPPER_PROTOCOL_VERSION = "1.0"; | const CLIPPER_PROTOCOL_VERSION = "1.0"; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| module.exports = { buildDate:"2023-09-29T00:54:45+02:00", buildRevision: "e5555beea9a1638fefa218118e0596f4cfc1f4d0" }; | module.exports = { buildDate:"2023-10-07T23:02:47+03:00", buildRevision: "3d15aeae58224ac8716dd58938458e89af9bf7a0" }; | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ const BBranch = require('../becca/entities/bbranch'); | |||||||
| const becca = require("../becca/becca"); | const becca = require("../becca/becca"); | ||||||
| const log = require("./log"); | const log = require("./log"); | ||||||
|  |  | ||||||
| function cloneNoteToParentNote(noteId, parentNoteId, prefix) { | function cloneNoteToParentNote(noteId, parentNoteId, prefix = null) { | ||||||
|     if (!(noteId in becca.notes) || !(parentNoteId in becca.notes)) { |     if (!(noteId in becca.notes) || !(parentNoteId in becca.notes)) { | ||||||
|         return { success: false, message: 'Note cannot be cloned because either the cloned note or the intended parent is deleted.' }; |         return { success: false, message: 'Note cannot be cloned because either the cloned note or the intended parent is deleted.' }; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -327,6 +327,11 @@ async function importZip(taskContext, fileBuffer, importRootNote) { | |||||||
|         content = content.replace(/<\/body>.*<\/html>/gis, ""); |         content = content.replace(/<\/body>.*<\/html>/gis, ""); | ||||||
|  |  | ||||||
|         content = content.replace(/src="([^"]*)"/g, (match, url) => { |         content = content.replace(/src="([^"]*)"/g, (match, url) => { | ||||||
|  |             if (url.startsWith("data:image")) { | ||||||
|  |                 // inline images are parsed and saved into attachments in the note service | ||||||
|  |                 return match; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             try { |             try { | ||||||
|                 url = decodeURIComponent(url).trim(); |                 url = decodeURIComponent(url).trim(); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|   | |||||||
| @@ -56,9 +56,9 @@ class OrderByAndLimitExp extends Expression { | |||||||
|                 if (!valA && !valB) { |                 if (!valA && !valB) { | ||||||
|                     // the attribute value is empty/zero in both notes so continue to the next order definition |                     // the attribute value is empty/zero in both notes so continue to the next order definition | ||||||
|                     continue; |                     continue; | ||||||
|                 } else if (!valB || valA < valB) { |                 } else if (valA < valB) { | ||||||
|                     return smaller; |                     return smaller; | ||||||
|                 } else if (!valA || valA > valB) { |                 } else if (valA > valB) { | ||||||
|                     return larger; |                     return larger; | ||||||
|                 } |                 } | ||||||
|                 // else the values are equal and continue to next order definition |                 // else the values are equal and continue to next order definition | ||||||
|   | |||||||
| @@ -31,7 +31,8 @@ const PROP_MAPPING = { | |||||||
|     "targetrelationcount": "targetRelationCount", |     "targetrelationcount": "targetRelationCount", | ||||||
|     "targetrelationcountincludinglinks": "targetRelationCountIncludingLinks", |     "targetrelationcountincludinglinks": "targetRelationCountIncludingLinks", | ||||||
|     "contentsize": "contentSize", |     "contentsize": "contentSize", | ||||||
|     "notesize": "noteSize", |     "contentandattachmentssize": "contentAndAttachmentsSize", | ||||||
|  |     "contentandattachmentsandrevisionssize": "contentAndAttachmentsAndRevisionsSize", | ||||||
|     "revisioncount": "revisionCount" |     "revisioncount": "revisionCount" | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -48,7 +49,7 @@ class PropertyComparisonExp extends Expression { | |||||||
|         this.comparedValue = comparedValue; // for DEBUG mode |         this.comparedValue = comparedValue; // for DEBUG mode | ||||||
|         this.comparator = buildComparator(operator, comparedValue); |         this.comparator = buildComparator(operator, comparedValue); | ||||||
|  |  | ||||||
|         if (['contentsize', 'notesize', 'revisioncount'].includes(this.propertyName)) { |         if (['contentsize', 'contentandattachmentssize', 'contentandattachmentsandrevisionssize', 'revisioncount'].includes(this.propertyName)) { | ||||||
|             searchContext.dbLoadNeeded = true; |             searchContext.dbLoadNeeded = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -92,48 +92,108 @@ function searchFromRelation(note, relationName) { | |||||||
| function loadNeededInfoFromDatabase() { | function loadNeededInfoFromDatabase() { | ||||||
|     const sql = require('../../sql'); |     const sql = require('../../sql'); | ||||||
|  |  | ||||||
|     for (const noteId in becca.notes) { |     /** | ||||||
|         becca.notes[noteId].contentSize = 0; |      * This complex structure is needed to calculate total occupied space by a note. Several object instances | ||||||
|         becca.notes[noteId].noteSize = 0; |      * (note, revisions, attachments) can point to a single blobId, and thus the blob size should count towards the total | ||||||
|         becca.notes[noteId].revisionCount = 0; |      * only once. | ||||||
|     } |      * | ||||||
|  |      * @var {Object.<string, Object.<string, int>>} - noteId => { blobId => blobSize } | ||||||
|  |      */ | ||||||
|  |     const noteBlobs = {}; | ||||||
|  |  | ||||||
|     const noteContentLengths = sql.getRows(` |     const noteContentLengths = sql.getRows(` | ||||||
|         SELECT  |         SELECT  | ||||||
|             noteId,  |             noteId,  | ||||||
|  |             blobId, | ||||||
|             LENGTH(content) AS length  |             LENGTH(content) AS length  | ||||||
|         FROM notes |         FROM notes | ||||||
|              JOIN blobs USING(blobId)  |              JOIN blobs USING(blobId)  | ||||||
|         WHERE notes.isDeleted = 0`); |         WHERE notes.isDeleted = 0`); | ||||||
|  |  | ||||||
|     for (const {noteId, length} of noteContentLengths) { |     for (const {noteId, blobId, length} of noteContentLengths) { | ||||||
|         if (!(noteId in becca.notes)) { |         if (!(noteId in becca.notes)) { | ||||||
|             log.error(`Note ${noteId} not found in becca.`); |             log.error(`Note '${noteId}' not found in becca.`); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         becca.notes[noteId].contentSize = length; |         becca.notes[noteId].contentSize = length; | ||||||
|         becca.notes[noteId].noteSize = length; |         becca.notes[noteId].revisionCount = 0; | ||||||
|  |  | ||||||
|  |         noteBlobs[noteId] = { [blobId]: length }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const attachmentContentLengths = sql.getRows(` | ||||||
|  |         SELECT | ||||||
|  |             ownerId AS noteId, | ||||||
|  |             attachments.blobId, | ||||||
|  |             LENGTH(content) AS length | ||||||
|  |         FROM attachments | ||||||
|  |             JOIN notes ON attachments.ownerId = notes.noteId | ||||||
|  |             JOIN blobs ON attachments.blobId = blobs.blobId | ||||||
|  |         WHERE attachments.isDeleted = 0  | ||||||
|  |             AND notes.isDeleted = 0`); | ||||||
|  |  | ||||||
|  |     for (const {noteId, blobId, length} of attachmentContentLengths) { | ||||||
|  |         if (!(noteId in becca.notes)) { | ||||||
|  |             log.error(`Note '${noteId}' not found in becca.`); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!(noteId in noteBlobs)) { | ||||||
|  |             log.error(`Did not find a '${noteId}' in the noteBlobs.`); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         noteBlobs[noteId][blobId] = length; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (const noteId in noteBlobs) { | ||||||
|  |         becca.notes[noteId].contentAndAttachmentsSize = Object.values(noteBlobs[noteId]).reduce((acc, size) => acc + size, 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const revisionContentLengths = sql.getRows(` |     const revisionContentLengths = sql.getRows(` | ||||||
|             SELECT  |             SELECT  | ||||||
|                 noteId,  |                 noteId,  | ||||||
|             LENGTH(content) AS length  |                 revisions.blobId, | ||||||
|  |                 LENGTH(content) AS length, | ||||||
|  |                 1 AS isNoteRevision | ||||||
|             FROM notes |             FROM notes | ||||||
|                 JOIN revisions USING(noteId)  |                 JOIN revisions USING(noteId)  | ||||||
|              JOIN blobs USING(blobId)  |                 JOIN blobs ON revisions.blobId = blobs.blobId | ||||||
|  |             WHERE notes.isDeleted = 0 | ||||||
|  |         UNION ALL | ||||||
|  |             SELECT | ||||||
|  |                 noteId, | ||||||
|  |                 revisions.blobId, | ||||||
|  |                 LENGTH(content) AS length, | ||||||
|  |                 0 AS isNoteRevision -- it's attachment not counting towards revision count | ||||||
|  |             FROM notes | ||||||
|  |                 JOIN revisions USING(noteId) | ||||||
|  |                 JOIN attachments ON attachments.ownerId = revisions.revisionId | ||||||
|  |                 JOIN blobs ON attachments.blobId = blobs.blobId | ||||||
|             WHERE notes.isDeleted = 0`); |             WHERE notes.isDeleted = 0`); | ||||||
|  |  | ||||||
|     for (const {noteId, length} of revisionContentLengths) { |     for (const {noteId, blobId, length, isNoteRevision} of revisionContentLengths) { | ||||||
|         if (!(noteId in becca.notes)) { |         if (!(noteId in becca.notes)) { | ||||||
|             log.error(`Note ${noteId} not found in becca.`); |             log.error(`Note '${noteId}' not found in becca.`); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         becca.notes[noteId].noteSize += length; |         if (!(noteId in noteBlobs)) { | ||||||
|  |             log.error(`Did not find a '${noteId}' in the noteBlobs.`); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         noteBlobs[noteId][blobId] = length; | ||||||
|  |  | ||||||
|  |         if (isNoteRevision) { | ||||||
|             becca.notes[noteId].revisionCount++; |             becca.notes[noteId].revisionCount++; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (const noteId in noteBlobs) { | ||||||
|  |         becca.notes[noteId].contentAndAttachmentsAndRevisionsSize = Object.values(noteBlobs[noteId]).reduce((acc, size) => acc + size, 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -27,7 +27,8 @@ const PROP_MAPPING = { | |||||||
|     "targetrelationcount": "targetRelationCount", |     "targetrelationcount": "targetRelationCount", | ||||||
|     "targetrelationcountincludinglinks": "targetRelationCountIncludingLinks", |     "targetrelationcountincludinglinks": "targetRelationCountIncludingLinks", | ||||||
|     "contentsize": "contentSize", |     "contentsize": "contentSize", | ||||||
|     "notesize": "noteSize", |     "contentandattachmentssize": "contentAndAttachmentsSize", | ||||||
|  |     "contentandattachmentsandrevisionssize": "contentAndAttachmentsAndRevisionsSize", | ||||||
|     "revisioncount": "revisionCount" |     "revisioncount": "revisionCount" | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -42,7 +43,7 @@ class ValueExtractor { | |||||||
|             this.propertyPath = ['note', 'relations', this.propertyPath[0].substr(1), ...this.propertyPath.slice(1, this.propertyPath.length)]; |             this.propertyPath = ['note', 'relations', this.propertyPath[0].substr(1), ...this.propertyPath.slice(1, this.propertyPath.length)]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (['contentsize', 'notesize', 'revisioncount'].includes(this.propertyPath[this.propertyPath.length - 1])) { |         if (['contentsize', 'contentandattachmentssize', 'contentandattachmentsandrevisionssize', 'revisioncount'].includes(this.propertyPath[this.propertyPath.length - 1])) { | ||||||
|             searchContext.dbLoadNeeded = true; |             searchContext.dbLoadNeeded = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -151,10 +151,15 @@ async function pullChanges(syncContext) { | |||||||
|         if (entityChanges.length === 0) { |         if (entityChanges.length === 0) { | ||||||
|             break; |             break; | ||||||
|         } else { |         } else { | ||||||
|  |             try { // https://github.com/zadam/trilium/issues/4310 | ||||||
|                 const sizeInKb = Math.round(JSON.stringify(resp).length / 1024); |                 const sizeInKb = Math.round(JSON.stringify(resp).length / 1024); | ||||||
|  |  | ||||||
|                 log.info(`Sync ${logMarkerId}: Pulled ${entityChanges.length} changes in ${sizeInKb} KB, starting at entityChangeId=${lastSyncedPull} in ${pulledDate - startDate}ms and applied them in ${Date.now() - pulledDate}ms, ${outstandingPullCount} outstanding pulls`); |                 log.info(`Sync ${logMarkerId}: Pulled ${entityChanges.length} changes in ${sizeInKb} KB, starting at entityChangeId=${lastSyncedPull} in ${pulledDate - startDate}ms and applied them in ${Date.now() - pulledDate}ms, ${outstandingPullCount} outstanding pulls`); | ||||||
|             } |             } | ||||||
|  |             catch (e) { | ||||||
|  |                 log.error(`Error occurred ${e.message} ${e.stack}`); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     log.info("Finished pull"); |     log.info("Finished pull"); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user