mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	etapi improvements and more tests
This commit is contained in:
		| @@ -53,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, | ||||
| @@ -66,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 | ||||
| ); | ||||
|   | ||||
							
								
								
									
										301
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										301
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "trilium", | ||||
|   "version": "0.49.3", | ||||
|   "version": "0.49.4", | ||||
|   "lockfileVersion": 1, | ||||
|   "requires": true, | ||||
|   "dependencies": { | ||||
| @@ -546,9 +546,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@npmcli/fs": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.0.0.tgz", | ||||
|       "integrity": "sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ==", | ||||
|       "version": "1.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.0.tgz", | ||||
|       "integrity": "sha512-VhP1qZLXcrXRIaPoqb4YA55JQxLNF3jNR4T55IdOJa3+IFJKNYHtPvtXx8slmeMavj37vCzCfrqQM1vWLsYKLA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@gar/promisify": "^1.0.1", | ||||
| @@ -989,9 +989,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "agentkeepalive": { | ||||
|       "version": "4.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", | ||||
|       "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", | ||||
|       "version": "4.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.0.tgz", | ||||
|       "integrity": "sha512-0PhAp58jZNw13UJv7NVdTGb0ZcghHUb3DrZ046JiiJY/BOaTTpbwdHq2VObPCBV8M2GPh7sgrJ3AQ8Ey468LJw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "debug": "^4.1.0", | ||||
| @@ -1466,33 +1466,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", | ||||
|       "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" | ||||
|     }, | ||||
|     "body-parser": { | ||||
|       "version": "1.19.1", | ||||
|       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", | ||||
|       "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", | ||||
|       "requires": { | ||||
|         "bytes": "3.1.1", | ||||
|         "content-type": "~1.0.4", | ||||
|         "debug": "2.6.9", | ||||
|         "depd": "~1.1.2", | ||||
|         "http-errors": "1.8.1", | ||||
|         "iconv-lite": "0.4.24", | ||||
|         "on-finished": "~2.3.0", | ||||
|         "qs": "6.9.6", | ||||
|         "raw-body": "2.4.2", | ||||
|         "type-is": "~1.6.18" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "debug": { | ||||
|           "version": "2.6.9", | ||||
|           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", | ||||
|           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", | ||||
|           "requires": { | ||||
|             "ms": "2.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "boolbase": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", | ||||
| @@ -1829,11 +1802,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "bytes": { | ||||
|       "version": "3.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", | ||||
|       "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" | ||||
|     }, | ||||
|     "cacache": { | ||||
|       "version": "15.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", | ||||
| @@ -2224,18 +2192,18 @@ | ||||
|       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", | ||||
|       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" | ||||
|     }, | ||||
|     "color-support": { | ||||
|       "version": "1.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", | ||||
|       "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "colorette": { | ||||
|       "version": "2.0.16", | ||||
|       "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", | ||||
|       "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "colors": { | ||||
|       "version": "1.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", | ||||
|       "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "combined-stream": { | ||||
|       "version": "1.0.8", | ||||
|       "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | ||||
| @@ -2909,9 +2877,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "electron": { | ||||
|       "version": "16.0.6", | ||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-16.0.6.tgz", | ||||
|       "integrity": "sha512-Xs9dYLYhcJf3wXn8m2gDqFTb1L862KEhMxOx9swfFBHj6NoUPPtUgw/RyPQ0tXN1XPxG9vnBkoI0BdcKwrLKuQ==", | ||||
|       "version": "16.0.7", | ||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-16.0.7.tgz", | ||||
|       "integrity": "sha512-/IMwpBf2svhA1X/7Q58RV+Nn0fvUJsHniG4TizaO7q4iKFYSQ6hBvsLz+cylcZ8hRMKmVy5G1XaMNJID2ah23w==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@electron/get": "^1.13.0", | ||||
| @@ -2937,9 +2905,9 @@ | ||||
|           } | ||||
|         }, | ||||
|         "@types/node": { | ||||
|           "version": "14.18.1", | ||||
|           "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.1.tgz", | ||||
|           "integrity": "sha512-fTFWOFrgAkj737w1o0HLTIgisgYHnsZfeiqhG1Ltrf/iJjudEbUwetQAsfrtVE49JGwvpEzQR+EbMkIqG4227g==", | ||||
|           "version": "14.18.5", | ||||
|           "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.5.tgz", | ||||
|           "integrity": "sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "boolean": { | ||||
| @@ -3554,18 +3522,18 @@ | ||||
|       } | ||||
|     }, | ||||
|     "electron-rebuild": { | ||||
|       "version": "3.2.5", | ||||
|       "resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-3.2.5.tgz", | ||||
|       "integrity": "sha512-U9dKi10V9w/BdIVB8a8dTKYLK3Q1d2WZ+Yo5qfM3XX/O4jI7KpnwgvWgGoVv0jTWPC2NlebF00ffWS/8NfUAtA==", | ||||
|       "version": "3.2.7", | ||||
|       "resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-3.2.7.tgz", | ||||
|       "integrity": "sha512-WvaW1EgRinDQ61khHFZfx30rkPQG5ItaOT0wrI7iJv9A3SbghriQGfZQfHZs25fWLBe6/vkv05LOqg6aDw6Wzw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@malept/cross-spawn-promise": "^2.0.0", | ||||
|         "colors": "^1.3.3", | ||||
|         "chalk": "^4.0.0", | ||||
|         "debug": "^4.1.1", | ||||
|         "detect-libc": "^1.0.3", | ||||
|         "fs-extra": "^10.0.0", | ||||
|         "got": "^11.7.0", | ||||
|         "lzma-native": "^8.0.1", | ||||
|         "lzma-native": "^8.0.5", | ||||
|         "node-abi": "^3.0.0", | ||||
|         "node-api-version": "^0.1.4", | ||||
|         "node-gyp": "^8.4.0", | ||||
| @@ -3585,9 +3553,9 @@ | ||||
|           } | ||||
|         }, | ||||
|         "@sindresorhus/is": { | ||||
|           "version": "4.2.0", | ||||
|           "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", | ||||
|           "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==", | ||||
|           "version": "4.2.1", | ||||
|           "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.1.tgz", | ||||
|           "integrity": "sha512-BrzrgtaqEre0qfvI8sMTaEvx+bayuhPmfe2rfeUGPPHYr/PLxCOqkOe4TQTDPb+qcqgNcsAtXV/Ew74mcDIE8w==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "@szmarczak/http-timer": { | ||||
| @@ -3599,6 +3567,15 @@ | ||||
|             "defer-to-connect": "^2.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "ansi-styles": { | ||||
|           "version": "4.3.0", | ||||
|           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", | ||||
|           "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "color-convert": "^2.0.1" | ||||
|           } | ||||
|         }, | ||||
|         "cacheable-request": { | ||||
|           "version": "7.0.2", | ||||
|           "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", | ||||
| @@ -3614,6 +3591,31 @@ | ||||
|             "responselike": "^2.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "chalk": { | ||||
|           "version": "4.1.2", | ||||
|           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", | ||||
|           "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "ansi-styles": "^4.1.0", | ||||
|             "supports-color": "^7.1.0" | ||||
|           } | ||||
|         }, | ||||
|         "color-convert": { | ||||
|           "version": "2.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", | ||||
|           "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "color-name": "~1.1.4" | ||||
|           } | ||||
|         }, | ||||
|         "color-name": { | ||||
|           "version": "1.1.4", | ||||
|           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", | ||||
|           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "decompress-response": { | ||||
|           "version": "6.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", | ||||
| @@ -3639,9 +3641,9 @@ | ||||
|           } | ||||
|         }, | ||||
|         "got": { | ||||
|           "version": "11.8.2", | ||||
|           "resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", | ||||
|           "integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", | ||||
|           "version": "11.8.3", | ||||
|           "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", | ||||
|           "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "@sindresorhus/is": "^4.0.0", | ||||
| @@ -3649,7 +3651,7 @@ | ||||
|             "@types/cacheable-request": "^6.0.1", | ||||
|             "@types/responselike": "^1.0.0", | ||||
|             "cacheable-lookup": "^5.0.3", | ||||
|             "cacheable-request": "^7.0.1", | ||||
|             "cacheable-request": "^7.0.2", | ||||
|             "decompress-response": "^6.0.0", | ||||
|             "http2-wrapper": "^1.0.0-beta.5.2", | ||||
|             "lowercase-keys": "^2.0.0", | ||||
| @@ -3664,9 +3666,9 @@ | ||||
|           "dev": true | ||||
|         }, | ||||
|         "keyv": { | ||||
|           "version": "4.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz", | ||||
|           "integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==", | ||||
|           "version": "4.0.5", | ||||
|           "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.5.tgz", | ||||
|           "integrity": "sha512-531pkGLqV3BMg0eDqqJFI0R1mkK1Nm5xIP2mM6keP5P8WfFtCkg2IOwplTUmlGoTgIg9yQYZ/kdihhz89XH3vA==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "json-buffer": "3.0.1" | ||||
| @@ -4092,9 +4094,9 @@ | ||||
|       "integrity": "sha512-o1JrraDGpMFaPtkuvtZ4cIBC/xuJn90KBGlxRrm3FxcfER1bPaBnBsTnypF65p+CMTXul2KrZodb3Vv3MScB4A==" | ||||
|     }, | ||||
|     "express-rate-limit": { | ||||
|       "version": "6.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.0.5.tgz", | ||||
|       "integrity": "sha512-EB1mRTrzyyPfEsQZIQFXocd8NKZoDZbEwrtbdgkc20Yed6oYg02Xfjza2HHPI/0orp54BrFeHeT92ICB9ydokw==" | ||||
|       "version": "6.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.1.0.tgz", | ||||
|       "integrity": "sha512-OWyJUDYVq/hRxGU3ufTnXDer5bRBwFiq5D35ZSZ9B2EHdjulWO4bwrbg+iIrapodDZse/35obeOj7igRHuP3Zw==" | ||||
|     }, | ||||
|     "express-session": { | ||||
|       "version": "1.17.2", | ||||
| @@ -4770,35 +4772,6 @@ | ||||
|       "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "http-errors": { | ||||
|       "version": "1.8.1", | ||||
|       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", | ||||
|       "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", | ||||
|       "requires": { | ||||
|         "depd": "~1.1.2", | ||||
|         "inherits": "2.0.4", | ||||
|         "setprototypeof": "1.2.0", | ||||
|         "statuses": ">= 1.5.0 < 2", | ||||
|         "toidentifier": "1.0.1" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "inherits": { | ||||
|           "version": "2.0.4", | ||||
|           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | ||||
|           "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" | ||||
|         }, | ||||
|         "setprototypeof": { | ||||
|           "version": "1.2.0", | ||||
|           "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", | ||||
|           "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" | ||||
|         }, | ||||
|         "toidentifier": { | ||||
|           "version": "1.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", | ||||
|           "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "http-proxy-agent": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", | ||||
| @@ -5183,9 +5156,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "jasmine": { | ||||
|       "version": "4.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-4.0.1.tgz", | ||||
|       "integrity": "sha512-NAf9b80ie0pAXLW2l+Fxc8s0Q6SjVgi81jOyHJRQuZ+fPjbVAnXNfN2nIwf5yoRjoSTROyRiETjr9Cr+nNBTVw==", | ||||
|       "version": "4.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-4.0.2.tgz", | ||||
|       "integrity": "sha512-YsrgxJQEggxzByYe4j68eQLOiQeSrPDYGv4sHhGBp3c6HHdq+uPXeAQ73kOAQpdLZ3/0zN7x/TZTloqeE1/qIA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "glob": "^7.1.6", | ||||
| @@ -5678,9 +5651,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "lzma-native": { | ||||
|       "version": "8.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.1.tgz", | ||||
|       "integrity": "sha512-Ryr9X3yDVZhRYOxR8QhUBCNe6GdEfy9BvFDIFtUvEkocvSvnrYt9lRm6FR1z0eQn0QSMenrgrDIJRMgUf9zsKQ==", | ||||
|       "version": "8.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.5.tgz", | ||||
|       "integrity": "sha512-lEkBBmePuYBycdlK8ul/sKQuZW47FMxAdjeTgDZLY4duX5Q067JJLUueyzN0wCAw6t2Y6YXCcAqHA5A1jQ9ttQ==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "node-addon-api": "^3.1.0", | ||||
| @@ -6050,9 +6023,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node-gyp": { | ||||
|       "version": "8.4.0", | ||||
|       "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.0.tgz", | ||||
|       "integrity": "sha512-Bi/oCm5bH6F+FmzfUxJpPaxMEyIhszULGR3TprmTeku8/dMFcdTcypk120NeZqEt54r1BrgEKtm2jJiuIKE28Q==", | ||||
|       "version": "8.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", | ||||
|       "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "env-paths": "^2.2.0", | ||||
| @@ -6060,11 +6033,95 @@ | ||||
|         "graceful-fs": "^4.2.6", | ||||
|         "make-fetch-happen": "^9.1.0", | ||||
|         "nopt": "^5.0.0", | ||||
|         "npmlog": "^4.1.2", | ||||
|         "npmlog": "^6.0.0", | ||||
|         "rimraf": "^3.0.2", | ||||
|         "semver": "^7.3.5", | ||||
|         "tar": "^6.1.2", | ||||
|         "which": "^2.0.2" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "ansi-regex": { | ||||
|           "version": "5.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", | ||||
|           "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "are-we-there-yet": { | ||||
|           "version": "2.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", | ||||
|           "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "delegates": "^1.0.0", | ||||
|             "readable-stream": "^3.6.0" | ||||
|           } | ||||
|         }, | ||||
|         "gauge": { | ||||
|           "version": "4.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", | ||||
|           "integrity": "sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "ansi-regex": "^5.0.1", | ||||
|             "aproba": "^1.0.3 || ^2.0.0", | ||||
|             "color-support": "^1.1.2", | ||||
|             "console-control-strings": "^1.0.0", | ||||
|             "has-unicode": "^2.0.1", | ||||
|             "signal-exit": "^3.0.0", | ||||
|             "string-width": "^4.2.3", | ||||
|             "strip-ansi": "^6.0.1", | ||||
|             "wide-align": "^1.1.2" | ||||
|           } | ||||
|         }, | ||||
|         "is-fullwidth-code-point": { | ||||
|           "version": "3.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", | ||||
|           "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", | ||||
|           "dev": true | ||||
|         }, | ||||
|         "npmlog": { | ||||
|           "version": "6.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", | ||||
|           "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "are-we-there-yet": "^2.0.0", | ||||
|             "console-control-strings": "^1.1.0", | ||||
|             "gauge": "^4.0.0", | ||||
|             "set-blocking": "^2.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "readable-stream": { | ||||
|           "version": "3.6.0", | ||||
|           "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", | ||||
|           "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "inherits": "^2.0.3", | ||||
|             "string_decoder": "^1.1.1", | ||||
|             "util-deprecate": "^1.0.1" | ||||
|           } | ||||
|         }, | ||||
|         "string-width": { | ||||
|           "version": "4.2.3", | ||||
|           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", | ||||
|           "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "emoji-regex": "^8.0.0", | ||||
|             "is-fullwidth-code-point": "^3.0.0", | ||||
|             "strip-ansi": "^6.0.1" | ||||
|           } | ||||
|         }, | ||||
|         "strip-ansi": { | ||||
|           "version": "6.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", | ||||
|           "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "ansi-regex": "^5.0.1" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node-gyp-build": { | ||||
| @@ -6739,11 +6796,6 @@ | ||||
|         "escape-goat": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "qs": { | ||||
|       "version": "6.9.6", | ||||
|       "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", | ||||
|       "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" | ||||
|     }, | ||||
|     "quick-lru": { | ||||
|       "version": "5.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", | ||||
| @@ -6774,17 +6826,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", | ||||
|       "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" | ||||
|     }, | ||||
|     "raw-body": { | ||||
|       "version": "2.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", | ||||
|       "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", | ||||
|       "requires": { | ||||
|         "bytes": "3.1.1", | ||||
|         "http-errors": "1.8.1", | ||||
|         "iconv-lite": "0.4.24", | ||||
|         "unpipe": "1.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "rc": { | ||||
|       "version": "1.2.8", | ||||
|       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", | ||||
| @@ -7452,9 +7493,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "socks-proxy-agent": { | ||||
|       "version": "6.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz", | ||||
|       "integrity": "sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg==", | ||||
|       "version": "6.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", | ||||
|       "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "agent-base": "^6.0.2", | ||||
| @@ -7463,9 +7504,9 @@ | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "debug": { | ||||
|           "version": "4.3.2", | ||||
|           "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", | ||||
|           "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", | ||||
|           "version": "4.3.3", | ||||
|           "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", | ||||
|           "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", | ||||
|           "dev": true, | ||||
|           "requires": { | ||||
|             "ms": "2.1.2" | ||||
|   | ||||
| @@ -28,7 +28,6 @@ | ||||
|     "async-mutex": "0.3.2", | ||||
|     "axios": "0.24.0", | ||||
|     "better-sqlite3": "7.4.5", | ||||
|     "body-parser": "1.19.1", | ||||
|     "chokidar": "3.5.2", | ||||
|     "cls-hooked": "4.2.2", | ||||
|     "commonmark": "0.30.0", | ||||
| @@ -43,7 +42,7 @@ | ||||
|     "@electron/remote": "2.0.1", | ||||
|     "express": "4.17.2", | ||||
|     "express-partial-content": "^1.0.2", | ||||
|     "express-rate-limit": "6.0.5", | ||||
|     "express-rate-limit": "6.1.0", | ||||
|     "express-session": "1.17.2", | ||||
|     "fs-extra": "10.0.0", | ||||
|     "helmet": "5.0.1", | ||||
| @@ -83,12 +82,12 @@ | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "cross-env": "7.0.3", | ||||
|     "electron": "16.0.6", | ||||
|     "electron": "16.0.7", | ||||
|     "electron-builder": "22.14.5", | ||||
|     "electron-packager": "15.4.0", | ||||
|     "electron-rebuild": "3.2.6", | ||||
|     "electron-rebuild": "3.2.7", | ||||
|     "esm": "3.2.25", | ||||
|     "jasmine": "4.0.1", | ||||
|     "jasmine": "4.0.2", | ||||
|     "jsdoc": "3.6.7", | ||||
|     "lorem-ipsum": "2.0.4", | ||||
|     "rcedit": "3.0.1", | ||||
|   | ||||
| @@ -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); | ||||
| @@ -20,13 +19,13 @@ 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.urlencoded({extended: false})); | ||||
| app.use(cookieParser()); | ||||
| app.use(express.static(path.join(__dirname, 'public'))); | ||||
| app.use('/libraries', express.static(path.join(__dirname, '..', 'libraries'))); | ||||
|   | ||||
| @@ -2,7 +2,6 @@ | ||||
|  | ||||
| const sql = require("../services/sql"); | ||||
| const NoteSet = require("../services/search/note_set"); | ||||
| const EtapiToken = require("./entities/etapi_token"); | ||||
|  | ||||
| /** | ||||
|  * Becca is a backend cache of all notes, branches and attributes. There's a similar frontend cache Froca. | ||||
|   | ||||
| @@ -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} */ | ||||
|   | ||||
| @@ -9,6 +9,9 @@ const sql = require("../../services/sql.js"); | ||||
|  * 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"; } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ const becca = require("../becca/becca"); | ||||
| const eu = require("./etapi_utils"); | ||||
| const mappers = require("./mappers"); | ||||
| const attributeService = require("../services/attributes"); | ||||
| const validators = require("./validators"); | ||||
| const v = require("./validators"); | ||||
|  | ||||
| function register(router) { | ||||
|     eu.route(router, 'get', '/etapi/attributes/:attributeId', (req, res, next) => { | ||||
| @@ -11,18 +11,23 @@ function register(router) { | ||||
|         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) => { | ||||
|         const params = req.body; | ||||
|  | ||||
|         eu.getAndCheckNote(params.noteId); | ||||
|  | ||||
|         if (params.type === 'relation') { | ||||
|             eu.getAndCheckNote(params.value); | ||||
|         if (req.body.type === 'relation') { | ||||
|             eu.getAndCheckNote(req.body.value); | ||||
|         } | ||||
|          | ||||
|         if (params.type !== 'relation' && params.type !== 'label') { | ||||
|             throw new eu.EtapiError(400, eu.GENERIC_CODE, `Only "relation" and "label" are supported attribute types, "${params.type}" given.`); | ||||
|         } | ||||
|         const params = {}; | ||||
|          | ||||
|         eu.validateAndPatch(params, req.body, ALLOWED_PROPERTIES_FOR_CREATE_ATTRIBUTE); | ||||
|  | ||||
|         try { | ||||
|             const attr = attributeService.createAttribute(params); | ||||
| @@ -30,19 +35,25 @@ function register(router) { | ||||
|             res.json(mappers.mapAttributeToPojo(attr)); | ||||
|         } | ||||
|         catch (e) { | ||||
|             throw new eu.EtapiError(400, eu.GENERIC_CODE, e.message); | ||||
|             throw new eu.EtapiError(500, eu.GENERIC_CODE, e.message); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     const ALLOWED_PROPERTIES_FOR_PATCH = { | ||||
|         'value': validators.isString | ||||
|         '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)); | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ const Branch = require("../becca/entities/branch"); | ||||
| const noteService = require("../services/notes"); | ||||
| const TaskContext = require("../services/task_context"); | ||||
| const entityChangesService = require("../services/entity_changes"); | ||||
| const validators = require("./validators"); | ||||
| const v = require("./validators"); | ||||
|  | ||||
| function register(router) { | ||||
|     eu.route(router, 'get', '/etapi/branches/:branchId', (req, res, next) => { | ||||
| @@ -14,11 +14,19 @@ function register(router) { | ||||
|         res.json(mappers.mapBranchToPojo(branch)); | ||||
|     }); | ||||
|  | ||||
|     eu.route(router, 'post' ,'/etapi/branches', (req, res, next) => { | ||||
|         const params = req.body; | ||||
|     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.getAndCheckNote(params.noteId); | ||||
|         eu.getAndCheckNote(params.parentNoteId); | ||||
|     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); | ||||
|  | ||||
| @@ -41,15 +49,16 @@ function register(router) { | ||||
|     }); | ||||
|  | ||||
|     const ALLOWED_PROPERTIES_FOR_PATCH = { | ||||
|         'notePosition': validators.isInteger, | ||||
|         'prefix': validators.isStringOrNull, | ||||
|         'isExpanded': validators.isBoolean | ||||
|         '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)); | ||||
|     }); | ||||
|   | ||||
| @@ -591,13 +591,15 @@ components: | ||||
|       type: object | ||||
|       required: | ||||
|         - parentNoteId | ||||
|         - type | ||||
|         - 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:  | ||||
| @@ -613,8 +615,6 @@ components: | ||||
|           type: string | ||||
|           description: this needs to be specified only for note types 'code', 'file', 'image'. | ||||
|           example: application/json | ||||
|         title: | ||||
|           type: string | ||||
|         content: | ||||
|           type: string | ||||
|         notePosition: | ||||
| @@ -628,6 +628,9 @@ components: | ||||
|             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 | ||||
| @@ -644,7 +647,7 @@ components: | ||||
|           type: string | ||||
|         type: | ||||
|           type: string | ||||
|           enum: [text, code, book, image, file, mermaid, relation-map, render, search, note-map] | ||||
|           enum: [text, code, render, file, image, search, relation-map, book, note-map, mermaid] | ||||
|         mime: | ||||
|           type: string | ||||
|         isProtected: | ||||
| @@ -686,7 +689,6 @@ components: | ||||
|       properties: | ||||
|         branchId: | ||||
|           $ref: '#/components/schemas/EntityId' | ||||
|           readOnly: true | ||||
|         noteId: | ||||
|           $ref: '#/components/schemas/EntityId' | ||||
|           readOnly: true | ||||
| @@ -700,7 +702,7 @@ components: | ||||
|         notePosition: | ||||
|           type: integer | ||||
|           format: int32 | ||||
|         isExanded: | ||||
|         isExpanded: | ||||
|           type: boolean | ||||
|         utcDateModified: | ||||
|           $ref: '#/components/schemas/UtcDateTime' | ||||
| @@ -713,7 +715,6 @@ components: | ||||
|       properties: | ||||
|         attributeId: | ||||
|           $ref: '#/components/schemas/EntityId' | ||||
|           readOnly: true | ||||
|         noteId: | ||||
|           $ref: '#/components/schemas/EntityId' | ||||
|           readOnly: true | ||||
| @@ -753,7 +754,7 @@ components: | ||||
|           description: debugging info on parsing the search query enabled with &debug=true parameter | ||||
|     EntityId: | ||||
|       type: string | ||||
|       pattern: '[a-zA-Z0-9]{4,12}' | ||||
|       pattern: '[a-zA-Z0-9]{4,32}' | ||||
|       example: evnnmvHTCgIn | ||||
|     EntityIdList: | ||||
|       type: array | ||||
|   | ||||
| @@ -103,27 +103,26 @@ function getAndCheckAttribute(attributeId) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function validateAndPatch(entity, props, allowedProperties) { | ||||
|     for (const key of Object.keys(props)) { | ||||
| function validateAndPatch(target, source, allowedProperties) { | ||||
|     for (const key of Object.keys(source)) { | ||||
|         if (!(key in allowedProperties)) { | ||||
|             throw new EtapiError(400, "PROPERTY_NOT_ALLOWED_FOR_PATCH", `Property '${key}' is not allowed for PATCH.`); | ||||
|             throw new EtapiError(400, "PROPERTY_NOT_ALLOWED", `Property '${key}' is not allowed for PATCH.`); | ||||
|         } | ||||
|         else { | ||||
|             const validator = allowedProperties[key]; | ||||
|             const validationResult = validator(props[key]); | ||||
|             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}`); | ||||
|                 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(props)) { | ||||
|         entity[propName] = props[propName]; | ||||
|     for (const propName of Object.keys(source)) { | ||||
|         target[propName] = source[propName]; | ||||
|     } | ||||
|      | ||||
|     entity.save(); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ const eu = require("./etapi_utils"); | ||||
| const mappers = require("./mappers"); | ||||
| const noteService = require("../services/notes"); | ||||
| const TaskContext = require("../services/task_context"); | ||||
| const validators = require("./validators"); | ||||
| const v = require("./validators"); | ||||
| const searchService = require("../services/search/services/search"); | ||||
| const SearchContext = require("../services/search/search_context"); | ||||
|  | ||||
| @@ -39,10 +39,23 @@ function register(router) { | ||||
|         res.json(mappers.mapNoteToPojo(note)); | ||||
|     }); | ||||
|  | ||||
|     eu.route(router, 'post' ,'/etapi/create-note', (req, res, next) => { | ||||
|         const params = req.body; | ||||
|     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.getAndCheckNote(params.parentNoteId); | ||||
|     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); | ||||
| @@ -53,14 +66,14 @@ function register(router) { | ||||
|             }); | ||||
|         } | ||||
|         catch (e) { | ||||
|             return eu.sendError(res, 400, eu.GENERIC_CODE, e.message); | ||||
|             return eu.sendError(res, 500, eu.GENERIC_CODE, e.message); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     const ALLOWED_PROPERTIES_FOR_PATCH = { | ||||
|         'title': validators.isString, | ||||
|         'type': validators.isString, | ||||
|         'mime': validators.isString | ||||
|         '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) => { | ||||
| @@ -71,6 +84,7 @@ function register(router) { | ||||
|         } | ||||
|  | ||||
|         eu.validateAndPatch(note, req.body, ALLOWED_PROPERTIES_FOR_PATCH); | ||||
|         note.save(); | ||||
|  | ||||
|         res.json(mappers.mapNoteToPojo(note)); | ||||
|     }); | ||||
|   | ||||
| @@ -1,30 +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 isStringOrNull(obj) { | ||||
|     if (obj) { | ||||
|         return isString(obj); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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, | ||||
|     isStringOrNull, | ||||
|     isBoolean, | ||||
|     isInteger | ||||
|     isInteger, | ||||
|     isNoteId, | ||||
|     isNoteType, | ||||
|     isAttributeType, | ||||
|     isValidEntityId | ||||
| }; | ||||
| @@ -91,7 +91,7 @@ export default class LoadResults { | ||||
|         } | ||||
|  | ||||
|         const componentIds = this.noteIdToComponentId[noteId]; | ||||
|         return componentIds && !!componentIds.find(sId => sId !== componentId); | ||||
|         return componentIds && componentIds.find(sId => sId !== componentId) !== undefined; | ||||
|     } | ||||
|  | ||||
|     addNoteContent(noteId, componentId) { | ||||
|   | ||||
							
								
								
									
										0
									
								
								src/public/stylesheets/calendar.css
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								src/public/stylesheets/calendar.css
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @@ -190,7 +190,7 @@ const uploadMiddleware = multer.single('upload'); | ||||
| function register(app) { | ||||
|     route(GET, '/', [auth.checkAuth, csrfMiddleware], indexRoute.index); | ||||
|     route(GET, '/login', [auth.checkAppInitialized, auth.checkPasswordSet], loginRoute.loginPage); | ||||
|     route(GET, '/set-password', [auth.checkAppInitialized], loginRoute.setPasswordPage); | ||||
|     route(GET, '/set-password', [auth.checkAppInitialized, auth.checkPasswordNotSet], loginRoute.setPasswordPage); | ||||
|  | ||||
|     const loginRateLimiter = rateLimit({ | ||||
|         windowMs: 15 * 60 * 1000, // 15 minutes | ||||
| @@ -199,7 +199,7 @@ function register(app) { | ||||
|  | ||||
|     route(POST, '/login', [loginRateLimiter], loginRoute.login); | ||||
|     route(POST, '/logout', [csrfMiddleware, auth.checkAuth], loginRoute.logout); | ||||
|     route(POST, '/set-password', [auth.checkAppInitialized], loginRoute.setPassword); | ||||
|     route(POST, '/set-password', [auth.checkAppInitialized, auth.checkPasswordNotSet], loginRoute.setPassword); | ||||
|     route(GET, '/setup', [], setupRoute.setupPage); | ||||
|  | ||||
|     apiRoute(GET, '/api/tree', treeApiRoute.getTree); | ||||
|   | ||||
| @@ -14,6 +14,8 @@ function setupPage(req, res) { | ||||
|         else { | ||||
|             res.redirect('/'); | ||||
|         } | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // we got here because DB is not completely initialized so if schema exists | ||||
|   | ||||
| @@ -15,11 +15,7 @@ function checkAuth(req, res, next) { | ||||
|         res.redirect("setup"); | ||||
|     } | ||||
|     else if (!req.session.loggedIn && !utils.isElectron() && !noAuthentication) { | ||||
|         if (passwordService.isPasswordSet()) { | ||||
|             res.redirect("login"); | ||||
|         } else { | ||||
|             res.redirect("set-password"); | ||||
|         } | ||||
|         res.redirect("login"); | ||||
|     } | ||||
|     else { | ||||
|         next(); | ||||
| @@ -63,6 +59,14 @@ function checkPasswordSet(req, res, next) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function checkPasswordNotSet(req, res, next) { | ||||
|     if (!utils.isElectron() && passwordService.isPasswordSet()) { | ||||
|         res.redirect("login"); | ||||
|     } else { | ||||
|         next(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function checkAppNotInitialized(req, res, next) { | ||||
|     if (sqlInit.isDbInitialized()) { | ||||
|         reject(req, res, "App already initialized."); | ||||
| @@ -111,6 +115,7 @@ module.exports = { | ||||
|     checkApiAuth, | ||||
|     checkAppInitialized, | ||||
|     checkPasswordSet, | ||||
|     checkPasswordNotSet, | ||||
|     checkAppNotInitialized, | ||||
|     checkApiAuthOrElectron, | ||||
|     checkEtapiToken, | ||||
|   | ||||
| @@ -13,6 +13,7 @@ const attributeService = require('./attributes'); | ||||
| const noteRevisionService = require('./note_revisions'); | ||||
| const becca = require("../becca/becca"); | ||||
| const utils = require("../services/utils"); | ||||
| const noteTypes = require("../services/note_types"); | ||||
|  | ||||
| class ConsistencyChecks { | ||||
|     constructor(autoFix) { | ||||
| @@ -281,11 +282,13 @@ class ConsistencyChecks { | ||||
|     } | ||||
|  | ||||
|     findLogicIssues() { | ||||
|         const noteTypesStr = noteTypes.map(nt => `'${nt}'`).join(", "); | ||||
|          | ||||
|         this.findAndFixIssues(` | ||||
|                     SELECT noteId, type | ||||
|                     FROM notes | ||||
|                     WHERE isDeleted = 0 | ||||
|                       AND type NOT IN ('text', 'code', 'render', 'file', 'image', 'search', 'relation-map', 'book', 'note-map', 'mermaid')`, | ||||
|                       AND type NOT IN (${noteTypesStr})`, | ||||
|             ({noteId, type}) => { | ||||
|                 if (this.autoFix) { | ||||
|                     const note = becca.getNote(noteId); | ||||
|   | ||||
| @@ -23,7 +23,7 @@ function addEntityChange(origEntityChange) { | ||||
|         ec.changeId = utils.randomString(12); | ||||
|     } | ||||
|  | ||||
|     ec.componentId = ec.componentId || cls.getComponentId() || ""; | ||||
|     ec.componentId = ec.componentId || cls.getComponentId() || "NA"; // NA = not available | ||||
|     ec.instanceId = ec.instanceId || instanceId; | ||||
|     ec.isSynced = ec.isSynced ? 1 : 0; | ||||
|     ec.isErased = ec.isErased ? 1 : 0; | ||||
| @@ -43,7 +43,7 @@ function addNoteReorderingEntityChange(parentNoteId, componentId) { | ||||
|         utcDateChanged: dateUtils.utcNowDateTime(), | ||||
|         isSynced: true, | ||||
|         componentId, | ||||
|         instanceId: instanceId | ||||
|         instanceId | ||||
|     }); | ||||
|  | ||||
|     const eventService = require('./events'); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ function getTokenHash(token) { | ||||
| } | ||||
|  | ||||
| function createToken(tokenName) { | ||||
|     const token = utils.randomSecureToken(); | ||||
|     const token = utils.randomSecureToken(32); | ||||
|     const tokenHash = getTokenHash(token); | ||||
|  | ||||
|     const etapiToken = new EtapiToken({ | ||||
|   | ||||
| @@ -18,8 +18,6 @@ const Branch = require('../becca/entities/branch'); | ||||
| const Note = require('../becca/entities/note'); | ||||
| const Attribute = require('../becca/entities/attribute'); | ||||
|  | ||||
| // TODO: patch/put note content | ||||
|  | ||||
| function getNewNotePosition(parentNoteId) { | ||||
|     const note = becca.notes[parentNoteId]; | ||||
|  | ||||
|   | ||||
| @@ -1,22 +1,27 @@ | ||||
| const becca = require('../becca/becca'); | ||||
| const sql = require("./sql"); | ||||
|  | ||||
| function getOption(name) { | ||||
| function getOptionOrNull(name) { | ||||
|     let option; | ||||
|  | ||||
|     if (becca.loaded) { | ||||
|         option = becca.getOption(name); | ||||
|     } | ||||
|     else { | ||||
|     } else { | ||||
|         // e.g. in initial sync becca is not loaded because DB is not initialized | ||||
|         option = sql.getRow("SELECT * FROM options WHERE name = ?", name); | ||||
|     } | ||||
|      | ||||
|     if (!option) { | ||||
|     return option ? option.value : null; | ||||
| } | ||||
|  | ||||
| function getOption(name) { | ||||
|     const val = getOptionOrNull(name); | ||||
|  | ||||
|     if (val === null) { | ||||
|         throw new Error(`Option "${name}" doesn't exist`); | ||||
|     } | ||||
|  | ||||
|     return option.value; | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -96,5 +101,6 @@ module.exports = { | ||||
|     setOption, | ||||
|     createOption, | ||||
|     getOptions, | ||||
|     getOptionsMap | ||||
|     getOptionsMap, | ||||
|     getOptionOrNull | ||||
| }; | ||||
|   | ||||
| @@ -6,7 +6,11 @@ const dataEncryptionService = require('./data_encryption'); | ||||
| function verifyPassword(password) { | ||||
|     const givenPasswordHash = utils.toBase64(myScryptService.getVerificationHash(password)); | ||||
|  | ||||
|     const dbPasswordHash = optionService.getOption('passwordVerificationHash'); | ||||
|     const dbPasswordHash = optionService.getOptionOrNull('passwordVerificationHash'); | ||||
|  | ||||
|     if (!dbPasswordHash) { | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     return givenPasswordHash === dbPasswordHash; | ||||
| } | ||||
|   | ||||
| @@ -154,10 +154,6 @@ function sortNotes(parentNoteId, customSortBy = 'title', reverse = false, folder | ||||
|             const topAEl = fetchValue(a, 'top'); | ||||
|             const topBEl = fetchValue(b, 'top'); | ||||
|  | ||||
|             console.log(a.title, topAEl); | ||||
|             console.log(b.title, topBEl); | ||||
|             console.log("comp", compare(topAEl, topBEl) && !reverse); | ||||
|  | ||||
|             if (topAEl !== topBEl) { | ||||
|                 // since "top" should not be reversible, we'll reverse it once more to nullify this effect | ||||
|                 return compare(topAEl, topBEl) * (reverse ? -1 : 1); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ Content-Type: application/json | ||||
| } | ||||
|  | ||||
| > {% | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.status === 200); | ||||
|      | ||||
|     client.global.set("authToken", response.body.authToken); | ||||
| %} | ||||
| @@ -3,6 +3,8 @@ Authorization: {{authToken}} | ||||
| Content-Type: application/json | ||||
|  | ||||
| { | ||||
|   "noteId": "forcedId{{$randomInt}}", | ||||
|   "branchId": "forcedId{{$randomInt}}", | ||||
|   "parentNoteId": "root", | ||||
|   "title": "Hello", | ||||
|   "type": "text", | ||||
| @@ -10,11 +12,11 @@ Content-Type: application/json | ||||
| } | ||||
|  | ||||
| > {%     | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body.note.title == "Hello"); | ||||
|         client.assert(response.body.branch.parentNoteId == "root"); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.note.noteId.startsWith("forcedId")); | ||||
|     client.assert(response.body.note.title == "Hello"); | ||||
|     client.assert(response.body.branch.branchId.startsWith("forcedId")); | ||||
|     client.assert(response.body.branch.parentNoteId == "root"); | ||||
|  | ||||
|     client.log(`Created note ` + response.body.note.noteId + ` and branch ` + response.body.branch.branchId); | ||||
|      | ||||
| @@ -29,15 +31,14 @@ Authorization: {{authToken}} | ||||
| Content-Type: application/json | ||||
|  | ||||
| { | ||||
|   "branchId": "forcedClonedId", | ||||
|   "noteId": "{{createdNoteId}}", | ||||
|   "parentNoteId": "hidden" | ||||
| } | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body.parentNoteId == "hidden"); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.parentNoteId == "hidden"); | ||||
|  | ||||
|     client.global.set("clonedBranchId", response.body.branchId); | ||||
|      | ||||
| @@ -50,14 +51,12 @@ GET {{triliumHost}}/etapi/notes/{{createdNoteId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body.noteId == client.global.get("createdNoteId")); | ||||
|         client.assert(response.body.title == "Hello"); | ||||
|         // order is not defined and may fail in the future | ||||
|         client.assert(response.body.parentBranchIds[0] == client.global.get("clonedBranchId")) | ||||
|         client.assert(response.body.parentBranchIds[1] == client.global.get("createdBranchId")); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.noteId == client.global.get("createdNoteId")); | ||||
|     client.assert(response.body.title == "Hello"); | ||||
|     // order is not defined and may fail in the future | ||||
|     client.assert(response.body.parentBranchIds[0] == client.global.get("clonedBranchId")) | ||||
|     client.assert(response.body.parentBranchIds[1] == client.global.get("createdBranchId")); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -66,10 +65,8 @@ GET {{triliumHost}}/etapi/notes/{{createdNoteId}}/content | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body == "Hi there!"); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body == "Hi there!"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -78,11 +75,9 @@ GET {{triliumHost}}/etapi/branches/{{createdBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body.branchId == client.global.get("createdBranchId")); | ||||
|         client.assert(response.body.parentNoteId == "root"); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.branchId == client.global.get("createdBranchId")); | ||||
|     client.assert(response.body.parentNoteId == "root"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -91,11 +86,9 @@ GET {{triliumHost}}/etapi/branches/{{clonedBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body.branchId == client.global.get("clonedBranchId")); | ||||
|         client.assert(response.body.parentNoteId == "hidden"); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.branchId == client.global.get("clonedBranchId")); | ||||
|     client.assert(response.body.parentNoteId == "hidden"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -105,19 +98,17 @@ Content-Type: application/json | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| { | ||||
|   "attributeId": "forcedAttributeId{{$randomInt}}", | ||||
|   "noteId": "{{createdNoteId}}", | ||||
|   "type": "label", | ||||
|   "name": "mylabel", | ||||
|   "value": "val", | ||||
|   "isInheritable": "true" | ||||
|   "isInheritable": true | ||||
| } | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
|  | ||||
|     client.log(`Created attribute ` + response.body.attributeId); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.attributeId.startsWith("forcedAttributeId")); | ||||
|      | ||||
|     client.global.set("createdAttributeId", response.body.attributeId); | ||||
| %} | ||||
| @@ -128,8 +119,6 @@ GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|         client.assert(response.body.attributeId == client.global.get("createdAttributeId")); | ||||
|     }); | ||||
|     client.assert(response.status === 200); | ||||
|     client.assert(response.body.attributeId == client.global.get("createdAttributeId")); | ||||
| %} | ||||
| @@ -25,7 +25,7 @@ Content-Type: application/json | ||||
|   "type": "label", | ||||
|   "name": "mylabel", | ||||
|   "value": "val", | ||||
|   "isInheritable": "true" | ||||
|   "isInheritable": true | ||||
| } | ||||
|  | ||||
| > {% client.global.set("createdAttributeId", response.body.attributeId); %} | ||||
| @@ -35,14 +35,14 @@ Content-Type: application/json | ||||
| GET {{triliumHost}}/etapi/notes/{{createdNoteId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/branches/{{createdBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
|   | ||||
| @@ -32,21 +32,21 @@ Content-Type: application/json | ||||
| GET {{triliumHost}}/etapi/notes/{{createdNoteId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/branches/{{createdBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/branches/{{clonedBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| @@ -77,11 +77,11 @@ Authorization: {{authToken}} | ||||
| GET {{triliumHost}}/etapi/branches/{{clonedBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/notes/{{createdNoteId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|   | ||||
| @@ -25,7 +25,7 @@ Content-Type: application/json | ||||
|   "type": "label", | ||||
|   "name": "mylabel", | ||||
|   "value": "val", | ||||
|   "isInheritable": "true" | ||||
|   "isInheritable": true | ||||
| } | ||||
|  | ||||
| > {% client.global.set("createdAttributeId", response.body.attributeId); %} | ||||
| @@ -48,28 +48,28 @@ Content-Type: application/json | ||||
| GET {{triliumHost}}/etapi/notes/{{createdNoteId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/branches/{{createdBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/branches/{{clonedBranchId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}} | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% client.assert(response.status === 200, "Response status is not 200"); %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
|   | ||||
| @@ -1,22 +1,14 @@ | ||||
| GET {{triliumHost}}/etapi/inbox/2022-01-01 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
| %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| GET {{triliumHost}}/etapi/calendar/days/2022-01-01 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
| %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| @@ -24,10 +16,8 @@ GET {{triliumHost}}/etapi/calendar/days/2022-1 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Correct error handling", function() { | ||||
|         client.assert(response.status === 400, "Response status is not 400"); | ||||
|         client.assert(response.body.code === "DATE_INVALID"); | ||||
|     }); | ||||
|     client.assert(response.status === 400); | ||||
|     client.assert(response.body.code === "DATE_INVALID"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -35,11 +25,7 @@ Authorization: {{authToken}} | ||||
| GET {{triliumHost}}/etapi/calendar/weeks/2022-01-01 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
| %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| @@ -47,10 +33,8 @@ GET {{triliumHost}}/etapi/calendar/weeks/2022-1 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Correct error handling", function() { | ||||
|         client.assert(response.status === 400, "Response status is not 400"); | ||||
|         client.assert(response.body.code === "DATE_INVALID"); | ||||
|     }); | ||||
|     client.assert(response.status === 400); | ||||
|     client.assert(response.body.code === "DATE_INVALID"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -58,11 +42,7 @@ Authorization: {{authToken}} | ||||
| GET {{triliumHost}}/etapi/calendar/months/2022-01 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
| %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| @@ -70,10 +50,8 @@ GET {{triliumHost}}/etapi/calendar/months/2022-1 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Correct error handling", function() { | ||||
|         client.assert(response.status === 400, "Response status is not 400"); | ||||
|         client.assert(response.body.code === "MONTH_INVALID"); | ||||
|     }); | ||||
|     client.assert(response.status === 400); | ||||
|     client.assert(response.body.code === "MONTH_INVALID"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
| @@ -81,11 +59,7 @@ Authorization: {{authToken}} | ||||
| GET {{triliumHost}}/etapi/calendar/years/2022 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
| %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
|  | ||||
| ### | ||||
|  | ||||
| @@ -93,11 +67,6 @@ GET {{triliumHost}}/etapi/calendar/years/202 | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Correct error handling", function() { | ||||
|         client.assert(response.status === 400, "Response status is not 400"); | ||||
|         client.assert(response.body.code === "YEAR_INVALID"); | ||||
|     }); | ||||
|     client.assert(response.status === 400); | ||||
|     client.assert(response.body.code === "YEAR_INVALID"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,4 @@ | ||||
| POST {{triliumHost}}/etapi/refresh-note-ordering/root | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
|     client.test("Request executed successfully", function() { | ||||
|         client.assert(response.status === 200, "Response status is not 200"); | ||||
|     }); | ||||
| %} | ||||
| > {% client.assert(response.status === 200); %} | ||||
| @@ -25,7 +25,7 @@ Content-Type: application/json | ||||
|   "type": "label", | ||||
|   "name": "mylabel", | ||||
|   "value": "val", | ||||
|   "isInheritable": "true" | ||||
|   "isInheritable": true | ||||
| } | ||||
|  | ||||
| > {% client.global.set("createdAttributeId", response.body.attributeId); %} | ||||
| @@ -61,7 +61,7 @@ Content-Type: application/json | ||||
|  | ||||
| > {%  | ||||
|     client.assert(response.status === 400);  | ||||
|     client.assert(response.body.code == "PROPERTY_NOT_ALLOWED_FOR_PATCH"); | ||||
|     client.assert(response.body.code == "PROPERTY_NOT_ALLOWED"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
|   | ||||
| @@ -47,7 +47,7 @@ Content-Type: application/json | ||||
|  | ||||
| > {%  | ||||
|     client.assert(response.status === 400);  | ||||
|     client.assert(response.body.code == "PROPERTY_NOT_ALLOWED_FOR_PATCH"); | ||||
|     client.assert(response.body.code == "PROPERTY_NOT_ALLOWED"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
|   | ||||
| @@ -60,7 +60,7 @@ Content-Type: application/json | ||||
|  | ||||
| > {%  | ||||
|     client.assert(response.status === 400);  | ||||
|     client.assert(response.body.code == "PROPERTY_NOT_ALLOWED_FOR_PATCH"); | ||||
|     client.assert(response.body.code == "PROPERTY_NOT_ALLOWED"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
|   | ||||
		Reference in New Issue
	
	Block a user