You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Clean up
This commit is contained in:
		
							
								
								
									
										1
									
								
								CliClient/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								CliClient/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -10,3 +10,4 @@ tests/fuzzing/client1 | ||||
| tests/fuzzing/client2 | ||||
| tests/fuzzing/sync | ||||
| tests/fuzzing.* | ||||
| tests/fuzzing -* | ||||
| @@ -202,10 +202,10 @@ commands.push({ | ||||
|  | ||||
| 			if (pattern.indexOf('*') < 0) { // Handle it as a simple title | ||||
| 				if (pattern.substr(0, 3) == '../') { | ||||
| 					itemType = BaseModel.MODEL_TYPE_FOLDER; | ||||
| 					itemType = BaseModel.TYPE_FOLDER; | ||||
| 					pattern = pattern.substr(3); | ||||
| 				} else { | ||||
| 					itemType = BaseModel.MODEL_TYPE_NOTE; | ||||
| 					itemType = BaseModel.TYPE_NOTE; | ||||
| 				} | ||||
|  | ||||
| 				let item = await BaseItem.loadItemByField(itemType, 'title', pattern); | ||||
| @@ -272,9 +272,9 @@ commands.push({ | ||||
| 	action: async function(args, end) { | ||||
| 		try { | ||||
| 			let tag = null; | ||||
| 			if (args.tag) tag = await loadItem(BaseModel.MODEL_TYPE_TAG, args.tag); | ||||
| 			if (args.tag) tag = await loadItem(BaseModel.TYPE_TAG, args.tag); | ||||
| 			let note = null; | ||||
| 			if (args.note) note = await loadItem(BaseModel.MODEL_TYPE_NOTE, args.note); | ||||
| 			if (args.note) note = await loadItem(BaseModel.TYPE_NOTE, args.note); | ||||
|  | ||||
| 			if (args.command == 'remove' && !tag) throw new Error(_('Tag does not exist: "%s"', args.tag)); | ||||
|  | ||||
|   | ||||
| @@ -25,7 +25,7 @@ describe('BaseItem', function() { | ||||
|  | ||||
| 		await Folder.delete(folder1.id); | ||||
|  | ||||
| 		let items = await BaseModel.deletedItems(); | ||||
| 		let items = await BaseItem.deletedItems(); | ||||
|  | ||||
| 		expect(items.length).toBe(1); | ||||
| 		expect(items[0].item_id).toBe(folder1.id); | ||||
|   | ||||
| @@ -38,7 +38,7 @@ async function localItemsSameAsRemote(locals, expect) { | ||||
| 			expect(remote.updated_time).toBe(dbItem.updated_time); | ||||
|  | ||||
| 			let remoteContent = await fileApi().get(path); | ||||
| 			remoteContent = dbItem.type_ == BaseModel.MODEL_TYPE_NOTE ? await Note.unserialize(remoteContent) : await Folder.unserialize(remoteContent); | ||||
| 			remoteContent = dbItem.type_ == BaseModel.TYPE_NOTE ? await Note.unserialize(remoteContent) : await Folder.unserialize(remoteContent); | ||||
| 			expect(remoteContent.title).toBe(dbItem.title); | ||||
| 		} | ||||
| 	} catch (error) { | ||||
| @@ -238,7 +238,7 @@ describe('Synchronizer', function() { | ||||
| 		expect(files.length).toBe(1); | ||||
| 		expect(files[0].path).toBe(Folder.systemPath(folder1)); | ||||
|  | ||||
| 		let deletedItems = await BaseModel.deletedItems(); | ||||
| 		let deletedItems = await BaseItem.deletedItems(); | ||||
| 		expect(deletedItems.length).toBe(0); | ||||
|  | ||||
| 		done(); | ||||
| @@ -267,7 +267,7 @@ describe('Synchronizer', function() { | ||||
|  | ||||
| 		expect(items.length).toBe(1); | ||||
|  | ||||
| 		let deletedItems = await BaseModel.deletedItems(); | ||||
| 		let deletedItems = await BaseItem.deletedItems(); | ||||
|  | ||||
| 		expect(deletedItems.length).toBe(0); | ||||
| 		 | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class BaseModel { | ||||
| 			return output; | ||||
| 		} else { | ||||
| 			model = Object.assign({}, model); | ||||
| 			model.type_ = this.itemType(); | ||||
| 			model.type_ = this.modelType(); | ||||
| 			return model; | ||||
| 		} | ||||
| 	} | ||||
| @@ -33,14 +33,10 @@ class BaseModel { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	static itemType() { | ||||
| 	static modelType() { | ||||
| 		throw new Error('Must be overriden'); | ||||
| 	} | ||||
|  | ||||
| 	static trackDeleted() { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	static byId(items, id) { | ||||
| 		for (let i = 0; i < items.length; i++) { | ||||
| 			if (items[i].id == id) return items[i]; | ||||
| @@ -69,13 +65,6 @@ class BaseModel { | ||||
| 		return this.db().tableFields(this.tableName()); | ||||
| 	} | ||||
|  | ||||
| 	static identifyItemType(item) { | ||||
| 		if (!item) throw new Error('Cannot identify undefined item'); | ||||
| 		if ('body' in item || ('parent_id' in item && !!item.parent_id)) return BaseModel.MODEL_TYPE_NOTE; | ||||
| 		if ('sync_time' in item) return BaseModel.MODEL_TYPE_FOLDER; | ||||
| 		throw new Error('Cannot identify item: ' + JSON.stringify(item)); | ||||
| 	} | ||||
|  | ||||
| 	static new() { | ||||
| 		let fields = this.fields(); | ||||
| 		let output = {}; | ||||
| @@ -86,26 +75,14 @@ class BaseModel { | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	static fromApiResult(apiResult) { | ||||
| 		let fieldNames = this.fieldNames(); | ||||
| 		let output = {}; | ||||
| 		for (let i = 0; i < fieldNames.length; i++) { | ||||
| 			let f = fieldNames[i]; | ||||
| 			output[f] = f in apiResult ? apiResult[f] : null; | ||||
| 		} | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	static modOptions(options) { | ||||
| 		if (!options) { | ||||
| 			options = {}; | ||||
| 		} else { | ||||
| 			options = Object.assign({}, options); | ||||
| 		} | ||||
| 		if (!('trackDeleted' in options)) options.trackDeleted = null; | ||||
| 		if (!('isNew' in options)) options.isNew = 'auto'; | ||||
| 		if (!('autoTimestamp' in options)) options.autoTimestamp = true; | ||||
| 		if (!('transactionNextQueries' in options)) options.transactionNextQueries = []; | ||||
| 		return options; | ||||
| 	} | ||||
|  | ||||
| @@ -179,15 +156,6 @@ class BaseModel { | ||||
| 		return this.modelSelectOne('SELECT * FROM `' + this.tableName() + '` WHERE `title` = ?', [fieldValue]); | ||||
| 	} | ||||
|  | ||||
| 	static applyPatch(model, patch) { | ||||
| 		model = Object.assign({}, model); | ||||
| 		for (let n in patch) { | ||||
| 			if (!patch.hasOwnProperty(n)) continue; | ||||
| 			model[n] = patch[n]; | ||||
| 		} | ||||
| 		return model; | ||||
| 	} | ||||
|  | ||||
| 	static diffObjects(oldModel, newModel) { | ||||
| 		let output = {}; | ||||
| 		let type = null; | ||||
| @@ -256,10 +224,6 @@ class BaseModel { | ||||
|  | ||||
| 		queries.push(saveQuery); | ||||
|  | ||||
| 		for (let i = 0; i < options.transactionNextQueries.length; i++) { | ||||
| 			queries.push(options.transactionNextQueries[i]); | ||||
| 		} | ||||
|  | ||||
| 		return this.db().transactionExecBatch(queries).then(() => { | ||||
| 			o = Object.assign({}, o); | ||||
| 			o.id = modelId; | ||||
| @@ -280,14 +244,6 @@ class BaseModel { | ||||
| 		return !object.id; | ||||
| 	} | ||||
|  | ||||
| 	static deletedItems() { | ||||
| 		return this.db().selectAll('SELECT * FROM deleted_items'); | ||||
| 	} | ||||
|  | ||||
| 	static remoteDeletedItem(itemId) { | ||||
| 		return this.db().exec('DELETE FROM deleted_items WHERE item_id = ?', [itemId]); | ||||
| 	} | ||||
|  | ||||
| 	static filterArray(models) { | ||||
| 		let output = []; | ||||
| 		for (let i = 0; i < models.length; i++) { | ||||
| @@ -312,16 +268,8 @@ class BaseModel { | ||||
|  | ||||
| 	static delete(id, options = null) { | ||||
| 		options = this.modOptions(options); | ||||
|  | ||||
| 		if (!id) throw new Error('Cannot delete object without an ID'); | ||||
|  | ||||
| 		return this.db().exec('DELETE FROM ' + this.tableName() + ' WHERE id = ?', [id]).then(() => { | ||||
| 			let trackDeleted = this.trackDeleted(); | ||||
| 			if (options.trackDeleted !== null) trackDeleted = options.trackDeleted; | ||||
| 			if (trackDeleted) { | ||||
| 				return this.db().exec('INSERT INTO deleted_items (item_type, item_id, deleted_time) VALUES (?, ?, ?)', [this.itemType(), id, time.unixMs()]); | ||||
| 			} | ||||
| 		}); | ||||
| 		return this.db().exec('DELETE FROM ' + this.tableName() + ' WHERE id = ?', [id]); | ||||
| 	} | ||||
|  | ||||
| 	static db() { | ||||
| @@ -331,11 +279,11 @@ class BaseModel { | ||||
|  | ||||
| } | ||||
|  | ||||
| BaseModel.MODEL_TYPE_NOTE = 1; | ||||
| BaseModel.MODEL_TYPE_FOLDER = 2; | ||||
| BaseModel.MODEL_TYPE_SETTING = 3; | ||||
| BaseModel.MODEL_TYPE_RESOURCE = 4; | ||||
| BaseModel.MODEL_TYPE_TAG = 5; | ||||
| BaseModel.TYPE_NOTE = 1; | ||||
| BaseModel.TYPE_FOLDER = 2; | ||||
| BaseModel.TYPE_SETTING = 3; | ||||
| BaseModel.TYPE_RESOURCE = 4; | ||||
| BaseModel.TYPE_TAG = 5; | ||||
| BaseModel.tableInfo_ = null; | ||||
| BaseModel.tableKeys_ = null; | ||||
| BaseModel.db_ = null; | ||||
|   | ||||
| @@ -9,6 +9,10 @@ class BaseItem extends BaseModel { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	static trackDeleted() { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// Need to dynamically load the classes like this to avoid circular dependencies | ||||
| 	static getClass(name) { | ||||
| 		if (!this.classes_) this.classes_ = {}; | ||||
| @@ -29,10 +33,10 @@ class BaseItem extends BaseModel { | ||||
| 			if (!('type_' in item)) throw new Error('Item does not have a type_ property'); | ||||
| 			return this.itemClass(item.type_); | ||||
| 		} else { | ||||
| 			if (Number(item) === BaseModel.MODEL_TYPE_NOTE) return this.getClass('Note'); | ||||
| 			if (Number(item) === BaseModel.MODEL_TYPE_FOLDER) return this.getClass('Folder'); | ||||
| 			if (Number(item) === BaseModel.MODEL_TYPE_RESOURCE) return this.getClass('Resource'); | ||||
| 			if (Number(item) === BaseModel.MODEL_TYPE_TAG) return this.getClass('Tag'); | ||||
| 			if (Number(item) === BaseModel.TYPE_NOTE) return this.getClass('Note'); | ||||
| 			if (Number(item) === BaseModel.TYPE_FOLDER) return this.getClass('Folder'); | ||||
| 			if (Number(item) === BaseModel.TYPE_RESOURCE) return this.getClass('Resource'); | ||||
| 			if (Number(item) === BaseModel.TYPE_TAG) return this.getClass('Tag'); | ||||
| 			throw new Error('Unknown type: ' + item); | ||||
| 		} | ||||
| 	} | ||||
| @@ -79,6 +83,25 @@ class BaseItem extends BaseModel { | ||||
| 		return ItemClass.delete(id); | ||||
| 	} | ||||
|  | ||||
| 	static async delete(id, options = null) { | ||||
| 		let trackDeleted = this.trackDeleted(); | ||||
| 		if (options && options.trackDeleted !== null && options.trackDeleted !== undefined) trackDeleted = options.trackDeleted; | ||||
|  | ||||
| 		await super.delete(id, options); | ||||
|  | ||||
| 		if (trackDeleted) { | ||||
| 			await this.db().exec('INSERT INTO deleted_items (item_type, item_id, deleted_time) VALUES (?, ?, ?)', [this.modelType(), id, time.unixMs()]); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static deletedItems() { | ||||
| 		return this.db().selectAll('SELECT * FROM deleted_items'); | ||||
| 	} | ||||
|  | ||||
| 	static remoteDeletedItem(itemId) { | ||||
| 		return this.db().exec('DELETE FROM deleted_items WHERE item_id = ?', [itemId]); | ||||
| 	} | ||||
|  | ||||
| 	static serialize_format(propName, propValue) { | ||||
| 		if (['created_time', 'updated_time'].indexOf(propName) >= 0) { | ||||
| 			if (!propValue) return ''; | ||||
| @@ -145,6 +168,7 @@ class BaseItem extends BaseModel { | ||||
| 				if (line == '') { | ||||
| 					state = 'readingBody'; | ||||
| 					continue; | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				let p = line.indexOf(':'); | ||||
| @@ -165,7 +189,7 @@ class BaseItem extends BaseModel { | ||||
| 		if (!output.type_) throw new Error('Missing required property: type_: ' + content); | ||||
| 		output.type_ = Number(output.type_); | ||||
|  | ||||
| 		if (output.type_ == BaseModel.MODEL_TYPE_NOTE) output.body = body.join("\n"); | ||||
| 		if (output.type_ == BaseModel.TYPE_NOTE) output.body = body.join("\n"); | ||||
|  | ||||
| 		for (let n in output) { | ||||
| 			if (!output.hasOwnProperty(n)) continue; | ||||
|   | ||||
| @@ -21,8 +21,8 @@ class Folder extends BaseItem { | ||||
| 		return super.serialize(folder, 'folder', fieldNames); | ||||
| 	} | ||||
|  | ||||
| 	static itemType() { | ||||
| 		return BaseModel.MODEL_TYPE_FOLDER; | ||||
| 	static modelType() { | ||||
| 		return BaseModel.TYPE_FOLDER; | ||||
| 	} | ||||
|  | ||||
| 	static trackDeleted() { | ||||
|   | ||||
| @@ -20,8 +20,8 @@ class Note extends BaseItem { | ||||
| 		return super.serialize(note, 'note', fieldNames); | ||||
| 	} | ||||
|  | ||||
| 	static itemType() { | ||||
| 		return BaseModel.MODEL_TYPE_NOTE; | ||||
| 	static modelType() { | ||||
| 		return BaseModel.TYPE_NOTE; | ||||
| 	} | ||||
|  | ||||
| 	static trackDeleted() { | ||||
|   | ||||
| @@ -11,8 +11,8 @@ class Resource extends BaseItem { | ||||
| 		return 'resources'; | ||||
| 	} | ||||
|  | ||||
| 	static itemType() { | ||||
| 		return BaseModel.MODEL_TYPE_RESOURCE; | ||||
| 	static modelType() { | ||||
| 		return BaseModel.TYPE_RESOURCE; | ||||
| 	} | ||||
|  | ||||
| 	static async serialize(item, type = null, shownKeys = null) { | ||||
|   | ||||
| @@ -7,8 +7,8 @@ class Setting extends BaseModel { | ||||
| 		return 'settings'; | ||||
| 	} | ||||
|  | ||||
| 	static itemType() { | ||||
| 		return BaseModel.MODEL_TYPE_SETTING; | ||||
| 	static modelType() { | ||||
| 		return BaseModel.TYPE_SETTING; | ||||
| 	} | ||||
|  | ||||
| 	static defaultSetting(key) { | ||||
|   | ||||
| @@ -11,8 +11,8 @@ class Tag extends BaseItem { | ||||
| 		return 'tags'; | ||||
| 	} | ||||
|  | ||||
| 	static itemType() { | ||||
| 		return BaseModel.MODEL_TYPE_TAG; | ||||
| 	static modelType() { | ||||
| 		return BaseModel.TYPE_TAG; | ||||
| 	} | ||||
|  | ||||
| 	static async serialize(item, type = null, shownKeys = null) { | ||||
|   | ||||
| @@ -156,7 +156,7 @@ class Synchronizer { | ||||
| 							reason = 'remote does not exist, and local is new and has never been synced'; | ||||
| 						} else { | ||||
| 							// Note or item was modified after having been deleted remotely | ||||
| 							action = local.type_ == BaseModel.MODEL_TYPE_NOTE ? 'noteConflict' : 'itemConflict'; | ||||
| 							action = local.type_ == BaseModel.TYPE_NOTE ? 'noteConflict' : 'itemConflict'; | ||||
| 							reason = 'remote has been deleted, but local has changes'; | ||||
| 						} | ||||
| 					} else { | ||||
| @@ -164,7 +164,7 @@ class Synchronizer { | ||||
| 							// Since, in this loop, we are only dealing with notes that require sync, if the | ||||
| 							// remote has been modified after the sync time, it means both notes have been | ||||
| 							// modified and so there's a conflict. | ||||
| 							action = local.type_ == BaseModel.MODEL_TYPE_NOTE ? 'noteConflict' : 'itemConflict'; | ||||
| 							action = local.type_ == BaseModel.TYPE_NOTE ? 'noteConflict' : 'itemConflict'; | ||||
| 							reason = 'both remote and local have changes'; | ||||
| 						} else { | ||||
| 							action = 'updateRemote'; | ||||
| @@ -175,7 +175,7 @@ class Synchronizer { | ||||
| 					this.logSyncOperation(action, local, remote, reason); | ||||
|  | ||||
|  | ||||
| 					if (local.type_ == BaseModel.MODEL_TYPE_RESOURCE && (action == 'createRemote' || (action == 'itemConflict' && remote))) { | ||||
| 					if (local.type_ == BaseModel.TYPE_RESOURCE && (action == 'createRemote' || (action == 'itemConflict' && remote))) { | ||||
| 						let remoteContentPath = this.resourceDirName_ + '/' + local.id; | ||||
| 						let resourceContent = await Resource.content(local); | ||||
| 						await this.api().put(remoteContentPath, resourceContent); | ||||
| @@ -244,7 +244,7 @@ class Synchronizer { | ||||
| 			// Delete the remote items that have been deleted locally. | ||||
| 			// ------------------------------------------------------------------------ | ||||
|  | ||||
| 			let deletedItems = await BaseModel.deletedItems(); | ||||
| 			let deletedItems = await BaseItem.deletedItems(); | ||||
| 			report.remotesToDelete = deletedItems.length; | ||||
| 			options.onProgress(report); | ||||
| 			for (let i = 0; i < deletedItems.length; i++) { | ||||
| @@ -253,7 +253,7 @@ class Synchronizer { | ||||
| 				this.logSyncOperation('deleteRemote', null, { id: item.item_id }, 'local has been deleted'); | ||||
| 				await this.api().delete(path); | ||||
| 				if (this.randomFailure(options, 2)) return; | ||||
| 				await BaseModel.remoteDeletedItem(item.item_id); | ||||
| 				await BaseItem.remoteDeletedItem(item.item_id); | ||||
|  | ||||
| 				report['deleteRemote']++; | ||||
| 				options.onProgress(report); | ||||
| @@ -315,7 +315,7 @@ class Synchronizer { | ||||
| 						}; | ||||
| 						if (action == 'createLocal') options.isNew = true; | ||||
|  | ||||
| 						if (newContent.type_ == BaseModel.MODEL_TYPE_RESOURCE && action == 'createLocal') { | ||||
| 						if (newContent.type_ == BaseModel.TYPE_RESOURCE && action == 'createLocal') { | ||||
| 							let localResourceContentPath = Resource.fullPath(newContent); | ||||
| 							let remoteResourceContentPath = this.resourceDirName_ + '/' + newContent.id; | ||||
| 							let remoteResourceContent = await this.api().get(remoteResourceContentPath, { encoding: 'binary' }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user