mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-17 18:44:45 +02:00
Merge branch 'dev' of github.com:laurent22/joplin into dev
This commit is contained in:
commit
3b6a66a016
@ -343,7 +343,7 @@ export default class JoplinDatabase extends Database {
|
|||||||
// must be set in the synchronizer too.
|
// must be set in the synchronizer too.
|
||||||
|
|
||||||
// Note: v16 and v17 don't do anything. They were used to debug an issue.
|
// Note: v16 and v17 don't do anything. They were used to debug an issue.
|
||||||
const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38];
|
const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39];
|
||||||
|
|
||||||
let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion);
|
let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion);
|
||||||
|
|
||||||
@ -888,6 +888,10 @@ export default class JoplinDatabase extends Database {
|
|||||||
GROUP BY tags.id`);
|
GROUP BY tags.id`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetVersion == 39) {
|
||||||
|
queries.push('ALTER TABLE `notes` ADD COLUMN conflict_original_id TEXT NOT NULL DEFAULT ""');
|
||||||
|
}
|
||||||
|
|
||||||
const updateVersionQuery = { sql: 'UPDATE version SET version = ?', params: [targetVersion] };
|
const updateVersionQuery = { sql: 'UPDATE version SET version = ?', params: [targetVersion] };
|
||||||
|
|
||||||
queries.push(updateVersionQuery);
|
queries.push(updateVersionQuery);
|
||||||
|
@ -610,10 +610,7 @@ export default class Synchronizer {
|
|||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
|
|
||||||
if (mustHandleConflict) {
|
if (mustHandleConflict) {
|
||||||
const conflictedNote = Object.assign({}, local);
|
await Note.createConflictNote(local, ItemChange.SOURCE_SYNC);
|
||||||
delete conflictedNote.id;
|
|
||||||
conflictedNote.is_conflict = 1;
|
|
||||||
await Note.save(conflictedNote, { autoTimestamp: false, changeSource: ItemChange.SOURCE_SYNC });
|
|
||||||
}
|
}
|
||||||
} else if (action == 'resourceConflict') {
|
} else if (action == 'resourceConflict') {
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
|
@ -6,6 +6,7 @@ import { sortedIds, createNTestNotes, setupDatabaseAndSynchronizer, switchClient
|
|||||||
import Folder from './Folder';
|
import Folder from './Folder';
|
||||||
import Note from './Note';
|
import Note from './Note';
|
||||||
import Tag from './Tag';
|
import Tag from './Tag';
|
||||||
|
import ItemChange from './ItemChange';
|
||||||
const ArrayUtils = require('../ArrayUtils.js');
|
const ArrayUtils = require('../ArrayUtils.js');
|
||||||
|
|
||||||
async function allItems() {
|
async function allItems() {
|
||||||
@ -344,4 +345,44 @@ describe('models_Note', function() {
|
|||||||
expect(sortedNotes3[4].id).toBe(note2.id);
|
expect(sortedNotes3[4].id).toBe(note2.id);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should create a conflict note', async () => {
|
||||||
|
const folder = await Folder.save({ title: 'Source Folder' });
|
||||||
|
const origNote = await Note.save({ title: 'note', parent_id: folder.id });
|
||||||
|
const conflictedNote = await Note.createConflictNote(origNote, ItemChange.SOURCE_SYNC);
|
||||||
|
|
||||||
|
expect(conflictedNote.is_conflict).toBe(1);
|
||||||
|
expect(conflictedNote.conflict_original_id).toBe(origNote.id);
|
||||||
|
expect(conflictedNote.parent_id).toBe(folder.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should copy conflicted note to target folder and cancel conflict', (async () => {
|
||||||
|
const srcfolder = await Folder.save({ title: 'Source Folder' });
|
||||||
|
const targetfolder = await Folder.save({ title: 'Target Folder' });
|
||||||
|
|
||||||
|
const note1 = await Note.save({ title: 'note', parent_id: srcfolder.id });
|
||||||
|
const conflictedNote = await Note.createConflictNote(note1, ItemChange.SOURCE_SYNC);
|
||||||
|
|
||||||
|
const note2 = await Note.copyToFolder(conflictedNote.id, targetfolder.id);
|
||||||
|
|
||||||
|
expect(note2.id === conflictedNote.id).toBe(false);
|
||||||
|
expect(note2.title).toBe(conflictedNote.title);
|
||||||
|
expect(note2.is_conflict).toBe(0);
|
||||||
|
expect(note2.conflict_original_id).toBe('');
|
||||||
|
expect(note2.parent_id).toBe(targetfolder.id);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should move conflicted note to target folder and cancel conflict', (async () => {
|
||||||
|
const srcFolder = await Folder.save({ title: 'Source Folder' });
|
||||||
|
const targetFolder = await Folder.save({ title: 'Target Folder' });
|
||||||
|
const note1 = await Note.save({ title: 'note', parent_id: srcFolder.id });
|
||||||
|
|
||||||
|
const conflictedNote = await Note.createConflictNote(note1, ItemChange.SOURCE_SYNC);
|
||||||
|
|
||||||
|
const movedNote = await Note.moveToFolder(conflictedNote.id, targetFolder.id);
|
||||||
|
|
||||||
|
expect(movedNote.parent_id).toBe(targetFolder.id);
|
||||||
|
expect(movedNote.is_conflict).toBe(0);
|
||||||
|
expect(movedNote.conflict_original_id).toBe('');
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -523,6 +523,7 @@ export default class Note extends BaseItem {
|
|||||||
changes: {
|
changes: {
|
||||||
parent_id: folderId,
|
parent_id: folderId,
|
||||||
is_conflict: 0, // Also reset the conflict flag in case we're moving the note out of the conflict folder
|
is_conflict: 0, // Also reset the conflict flag in case we're moving the note out of the conflict folder
|
||||||
|
conflict_original_id: '', // Reset parent id as well.
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -537,6 +538,7 @@ export default class Note extends BaseItem {
|
|||||||
id: noteId,
|
id: noteId,
|
||||||
parent_id: folderId,
|
parent_id: folderId,
|
||||||
is_conflict: 0,
|
is_conflict: 0,
|
||||||
|
conflict_original_id: '',
|
||||||
updated_time: time.unixMs(),
|
updated_time: time.unixMs(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -911,4 +913,12 @@ export default class Note extends BaseItem {
|
|||||||
return new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
|
return new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async createConflictNote(sourceNote: NoteEntity, changeSource: number): Promise<NoteEntity> {
|
||||||
|
const conflictNote = Object.assign({}, sourceNote);
|
||||||
|
delete conflictNote.id;
|
||||||
|
conflictNote.is_conflict = 1;
|
||||||
|
conflictNote.conflict_original_id = sourceNote.id;
|
||||||
|
return await Note.save(conflictNote, { autoTimestamp: false, changeSource: changeSource });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ export interface NoteEntity {
|
|||||||
"created_time"?: number
|
"created_time"?: number
|
||||||
"updated_time"?: number
|
"updated_time"?: number
|
||||||
"is_conflict"?: number
|
"is_conflict"?: number
|
||||||
|
"conflict_original_id"?: string
|
||||||
"latitude"?: number
|
"latitude"?: number
|
||||||
"longitude"?: number
|
"longitude"?: number
|
||||||
"altitude"?: number
|
"altitude"?: number
|
||||||
|
@ -44,9 +44,10 @@ describe('Synchronizer.conflicts', function() {
|
|||||||
// the conflicted and original note must be the same in every way, to make sure no data has been lost.
|
// the conflicted and original note must be the same in every way, to make sure no data has been lost.
|
||||||
const conflictedNote = conflictedNotes[0];
|
const conflictedNote = conflictedNotes[0];
|
||||||
expect(conflictedNote.id == note2conf.id).toBe(false);
|
expect(conflictedNote.id == note2conf.id).toBe(false);
|
||||||
|
expect(conflictedNote.conflict_original_id).toBe(note2conf.id);
|
||||||
for (const n in conflictedNote) {
|
for (const n in conflictedNote) {
|
||||||
if (!conflictedNote.hasOwnProperty(n)) continue;
|
if (!conflictedNote.hasOwnProperty(n)) continue;
|
||||||
if (n == 'id' || n == 'is_conflict') continue;
|
if (n == 'id' || n == 'is_conflict' || n == 'conflict_original_id') continue;
|
||||||
expect(conflictedNote[n]).toBe(note2conf[n]);
|
expect(conflictedNote[n]).toBe(note2conf[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,6 +477,7 @@ encryption_applied: 0
|
|||||||
markup_language: 1
|
markup_language: 1
|
||||||
is_shared: 1
|
is_shared: 1
|
||||||
share_id: ${note.share_id || ''}
|
share_id: ${note.share_id || ''}
|
||||||
|
conflict_original_id:
|
||||||
type_: 1`;
|
type_: 1`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user