diff --git a/src/entities/note_revision.js b/src/entities/note_revision.js index 53afce996..7b25bb5a5 100644 --- a/src/entities/note_revision.js +++ b/src/entities/note_revision.js @@ -15,7 +15,6 @@ const entityChangesService = require('../services/entity_changes.js'); * @property {string} type * @property {string} mime * @property {string} title - * @property {boolean} isErased * @property {boolean} isProtected * @property {string} dateLastEdited * @property {string} dateCreated diff --git a/src/routes/api/note_revisions.js b/src/routes/api/note_revisions.js index 4fab89c79..bebff5dd8 100644 --- a/src/routes/api/note_revisions.js +++ b/src/routes/api/note_revisions.js @@ -80,8 +80,7 @@ function downloadNoteRevision(req, res) { } function eraseAllNoteRevisions(req) { - const noteRevisionIdsToErase = sql.getColumn( - 'SELECT noteRevisionId FROM note_revisions WHERE isErased = 0 AND noteId = ?', + const noteRevisionIdsToErase = sql.getColumn('SELECT noteRevisionId FROM note_revisions WHERE noteId = ?', [req.params.noteId]); noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase); @@ -94,7 +93,7 @@ function eraseNoteRevision(req) { function restoreNoteRevision(req) { const noteRevision = repository.getNoteRevision(req.params.noteRevisionId); - if (noteRevision && !noteRevision.isErased) { + if (noteRevision) { const note = noteRevision.getNote(); noteRevisionService.createNoteRevision(note); diff --git a/src/routes/api/recent_changes.js b/src/routes/api/recent_changes.js index 017263405..5b1d9b3ef 100644 --- a/src/routes/api/recent_changes.js +++ b/src/routes/api/recent_changes.js @@ -15,7 +15,6 @@ function getRecentChanges(req) { notes.noteId, notes.isDeleted AS current_isDeleted, notes.deleteId AS current_deleteId, - notes.isErased AS current_isErased, notes.title AS current_title, notes.isProtected AS current_isProtected, note_revisions.title, @@ -23,8 +22,7 @@ function getRecentChanges(req) { note_revisions.dateCreated AS date FROM note_revisions - JOIN notes USING(noteId) - WHERE note_revisions.isErased = 0`); + JOIN notes USING(noteId)`); for (const noteRevision of noteRevisions) { if (noteCacheService.isInAncestor(noteRevision.noteId, ancestorNoteId)) { @@ -40,28 +38,24 @@ function getRecentChanges(req) { notes.noteId, notes.isDeleted AS current_isDeleted, notes.deleteId AS current_deleteId, - notes.isErased AS current_isErased, notes.title AS current_title, notes.isProtected AS current_isProtected, notes.title, notes.utcDateCreated AS utcDate, notes.dateCreated AS date - FROM - notes + FROM notes UNION ALL SELECT notes.noteId, notes.isDeleted AS current_isDeleted, notes.deleteId AS current_deleteId, - notes.isErased AS current_isErased, notes.title AS current_title, notes.isProtected AS current_isProtected, notes.title, notes.utcDateModified AS utcDate, notes.dateModified AS date - FROM - notes - WHERE notes.isDeleted = 1 AND notes.isErased = 0`); + FROM notes + WHERE notes.isDeleted = 1`); for (const note of notes) { if (noteCacheService.isInAncestor(note.noteId, ancestorNoteId)) { @@ -85,17 +79,12 @@ function getRecentChanges(req) { } if (change.current_isDeleted) { - if (change.current_isErased) { - change.canBeUndeleted = false; - } - else { - const deleteId = change.current_deleteId; + const deleteId = change.current_deleteId; - const undeletedParentBranches = noteService.getUndeletedParentBranches(change.noteId, deleteId); + const undeletedParentBranches = noteService.getUndeletedParentBranches(change.noteId, deleteId); - // note (and the subtree) can be undeleted if there's at least one undeleted parent (whose branch would be undeleted by this op) - change.canBeUndeleted = undeletedParentBranches.length > 0; - } + // note (and the subtree) can be undeleted if there's at least one undeleted parent (whose branch would be undeleted by this op) + change.canBeUndeleted = undeletedParentBranches.length > 0; } } diff --git a/src/services/consistency_checks.js b/src/services/consistency_checks.js index 575cdcccd..cb7044c9f 100644 --- a/src/services/consistency_checks.js +++ b/src/services/consistency_checks.js @@ -12,6 +12,7 @@ const optionsService = require('./options'); const Branch = require('../entities/branch'); const dateUtils = require('./date_utils'); const attributeService = require('./attributes'); +const noteRevisionService = require('./note_revisions'); class ConsistencyChecks { constructor(autoFix) { @@ -304,7 +305,7 @@ class ConsistencyChecks { } else { // empty string might be wrong choice for some note types but it's a best guess - note.setContent(note.isErased ? null : ''); + note.setContent(''); } logFix(`Note ${noteId} content was set to empty string since there was no corresponding row`); @@ -332,53 +333,6 @@ class ConsistencyChecks { } }); - this.findAndFixIssues(` - SELECT noteId - FROM notes - JOIN note_contents USING (noteId) - WHERE isErased = 1 - AND content IS NOT NULL`, - ({noteId}) => { - - // we always fix this issue because there does not seem to be a good way to prevent it. - // Scenario in which this can happen: - // 1. user on instance A deletes the note (sync for notes is created, but not for note_contents) and is later erased - // 2. instance B gets synced from instance A, note is updated because of entity change for notes, - // but note_contents is not because erasion does not create entity change rows - // 3. therefore note.isErased = true, but note_contents.content remains not updated and not erased. - // - // Considered solutions: - // - don't sync erased notes - this might prevent syncing also of the isDeleted flag and note would continue - // to exist on the other instance - // - create entity changes for erased event - this would be a problem for undeletion since erasion might happen - // on one instance after undelete and thus would win even though there's no user action behind it - // - // So instead we just fix such cases afterwards here. - - sql.execute(`UPDATE note_contents SET content = NULL WHERE noteId = ?`, [noteId]); - - logFix(`Note ${noteId} content has been set to null since the note is erased`); - }); - - this.findAndFixIssues(` - SELECT noteId, noteRevisionId - FROM notes - JOIN note_revisions USING (noteId) - WHERE notes.isErased = 1 - AND note_revisions.isErased = 0`, - ({noteId, noteRevisionId}) => { - if (this.autoFix) { - const noteRevision = repository.getNoteRevision(noteRevisionId); - noteRevision.isErased = true; - noteRevision.setContent(null); - noteRevision.save(); - - logFix(`Note revision ${noteRevisionId} has been erased since its note ${noteId} is also erased.`); - } else { - logError(`Note revision ${noteRevisionId} is not erased even though note ${noteId} is erased.`); - } - }); - this.findAndFixIssues(` SELECT note_revisions.noteRevisionId FROM note_revisions @@ -387,10 +341,7 @@ class ConsistencyChecks { AND note_revisions.isProtected = 0`, ({noteRevisionId}) => { if (this.autoFix) { - const noteRevision = repository.getNoteRevision(noteRevisionId); - noteRevision.setContent(null); - noteRevision.isErased = true; - noteRevision.save(); + noteRevisionService.eraseNoteRevisions([noteRevisionId]); logFix(`Note revision content ${noteRevisionId} was created and set to erased since it did not exist.`); } else { @@ -398,59 +349,6 @@ class ConsistencyChecks { } }); - this.findAndFixIssues(` - SELECT noteRevisionId - FROM note_revisions - JOIN note_revision_contents USING (noteRevisionId) - WHERE isErased = 0 - AND content IS NULL`, - ({noteRevisionId}) => { - if (this.autoFix) { - const noteRevision = repository.getNoteRevision(noteRevisionId); - noteRevision.isErased = true; - noteRevision.save(); - - logFix(`Note revision ${noteRevisionId} content was set to erased since it was null even though it was not erased`); - } else { - logError(`Note revision ${noteRevisionId} content is null even though it is not erased`); - } - }); - - this.findAndFixIssues(` - SELECT noteRevisionId - FROM note_revisions - JOIN note_revision_contents USING (noteRevisionId) - WHERE isErased = 1 - AND content IS NOT NULL`, - ({noteRevisionId}) => { - if (this.autoFix) { - sql.execute(`UPDATE note_revision_contents SET content = NULL WHERE noteRevisionId = ?`, [noteRevisionId]); - - logFix(`Note revision ${noteRevisionId} content was set to null since the note revision is erased`); - } - else { - logError(`Note revision ${noteRevisionId} content is not null even though the note revision is erased`); - } - }); - - this.findAndFixIssues(` - SELECT noteId - FROM notes - WHERE isErased = 1 - AND isDeleted = 0`, - ({noteId}) => { - if (this.autoFix) { - const note = repository.getNote(noteId); - note.isDeleted = true; - note.save(); - - logFix(`Note ${noteId} was set to deleted since it is erased`); - } - else { - logError(`Note ${noteId} is not deleted even though it is erased`); - } - }); - this.findAndFixIssues(` SELECT parentNoteId FROM branches @@ -661,36 +559,18 @@ class ConsistencyChecks { return !this.unrecoveredConsistencyErrors; } - showEntityStat(name, query) { - const map = sql.getMap(query); - - map[0] = map[0] || 0; - map[1] = map[1] || 0; - - log.info(`${name} deleted: ${map[1]}, not deleted ${map[0]}`); - } - runDbDiagnostics() { - this.showEntityStat("Notes", - `SELECT isDeleted, count(1) - FROM notes - GROUP BY isDeleted`); - this.showEntityStat("Note revisions", - `SELECT isErased, count(1) - FROM note_revisions - GROUP BY isErased`); - this.showEntityStat("Branches", - `SELECT isDeleted, count(1) - FROM branches - GROUP BY isDeleted`); - this.showEntityStat("Attributes", - `SELECT isDeleted, count(1) - FROM attributes - GROUP BY isDeleted`); - this.showEntityStat("API tokens", - `SELECT isDeleted, count(1) - FROM api_tokens - GROUP BY isDeleted`); + function showEntityStat(tableName) { + const count = sql.getValue(`SELECT COUNT(1) FROM ${tableName}`); + + log.info(`${tableName}: ${count}`); + } + + showEntityStat("notes"); + showEntityStat("note_revisions"); + showEntityStat("branches"); + showEntityStat("attributes"); + showEntityStat("api_tokens"); } async runChecks() {