mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	allow specifying date created in the ETAPI, #4199
This commit is contained in:
		
							
								
								
									
										687
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										687
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										16
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								package.json
									
									
									
									
									
								
							| @@ -68,10 +68,10 @@ | ||||
|     "jimp": "0.22.10", | ||||
|     "joplin-turndown-plugin-gfm": "1.0.12", | ||||
|     "jsdom": "22.1.0", | ||||
|     "marked": "7.0.3", | ||||
|     "marked": "7.0.5", | ||||
|     "mime-types": "2.1.35", | ||||
|     "multer": "1.4.5-lts.1", | ||||
|     "node-abi": "3.46.0", | ||||
|     "node-abi": "3.47.0", | ||||
|     "normalize-strings": "1.1.1", | ||||
|     "open": "8.4.1", | ||||
|     "rand-token": "1.0.1", | ||||
| @@ -97,14 +97,14 @@ | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "cross-env": "7.0.3", | ||||
|     "electron": "25.5.0", | ||||
|     "electron": "25.7.0", | ||||
|     "electron-builder": "24.6.3", | ||||
|     "electron-packager": "17.1.1", | ||||
|     "electron-packager": "17.1.2", | ||||
|     "electron-rebuild": "3.2.9", | ||||
|     "eslint": "8.47.0", | ||||
|     "eslint": "8.48.0", | ||||
|     "eslint-config-airbnb-base": "15.0.0", | ||||
|     "eslint-config-prettier": "9.0.0", | ||||
|     "eslint-plugin-import": "2.28.0", | ||||
|     "eslint-plugin-import": "2.28.1", | ||||
|     "eslint-plugin-jsonc": "2.9.0", | ||||
|     "eslint-plugin-prettier": "5.0.0", | ||||
|     "esm": "3.2.25", | ||||
| @@ -115,13 +115,13 @@ | ||||
|     "lint-staged": "14.0.0", | ||||
|     "lorem-ipsum": "2.0.8", | ||||
|     "nodemon": "3.0.1", | ||||
|     "prettier": "3.0.2", | ||||
|     "prettier": "3.0.3", | ||||
|     "rcedit": "3.1.0", | ||||
|     "webpack": "5.88.2", | ||||
|     "webpack-cli": "5.1.4" | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|     "electron-installer-debian": "3.1.0" | ||||
|     "electron-installer-debian": "3.2.0" | ||||
|   }, | ||||
|   "lint-staged": { | ||||
|     "*.js": "eslint --cache --fix" | ||||
|   | ||||
| @@ -802,6 +802,12 @@ components: | ||||
|         branchId: | ||||
|           $ref: '#/components/schemas/EntityId' | ||||
|           description: DON'T specify unless you want to force a specific branchId | ||||
|         dateCreated: | ||||
|           $ref: '#/components/schemas/LocalDateTime' | ||||
|           description: Local timestap of the note creation. Specify only if you want to override the default (current datetime in the current timezone/offset). | ||||
|         utcDateCreated: | ||||
|           $ref: '#/components/schemas/UtcDateTime' | ||||
|           description: UTC timestap of the note creation. Specify only if you want to override the default (current datetime). | ||||
|     Note: | ||||
|       type: object | ||||
|       properties: | ||||
| @@ -838,13 +844,11 @@ components: | ||||
|           readOnly: true | ||||
|         dateCreated: | ||||
|           $ref: '#/components/schemas/LocalDateTime' | ||||
|           readOnly: true | ||||
|         dateModified: | ||||
|           $ref: '#/components/schemas/LocalDateTime' | ||||
|           readOnly: true | ||||
|         utcDateCreated: | ||||
|           $ref: '#/components/schemas/UtcDateTime' | ||||
|           readOnly: true | ||||
|         utcDateModified: | ||||
|           $ref: '#/components/schemas/UtcDateTime' | ||||
|           readOnly: true | ||||
| @@ -937,11 +941,11 @@ components: | ||||
|     LocalDateTime: | ||||
|       type: string | ||||
|       pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[\+\-][0-9]{4}' | ||||
|       example: 2021-12-31 20:18:11.939+0100 | ||||
|       example: 2021-12-31 20:18:11.930+0100 | ||||
|     UtcDateTime: | ||||
|       type: string | ||||
|       pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z' | ||||
|       example: 2021-12-31 19:18:11.939Z | ||||
|       example: 2021-12-31 19:18:11.930Z | ||||
|     AppInfo: | ||||
|       type: object | ||||
|       properties: | ||||
|   | ||||
| @@ -50,7 +50,9 @@ function register(router) { | ||||
|         'notePosition': [v.notNull, v.isInteger], | ||||
|         'prefix': [v.notNull, v.isString], | ||||
|         'isExpanded': [v.notNull, v.isBoolean], | ||||
|         'noteId': [v.notNull, v.isValidEntityId] | ||||
|         'noteId': [v.notNull, v.isValidEntityId], | ||||
|         'dateCreated': [v.notNull, v.isString, v.isLocalDateTime], | ||||
|         'utcDateCreated': [v.notNull, v.isString, v.isUtcDateTime] | ||||
|     }; | ||||
|  | ||||
|     eu.route(router, 'post' ,'/etapi/create-note', (req, res, next) => { | ||||
| @@ -74,7 +76,9 @@ function register(router) { | ||||
|     const ALLOWED_PROPERTIES_FOR_PATCH = { | ||||
|         'title': [v.notNull, v.isString], | ||||
|         'type': [v.notNull, v.isString], | ||||
|         'mime': [v.notNull, v.isString] | ||||
|         'mime': [v.notNull, v.isString], | ||||
|         'dateCreated': [v.notNull, v.isString, v.isLocalDateTime], | ||||
|         'utcDateCreated': [v.notNull, v.isString, v.isUtcDateTime] | ||||
|     }; | ||||
|  | ||||
|     eu.route(router, 'patch' ,'/etapi/notes/:noteId', (req, res, next) => { | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| const noteTypeService = require("../services/note_types"); | ||||
| const dateUtils = require("../services/date_utils"); | ||||
|  | ||||
| function mandatory(obj) { | ||||
|     if (obj === undefined ) { | ||||
| @@ -22,6 +23,22 @@ function isString(obj) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function isLocalDateTime(obj) { | ||||
|     if (obj === undefined || obj === null) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     return dateUtils.validateLocalDateTime(obj); | ||||
| } | ||||
|  | ||||
| function isUtcDateTime(obj) { | ||||
|     if (obj === undefined || obj === null) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     return dateUtils.validateUtcDateTime(obj); | ||||
| } | ||||
|  | ||||
| function isBoolean(obj) { | ||||
|     if (obj === undefined || obj === null) { | ||||
|         return; | ||||
| @@ -99,5 +116,7 @@ module.exports = { | ||||
|     isNoteId, | ||||
|     isNoteType, | ||||
|     isAttributeType, | ||||
|     isValidEntityId | ||||
|     isValidEntityId, | ||||
|     isLocalDateTime, | ||||
|     isUtcDateTime | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| const dayjs = require('dayjs'); | ||||
| const cls = require('./cls'); | ||||
|  | ||||
| const LOCAL_DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSSZZ'; | ||||
| const UTC_DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ssZ'; | ||||
|  | ||||
| function utcNowDateTime() { | ||||
|     return utcDateTimeStr(new Date()); | ||||
| } | ||||
| @@ -10,7 +13,7 @@ function utcNowDateTime() { | ||||
| // "trilium-local-now-datetime" header which is then stored in CLS | ||||
| function localNowDateTime() { | ||||
|     return cls.getLocalNowDateTime() | ||||
|         || dayjs().format('YYYY-MM-DD HH:mm:ss.SSSZZ') | ||||
|         || dayjs().format(LOCAL_DATETIME_FORMAT) | ||||
| } | ||||
|  | ||||
| function localNowDate() { | ||||
| @@ -62,6 +65,36 @@ function getDateTimeForFile() { | ||||
|     return new Date().toISOString().substr(0, 19).replace(/:/g, ''); | ||||
| } | ||||
|  | ||||
| function validateLocalDateTime(str) { | ||||
|     if (!str) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[+-][0-9]{4}/.test(str)) { | ||||
|         return `Invalid local date time format in '${str}'. Correct format shoud follow example: '2023-08-21 23:38:51.110+0200'`; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     if (!dayjs(str, LOCAL_DATETIME_FORMAT)) { | ||||
|         return `Date '${str}' appears to be in the correct format, but cannot be parsed. It likely represents an invalid date.`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| function validateUtcDateTime(str) { | ||||
|     if (!str) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z/.test(str)) { | ||||
|         return `Invalid UTC date time format in '${str}'. Correct format shoud follow example: '2023-08-21 23:38:51.110Z'`; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     if (!dayjs(str, UTC_DATETIME_FORMAT)) { | ||||
|         return `Date '${str}' appears to be in the correct format, but cannot be parsed. It likely represents an invalid date.`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     utcNowDateTime, | ||||
|     localNowDateTime, | ||||
| @@ -70,5 +103,7 @@ module.exports = { | ||||
|     utcDateTimeStr, | ||||
|     parseDateTime, | ||||
|     parseLocalDate, | ||||
|     getDateTimeForFile | ||||
|     getDateTimeForFile, | ||||
|     validateLocalDateTime, | ||||
|     validateUtcDateTime | ||||
| }; | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| const sql = require('./sql'); | ||||
| const sqlInit = require('./sql_init'); | ||||
| const optionService = require('./options'); | ||||
| const dateUtils = require('./date_utils'); | ||||
| const entityChangesService = require('./entity_changes'); | ||||
| @@ -169,6 +168,15 @@ function createNewNote(params) { | ||||
|         throw new Error(`Note content must be set`); | ||||
|     } | ||||
|  | ||||
|     let error; | ||||
|     if (error = dateUtils.validateLocalDateTime(params.dateCreated)) { | ||||
|         throw new Error(error); | ||||
|     } | ||||
|  | ||||
|     if (error = dateUtils.validateUtcDateTime(params.utcDateCreated)) { | ||||
|         throw new Error(error); | ||||
|     } | ||||
|  | ||||
|     return sql.transactional(() => { | ||||
|         let note, branch, isEntityEventsDisabled; | ||||
|  | ||||
| @@ -189,7 +197,9 @@ function createNewNote(params) { | ||||
|                 title: params.title, | ||||
|                 isProtected: !!params.isProtected, | ||||
|                 type: params.type, | ||||
|                 mime: deriveMime(params.type, params.mime) | ||||
|                 mime: deriveMime(params.type, params.mime), | ||||
|                 dateCreated: params.dateCreated, | ||||
|                 utcDateCreated: params.utcDateCreated | ||||
|             }).save(); | ||||
|  | ||||
|             note.setContent(params.content); | ||||
|   | ||||
| @@ -7,13 +7,17 @@ Content-Type: application/json | ||||
|   "parentNoteId": "root", | ||||
|   "title": "Hello", | ||||
|   "type": "text", | ||||
|   "content": "Hi there!" | ||||
|   "content": "Hi there!", | ||||
|   "dateCreated": "2023-08-21 23:38:51.123+0200", | ||||
|   "utcDateCreated": "2023-08-21 23:38:51.123Z" | ||||
| } | ||||
|  | ||||
| > {% | ||||
|     client.assert(response.status === 201); | ||||
|     client.assert(response.body.note.noteId.startsWith("forcedId")); | ||||
|     client.assert(response.body.note.title == "Hello"); | ||||
|     client.assert(response.body.note.dateCreated == "2023-08-21 23:38:51.123+0200"); | ||||
|     client.assert(response.body.note.utcDateCreated == "2023-08-21 23:38:51.123Z"); | ||||
|     client.assert(response.body.branch.parentNoteId == "root"); | ||||
|  | ||||
|     client.log(`Created note ` + response.body.note.noteId + ` and branch ` + response.body.branch.branchId); | ||||
|   | ||||
| @@ -33,7 +33,9 @@ Content-Type: application/json | ||||
| { | ||||
|   "title": "Wassup", | ||||
|   "type": "html", | ||||
|   "mime": "text/html" | ||||
|   "mime": "text/html", | ||||
|   "dateCreated": "2023-08-21 23:38:51.123+0200", | ||||
|   "utcDateCreated": "2023-08-21 23:38:51.123Z" | ||||
| } | ||||
|  | ||||
| ### | ||||
| @@ -46,6 +48,8 @@ client.assert(response.status === 200); | ||||
| client.assert(response.body.title === 'Wassup'); | ||||
| client.assert(response.body.type === 'html'); | ||||
| client.assert(response.body.mime === 'text/html'); | ||||
| client.assert(response.body.dateCreated == "2023-08-21 23:38:51.123+0200"); | ||||
| client.assert(response.body.utcDateCreated == "2023-08-21 23:38:51.123Z"); | ||||
| %} | ||||
|  | ||||
| ### | ||||
|   | ||||
		Reference in New Issue
	
	Block a user