mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
rename "note revision" to just "revision"
This commit is contained in:
parent
cb9feab7b2
commit
779751a234
@ -2,7 +2,7 @@
|
||||
UPDATE etapi_tokens SET tokenHash = 'API token hash value';
|
||||
UPDATE notes SET title = 'title' WHERE noteId != 'root' AND noteId NOT LIKE '\_%' ESCAPE '\';
|
||||
UPDATE blobs SET content = 'text' WHERE content IS NOT NULL;
|
||||
UPDATE note_revisions SET title = 'title';
|
||||
UPDATE revisions SET title = 'title';
|
||||
|
||||
UPDATE attributes SET name = 'name', value = 'value'
|
||||
WHERE type = 'label'
|
||||
@ -28,7 +28,7 @@ UPDATE attributes SET name = 'name', value = 'value'
|
||||
'widget',
|
||||
'noteInfoWidgetDisabled',
|
||||
'linkMapWidgetDisabled',
|
||||
'noteRevisionsWidgetDisabled',
|
||||
'revisionsWidgetDisabled',
|
||||
'whatLinksHereWidgetDisabled',
|
||||
'similarNotesWidgetDisabled',
|
||||
'workspace',
|
||||
@ -103,7 +103,7 @@ UPDATE attributes SET name = 'name'
|
||||
'widget',
|
||||
'noteInfoWidgetDisabled',
|
||||
'linkMapWidgetDisabled',
|
||||
'noteRevisionsWidgetDisabled',
|
||||
'revisionsWidgetDisabled',
|
||||
'whatLinksHereWidgetDisabled',
|
||||
'similarNotesWidgetDisabled',
|
||||
'workspace',
|
||||
|
25
db/migrations/0221__rename_note_revision_to_revision.sql
Normal file
25
db/migrations/0221__rename_note_revision_to_revision.sql
Normal file
@ -0,0 +1,25 @@
|
||||
CREATE TABLE IF NOT EXISTS "revisions" (`revisionId` TEXT NOT NULL PRIMARY KEY,
|
||||
`noteId` TEXT NOT NULL,
|
||||
type TEXT DEFAULT '' NOT NULL,
|
||||
mime TEXT DEFAULT '' NOT NULL,
|
||||
`title` TEXT NOT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
blobId TEXT DEFAULT NULL,
|
||||
`utcDateLastEdited` TEXT NOT NULL,
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
`dateLastEdited` TEXT NOT NULL,
|
||||
`dateCreated` TEXT NOT NULL);
|
||||
|
||||
INSERT INTO revisions (revisionId, noteId, type, mime, title, isProtected, utcDateLastEdited, utcDateCreated, utcDateModified, dateLastEdited, dateCreated, blobId)
|
||||
SELECT noteRevisionId, noteId, type, mime, title, isProtected, utcDateLastEdited, utcDateCreated, utcDateModified, dateLastEdited, dateCreated, blobId FROM note_revisions;
|
||||
|
||||
DROP TABLE note_revisions;
|
||||
|
||||
CREATE INDEX `IDX_revisions_noteId` ON `revisions` (`noteId`);
|
||||
CREATE INDEX `IDX_revisions_utcDateCreated` ON `revisions` (`utcDateCreated`);
|
||||
CREATE INDEX `IDX_revisions_utcDateLastEdited` ON `revisions` (`utcDateLastEdited`);
|
||||
CREATE INDEX `IDX_revisions_dateCreated` ON `revisions` (`dateCreated`);
|
||||
CREATE INDEX `IDX_revisions_dateLastEdited` ON `revisions` (`dateLastEdited`);
|
||||
|
||||
UPDATE entity_changes SET entity_name = 'revisions' WHERE entity_name = 'note_revisions';
|
@ -35,24 +35,26 @@ CREATE TABLE IF NOT EXISTS "notes" (
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
`type` TEXT NOT NULL DEFAULT 'text',
|
||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||
blobId TEXT DEFAULT NULL,
|
||||
`isDeleted` INT NOT NULL DEFAULT 0,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
`dateCreated` TEXT NOT NULL,
|
||||
`dateModified` TEXT NOT NULL,
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL, blobId TEXT DEFAULT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
PRIMARY KEY(`noteId`));
|
||||
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
||||
CREATE TABLE IF NOT EXISTS "revisions" (`revisionId` TEXT NOT NULL PRIMARY KEY,
|
||||
`noteId` TEXT NOT NULL,
|
||||
type TEXT DEFAULT '' NOT NULL,
|
||||
mime TEXT DEFAULT '' NOT NULL,
|
||||
`title` TEXT NOT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
blobId TEXT DEFAULT NULL,
|
||||
`utcDateLastEdited` TEXT NOT NULL,
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
`dateLastEdited` TEXT NOT NULL,
|
||||
`dateCreated` TEXT NOT NULL, blobId TEXT DEFAULT NULL);
|
||||
`dateCreated` TEXT NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "options"
|
||||
(
|
||||
name TEXT not null PRIMARY KEY,
|
||||
@ -84,11 +86,11 @@ CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`);
|
||||
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
|
||||
CREATE INDEX `IDX_note_revisions_noteId` ON `note_revisions` (`noteId`);
|
||||
CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCreated`);
|
||||
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
|
||||
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
|
||||
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
|
||||
CREATE INDEX `IDX_revisions_noteId` ON `revisions` (`noteId`);
|
||||
CREATE INDEX `IDX_revisions_utcDateCreated` ON `revisions` (`utcDateCreated`);
|
||||
CREATE INDEX `IDX_revisions_utcDateLastEdited` ON `revisions` (`utcDateLastEdited`);
|
||||
CREATE INDEX `IDX_revisions_dateCreated` ON `revisions` (`dateCreated`);
|
||||
CREATE INDEX `IDX_revisions_dateLastEdited` ON `revisions` (`dateLastEdited`);
|
||||
CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`);
|
||||
CREATE INDEX IDX_attributes_name_value
|
||||
on attributes (name, value);
|
||||
|
@ -144,12 +144,12 @@ class Becca {
|
||||
return this.childParentToBranch[`${childNoteId}-${parentNoteId}`];
|
||||
}
|
||||
|
||||
/** @returns {BNoteRevision|null} */
|
||||
getNoteRevision(noteRevisionId) {
|
||||
const row = sql.getRow("SELECT * FROM note_revisions WHERE noteRevisionId = ?", [noteRevisionId]);
|
||||
/** @returns {BRevision|null} */
|
||||
getRevision(revisionId) {
|
||||
const row = sql.getRow("SELECT * FROM revisions WHERE revisionId = ?", [revisionId]);
|
||||
|
||||
const BNoteRevision = require("./entities/bnote_revision"); // avoiding circular dependency problems
|
||||
return row ? new BNoteRevision(row) : null;
|
||||
const BRevision = require("./entities/brevision.js"); // avoiding circular dependency problems
|
||||
return row ? new BRevision(row) : null;
|
||||
}
|
||||
|
||||
/** @returns {BAttachment|null} */
|
||||
@ -213,8 +213,8 @@ class Becca {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entityName === 'note_revisions') {
|
||||
return this.getNoteRevision(entityId);
|
||||
if (entityName === 'revisions') {
|
||||
return this.getRevision(entityId);
|
||||
} else if (entityName === 'attachments') {
|
||||
return this.getAttachment(entityId);
|
||||
} else if (entityName === 'blobs') {
|
||||
@ -243,12 +243,12 @@ class Becca {
|
||||
return rows.map(row => new BRecentNote(row));
|
||||
}
|
||||
|
||||
/** @returns {BNoteRevision[]} */
|
||||
getNoteRevisionsFromQuery(query, params = []) {
|
||||
/** @returns {BRevision[]} */
|
||||
getRevisionsFromQuery(query, params = []) {
|
||||
const rows = sql.getRows(query, params);
|
||||
|
||||
const BNoteRevision = require("./entities/bnote_revision"); // avoiding circular dependency problems
|
||||
return rows.map(row => new BNoteRevision(row));
|
||||
const BRevision = require("./entities/brevision.js"); // avoiding circular dependency problems
|
||||
return rows.map(row => new BRevision(row));
|
||||
}
|
||||
|
||||
/** Should be called when the set of all non-skeleton notes changes (added/removed) */
|
||||
|
@ -170,7 +170,7 @@ class AbstractBeccaEntity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sql.getValue("SELECT 1 FROM note_revisions WHERE blobId = ? LIMIT 1", [blobId])) {
|
||||
if (sql.getValue("SELECT 1 FROM revisions WHERE blobId = ? LIMIT 1", [blobId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class BAttachment extends AbstractBeccaEntity {
|
||||
|
||||
/** @type {string} */
|
||||
this.attachmentId = row.attachmentId;
|
||||
/** @type {string} either noteId or noteRevisionId to which this attachment belongs */
|
||||
/** @type {string} either noteId or revisionId to which this attachment belongs */
|
||||
this.parentId = row.parentId;
|
||||
/** @type {string} */
|
||||
this.role = row.role;
|
||||
|
@ -6,7 +6,7 @@ const sql = require('../../services/sql');
|
||||
const utils = require('../../services/utils');
|
||||
const dateUtils = require('../../services/date_utils');
|
||||
const AbstractBeccaEntity = require("./abstract_becca_entity");
|
||||
const BNoteRevision = require("./bnote_revision");
|
||||
const BRevision = require("./brevision.js");
|
||||
const BAttachment = require("./battachment");
|
||||
const TaskContext = require("../../services/task_context");
|
||||
const dayjs = require("dayjs");
|
||||
@ -1102,10 +1102,10 @@ class BNote extends AbstractBeccaEntity {
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
/** @returns {BNoteRevision[]} */
|
||||
getNoteRevisions() {
|
||||
return sql.getRows("SELECT * FROM note_revisions WHERE noteId = ?", [this.noteId])
|
||||
.map(row => new BNoteRevision(row));
|
||||
/** @returns {BRevision[]} */
|
||||
getRevisions() {
|
||||
return sql.getRows("SELECT * FROM revisions WHERE noteId = ?", [this.noteId])
|
||||
.map(row => new BRevision(row));
|
||||
}
|
||||
|
||||
/** @returns {BAttachment[]} */
|
||||
@ -1571,14 +1571,14 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {BNoteRevision|null}
|
||||
* @returns {BRevision|null}
|
||||
*/
|
||||
saveNoteRevision() {
|
||||
saveRevision() {
|
||||
return sql.transactional(() => {
|
||||
let noteContent = this.getContent();
|
||||
const contentMetadata = this.getContentMetadata();
|
||||
|
||||
const noteRevision = new BNoteRevision({
|
||||
const revision = new BRevision({
|
||||
noteId: this.noteId,
|
||||
// title and text should be decrypted now
|
||||
title: this.title,
|
||||
@ -1596,7 +1596,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
dateCreated: dateUtils.localNowDateTime()
|
||||
}, true);
|
||||
|
||||
noteRevision.save(); // to generate noteRevisionId which is then used to save attachments
|
||||
revision.save(); // to generate revisionId which is then used to save attachments
|
||||
|
||||
for (const noteAttachment of this.getAttachments()) {
|
||||
if (noteAttachment.utcDateScheduledForErasureSince) {
|
||||
@ -1604,16 +1604,16 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
const revisionAttachment = noteAttachment.copy();
|
||||
revisionAttachment.parentId = noteRevision.noteRevisionId;
|
||||
revisionAttachment.parentId = revision.revisionId;
|
||||
revisionAttachment.setContent(noteAttachment.getContent(), { forceSave: true });
|
||||
|
||||
// content is rewritten to point to the revision attachments
|
||||
noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`, `attachments/${revisionAttachment.attachmentId}`);
|
||||
}
|
||||
|
||||
noteRevision.setContent(noteContent, { forceSave: true });
|
||||
revision.setContent(noteContent, { forceSave: true });
|
||||
|
||||
return noteRevision;
|
||||
return revision;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -9,21 +9,21 @@ const sql = require("../../services/sql");
|
||||
const BAttachment = require("./battachment");
|
||||
|
||||
/**
|
||||
* NoteRevision represents a snapshot of note's title and content at some point in the past.
|
||||
* Revision represents a snapshot of note's title and content at some point in the past.
|
||||
* It's used for seamless note versioning.
|
||||
*
|
||||
* @extends AbstractBeccaEntity
|
||||
*/
|
||||
class BNoteRevision extends AbstractBeccaEntity {
|
||||
static get entityName() { return "note_revisions"; }
|
||||
static get primaryKeyName() { return "noteRevisionId"; }
|
||||
static get hashedProperties() { return ["noteRevisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; }
|
||||
class BRevision extends AbstractBeccaEntity {
|
||||
static get entityName() { return "revisions"; }
|
||||
static get primaryKeyName() { return "revisionId"; }
|
||||
static get hashedProperties() { return ["revisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; }
|
||||
|
||||
constructor(row, titleDecrypted = false) {
|
||||
super();
|
||||
|
||||
/** @type {string} */
|
||||
this.noteRevisionId = row.noteRevisionId;
|
||||
this.revisionId = row.revisionId;
|
||||
/** @type {string} */
|
||||
this.noteId = row.noteId;
|
||||
/** @type {string} */
|
||||
@ -66,14 +66,14 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
isContentAvailable() {
|
||||
return !this.noteRevisionId // new note which was not encrypted yet
|
||||
return !this.revisionId // new note which was not encrypted yet
|
||||
|| !this.isProtected
|
||||
|| protectedSessionService.isProtectedSessionAvailable()
|
||||
}
|
||||
|
||||
/*
|
||||
* Note revision content has quite special handling - it's not a separate entity, but a lazily loaded
|
||||
* part of NoteRevision entity with its own sync. The reason behind this hybrid design is that
|
||||
* part of Revision entity with its own sync. The reason behind this hybrid design is that
|
||||
* content can be quite large, and it's not necessary to load it / fill memory for any note access even
|
||||
* if we don't need a content, especially for bulk operations like search.
|
||||
*
|
||||
@ -88,7 +88,7 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
/**
|
||||
* @param content
|
||||
* @param {object} [opts]
|
||||
* @param {object} [opts.forceSave=false] - will also save this BNoteRevision entity
|
||||
* @param {object} [opts.forceSave=false] - will also save this BRevision entity
|
||||
*/
|
||||
setContent(content, opts) {
|
||||
this._setContent(content, opts);
|
||||
@ -100,7 +100,7 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
SELECT attachments.*
|
||||
FROM attachments
|
||||
WHERE parentId = ?
|
||||
AND isDeleted = 0`, [this.noteRevisionId])
|
||||
AND isDeleted = 0`, [this.revisionId])
|
||||
.map(row => new BAttachment(row));
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
|
||||
getPojo() {
|
||||
return {
|
||||
noteRevisionId: this.noteRevisionId,
|
||||
revisionId: this.revisionId,
|
||||
noteId: this.noteId,
|
||||
type: this.type,
|
||||
mime: this.mime,
|
||||
@ -148,4 +148,4 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BNoteRevision;
|
||||
module.exports = BRevision;
|
@ -1,5 +1,5 @@
|
||||
const BNote = require('./entities/bnote');
|
||||
const BNoteRevision = require('./entities/bnote_revision');
|
||||
const BRevision = require('./entities/brevision.js');
|
||||
const BAttachment = require("./entities/battachment");
|
||||
const BBranch = require('./entities/bbranch');
|
||||
const BAttribute = require('./entities/battribute');
|
||||
@ -11,7 +11,7 @@ const ENTITY_NAME_TO_ENTITY = {
|
||||
"attributes": BAttribute,
|
||||
"branches": BBranch,
|
||||
"notes": BNote,
|
||||
"note_revisions": BNoteRevision,
|
||||
"revisions": BRevision,
|
||||
"attachments": BAttachment,
|
||||
"recent_notes": BRecentNote,
|
||||
"etapi_tokens": BEtapiToken,
|
||||
|
@ -24,7 +24,7 @@ const IGNORED_ATTR_NAMES = [
|
||||
"keyboardshortcut",
|
||||
"noteinfowidgetdisabled",
|
||||
"linkmapwidgetdisabled",
|
||||
"noterevisionswidgetdisabled",
|
||||
"revisionswidgetdisabled",
|
||||
"whatlinksherewidgetdisabled",
|
||||
"similarnoteswidgetdisabled",
|
||||
"disableinclusion",
|
||||
|
@ -308,7 +308,7 @@ paths:
|
||||
default: html
|
||||
post:
|
||||
description: Create a note revision for the given note
|
||||
operationId: createNoteRevision
|
||||
operationId: createRevision
|
||||
responses:
|
||||
'204':
|
||||
description: revision has been created
|
||||
|
@ -149,7 +149,7 @@ function register(router) {
|
||||
eu.route(router, 'post' ,'/etapi/notes/:noteId/note-revision', (req, res, next) => {
|
||||
const note = eu.getAndCheckNote(req.params.noteId);
|
||||
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
|
||||
return res.sendStatus(204);
|
||||
});
|
||||
|
@ -197,7 +197,7 @@ export default class Entrypoints extends Component {
|
||||
this.hideAllPopups();
|
||||
}
|
||||
|
||||
async forceSaveNoteRevisionCommand() {
|
||||
async forceSaveRevisionCommand() {
|
||||
const noteId = appContext.tabManager.getActiveContextNoteId();
|
||||
|
||||
await server.post(`notes/${noteId}/revision`);
|
||||
|
@ -61,7 +61,7 @@ import ImportDialog from "../widgets/dialogs/import.js";
|
||||
import ExportDialog from "../widgets/dialogs/export.js";
|
||||
import MarkdownImportDialog from "../widgets/dialogs/markdown_import.js";
|
||||
import ProtectedSessionPasswordDialog from "../widgets/dialogs/protected_session_password.js";
|
||||
import NoteRevisionsDialog from "../widgets/dialogs/note_revisions.js";
|
||||
import RevisionsDialog from "../widgets/dialogs/revisions.js";
|
||||
import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js";
|
||||
import InfoDialog from "../widgets/dialogs/info.js";
|
||||
import ConfirmDialog from "../widgets/dialogs/confirm.js";
|
||||
@ -70,7 +70,7 @@ import FloatingButtons from "../widgets/floating_buttons/floating_buttons.js";
|
||||
import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons.js";
|
||||
import MermaidExportButton from "../widgets/floating_buttons/mermaid_export_button.js";
|
||||
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
||||
import NoteRevisionsButton from "../widgets/buttons/note_revisions_button.js";
|
||||
import RevisionsButton from "../widgets/buttons/revisions_button.js";
|
||||
import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js";
|
||||
import ApiLogWidget from "../widgets/api_log.js";
|
||||
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
|
||||
@ -147,7 +147,7 @@ export default class DesktopLayout {
|
||||
.ribbon(new NoteMapRibbonWidget())
|
||||
.ribbon(new SimilarNotesWidget())
|
||||
.ribbon(new NoteInfoWidget())
|
||||
.button(new NoteRevisionsButton())
|
||||
.button(new RevisionsButton())
|
||||
.button(new NoteActionsWidget())
|
||||
)
|
||||
.child(new SharedInfoWidget())
|
||||
@ -204,7 +204,7 @@ export default class DesktopLayout {
|
||||
.child(new UploadAttachmentsDialog())
|
||||
.child(new MarkdownImportDialog())
|
||||
.child(new ProtectedSessionPasswordDialog())
|
||||
.child(new NoteRevisionsDialog())
|
||||
.child(new RevisionsDialog())
|
||||
.child(new DeleteNotesDialog())
|
||||
.child(new InfoDialog())
|
||||
.child(new ConfirmDialog())
|
||||
|
@ -2,7 +2,7 @@ import server from "./server.js";
|
||||
import ws from "./ws.js";
|
||||
import MoveNoteBulkAction from "../widgets/bulk_actions/note/move_note.js";
|
||||
import DeleteNoteBulkAction from "../widgets/bulk_actions/note/delete_note.js";
|
||||
import DeleteNoteRevisionsBulkAction from "../widgets/bulk_actions/note/delete_note_revisions.js";
|
||||
import DeleteRevisionsBulkAction from "../widgets/bulk_actions/note/delete_revisions.js";
|
||||
import DeleteLabelBulkAction from "../widgets/bulk_actions/label/delete_label.js";
|
||||
import DeleteRelationBulkAction from "../widgets/bulk_actions/relation/delete_relation.js";
|
||||
import RenameLabelBulkAction from "../widgets/bulk_actions/label/rename_label.js";
|
||||
@ -25,7 +25,7 @@ const ACTION_GROUPS = [
|
||||
},
|
||||
{
|
||||
title: 'Notes',
|
||||
actions: [RenameNoteBulkAction, MoveNoteBulkAction, DeleteNoteBulkAction, DeleteNoteRevisionsBulkAction],
|
||||
actions: [RenameNoteBulkAction, MoveNoteBulkAction, DeleteNoteBulkAction, DeleteRevisionsBulkAction],
|
||||
},
|
||||
{
|
||||
title: 'Other',
|
||||
@ -37,7 +37,7 @@ const ACTION_CLASSES = [
|
||||
RenameNoteBulkAction,
|
||||
MoveNoteBulkAction,
|
||||
DeleteNoteBulkAction,
|
||||
DeleteNoteRevisionsBulkAction,
|
||||
DeleteRevisionsBulkAction,
|
||||
DeleteLabelBulkAction,
|
||||
DeleteRelationBulkAction,
|
||||
RenameLabelBulkAction,
|
||||
|
@ -30,8 +30,8 @@ async function processEntityChanges(entityChanges) {
|
||||
}
|
||||
|
||||
loadResults.addNoteContent(ec.noteIds, ec.componentId);
|
||||
} else if (ec.entityName === 'note_revisions') {
|
||||
loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId);
|
||||
} else if (ec.entityName === 'revisions') {
|
||||
loadResults.addRevision(ec.entityId, ec.noteId, ec.componentId);
|
||||
} else if (ec.entityName === 'options') {
|
||||
if (ec.entity.name === 'openNoteContexts') {
|
||||
continue; // only noise
|
||||
|
@ -18,7 +18,7 @@ export default class LoadResults {
|
||||
|
||||
this.noteReorderings = [];
|
||||
|
||||
this.noteRevisions = [];
|
||||
this.revisions = [];
|
||||
|
||||
this.contentNoteIdToComponentId = [];
|
||||
|
||||
@ -75,12 +75,12 @@ export default class LoadResults {
|
||||
.filter(attr => !!attr);
|
||||
}
|
||||
|
||||
addNoteRevision(noteRevisionId, noteId, componentId) {
|
||||
this.noteRevisions.push({noteRevisionId, noteId, componentId});
|
||||
addRevision(revisionId, noteId, componentId) {
|
||||
this.revisions.push({revisionId, noteId, componentId});
|
||||
}
|
||||
|
||||
hasNoteRevisionForNote(noteId) {
|
||||
return !!this.noteRevisions.find(nr => nr.noteId === noteId);
|
||||
hasRevisionForNote(noteId) {
|
||||
return !!this.revisions.find(nr => nr.noteId === noteId);
|
||||
}
|
||||
|
||||
getNoteIds() {
|
||||
@ -140,7 +140,7 @@ export default class LoadResults {
|
||||
&& this.branches.length === 0
|
||||
&& this.attributes.length === 0
|
||||
&& this.noteReorderings.length === 0
|
||||
&& this.noteRevisions.length === 0
|
||||
&& this.revisions.length === 0
|
||||
&& this.contentNoteIdToComponentId.length === 0
|
||||
&& this.options.length === 0
|
||||
&& this.attachments.length === 0;
|
||||
|
@ -102,8 +102,8 @@ async function openNoteCustom(noteId) {
|
||||
}
|
||||
}
|
||||
|
||||
function downloadNoteRevision(noteId, noteRevisionId) {
|
||||
const url = getUrlForDownload(`api/revisions/${noteRevisionId}/download`);
|
||||
function downloadRevision(noteId, revisionId) {
|
||||
const url = getUrlForDownload(`api/revisions/${revisionId}/download`);
|
||||
|
||||
download(url);
|
||||
}
|
||||
@ -164,7 +164,7 @@ function getHost() {
|
||||
export default {
|
||||
download,
|
||||
downloadFileNote,
|
||||
downloadNoteRevision,
|
||||
downloadRevision,
|
||||
downloadAttachment,
|
||||
getUrlForDownload,
|
||||
openNoteExternally,
|
||||
|
@ -19,8 +19,8 @@ const TPL = `
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class DeleteNoteRevisionsBulkAction extends AbstractBulkAction {
|
||||
static get actionName() { return "deleteNoteRevisions"; }
|
||||
export default class DeleteRevisionsBulkAction extends AbstractBulkAction {
|
||||
static get actionName() { return "deleteRevisions"; }
|
||||
static get actionTitle() { return "Delete note revisions"; }
|
||||
|
||||
doRender() {
|
@ -1,12 +1,12 @@
|
||||
import CommandButtonWidget from "./command_button.js";
|
||||
|
||||
export default class NoteRevisionsButton extends CommandButtonWidget {
|
||||
export default class RevisionsButton extends CommandButtonWidget {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.icon('bx-history')
|
||||
.title("Note Revisions")
|
||||
.command("showNoteRevisions")
|
||||
.command("showRevisions")
|
||||
.titlePlacement("bottom")
|
||||
.class("icon-action");
|
||||
}
|
@ -72,13 +72,13 @@ const TPL = `
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class NoteRevisionsDialog extends BasicWidget {
|
||||
export default class RevisionsDialog extends BasicWidget {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.revisionItems = [];
|
||||
this.note = null;
|
||||
this.noteRevisionId = null;
|
||||
this.revisionId = null;
|
||||
}
|
||||
|
||||
doRender() {
|
||||
@ -100,7 +100,7 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
});
|
||||
|
||||
this.$widget.on('shown.bs.modal', () => {
|
||||
this.$list.find(`[data-note-revision-id="${this.noteRevisionId}"]`)
|
||||
this.$list.find(`[data-note-revision-id="${this.revisionId}"]`)
|
||||
.trigger('focus');
|
||||
});
|
||||
|
||||
@ -130,13 +130,13 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
});
|
||||
}
|
||||
|
||||
async showNoteRevisionsEvent({noteId = appContext.tabManager.getActiveContextNoteId()}) {
|
||||
async showRevisionsEvent({noteId = appContext.tabManager.getActiveContextNoteId()}) {
|
||||
utils.openDialog(this.$widget);
|
||||
|
||||
await this.loadNoteRevisions(noteId);
|
||||
await this.loadRevisions(noteId);
|
||||
}
|
||||
|
||||
async loadNoteRevisions(noteId) {
|
||||
async loadRevisions(noteId) {
|
||||
this.$list.empty();
|
||||
this.$content.empty();
|
||||
this.$titleButtons.empty();
|
||||
@ -148,7 +148,7 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
this.$list.append(
|
||||
$('<a class="dropdown-item" tabindex="0">')
|
||||
.text(`${item.dateLastEdited.substr(0, 16)} (${item.contentLength} bytes)`)
|
||||
.attr('data-note-revision-id', item.noteRevisionId)
|
||||
.attr('data-note-revision-id', item.revisionId)
|
||||
.attr('title', `This revision was last edited on ${item.dateLastEdited}`)
|
||||
);
|
||||
}
|
||||
@ -156,21 +156,21 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
this.$listDropdown.dropdown('show');
|
||||
|
||||
if (this.revisionItems.length > 0) {
|
||||
if (!this.noteRevisionId) {
|
||||
this.noteRevisionId = this.revisionItems[0].noteRevisionId;
|
||||
if (!this.revisionId) {
|
||||
this.revisionId = this.revisionItems[0].revisionId;
|
||||
}
|
||||
} else {
|
||||
this.$title.text("No revisions for this note yet...");
|
||||
this.noteRevisionId = null;
|
||||
this.revisionId = null;
|
||||
}
|
||||
|
||||
this.$eraseAllRevisionsButton.toggle(this.revisionItems.length > 0);
|
||||
}
|
||||
|
||||
async setContentPane() {
|
||||
const noteRevisionId = this.$list.find(".active").attr('data-note-revision-id');
|
||||
const revisionId = this.$list.find(".active").attr('data-note-revision-id');
|
||||
|
||||
const revisionItem = this.revisionItems.find(r => r.noteRevisionId === noteRevisionId);
|
||||
const revisionItem = this.revisionItems.find(r => r.revisionId === revisionId);
|
||||
|
||||
this.$title.html(revisionItem.title);
|
||||
|
||||
@ -188,7 +188,7 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
const text = 'Do you want to restore this revision? This will overwrite current title/content of the note with this revision.';
|
||||
|
||||
if (await dialogService.confirm(text)) {
|
||||
await server.post(`revisions/${revisionItem.noteRevisionId}/restore`);
|
||||
await server.post(`revisions/${revisionItem.revisionId}/restore`);
|
||||
|
||||
this.$widget.modal('hide');
|
||||
|
||||
@ -202,9 +202,9 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
const text = 'Do you want to delete this revision? This action will delete revision title and content, but still preserve revision metadata.';
|
||||
|
||||
if (await dialogService.confirm(text)) {
|
||||
await server.remove(`revisions/${revisionItem.noteRevisionId}`);
|
||||
await server.remove(`revisions/${revisionItem.revisionId}`);
|
||||
|
||||
this.loadNoteRevisions(revisionItem.noteId);
|
||||
this.loadRevisions(revisionItem.noteId);
|
||||
|
||||
toastService.showMessage('Note revision has been deleted.');
|
||||
}
|
||||
@ -222,7 +222,7 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
|
||||
const $downloadButton = $('<button class="btn btn-sm btn-primary" type="button">Download</button>');
|
||||
|
||||
$downloadButton.on('click', () => openService.downloadNoteRevision(revisionItem.noteId, revisionItem.noteRevisionId));
|
||||
$downloadButton.on('click', () => openService.downloadRevision(revisionItem.noteId, revisionItem.revisionId));
|
||||
|
||||
if (!revisionItem.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||
this.$titleButtons.append($downloadButton);
|
||||
@ -232,10 +232,10 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
async renderContent(revisionItem) {
|
||||
this.$content.empty();
|
||||
|
||||
const fullNoteRevision = await server.get(`revisions/${revisionItem.noteRevisionId}`);
|
||||
const fullRevision = await server.get(`revisions/${revisionItem.revisionId}`);
|
||||
|
||||
if (revisionItem.type === 'text') {
|
||||
this.$content.html(fullNoteRevision.content);
|
||||
this.$content.html(fullRevision.content);
|
||||
|
||||
if (this.$content.find('span.math-tex').length > 0) {
|
||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
||||
@ -243,12 +243,12 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
renderMathInElement(this.$content[0], {trust: true});
|
||||
}
|
||||
} else if (revisionItem.type === 'code' || revisionItem.type === 'mermaid') {
|
||||
this.$content.html($("<pre>").text(fullNoteRevision.content));
|
||||
this.$content.html($("<pre>").text(fullRevision.content));
|
||||
} else if (revisionItem.type === 'image') {
|
||||
this.$content.html($("<img>")
|
||||
// reason why we put this inline as base64 is that we do not want to let user copy this
|
||||
// as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be an uploaded as a new note
|
||||
.attr("src", `data:${fullNoteRevision.mime};base64,${fullNoteRevision.content}`)
|
||||
.attr("src", `data:${fullRevision.mime};base64,${fullRevision.content}`)
|
||||
.css("max-width", "100%")
|
||||
.css("max-height", "100%"));
|
||||
} else if (revisionItem.type === 'file') {
|
||||
@ -262,12 +262,12 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
$("<td>").text(`${revisionItem.contentLength} bytes`)
|
||||
));
|
||||
|
||||
if (fullNoteRevision.content) {
|
||||
if (fullRevision.content) {
|
||||
$table.append($("<tr>").append(
|
||||
$('<td colspan="2">').append(
|
||||
$('<div style="font-weight: bold;">').text("Preview:"),
|
||||
$('<pre class="file-preview-content"></pre>')
|
||||
.text(fullNoteRevision.content)
|
||||
.text(fullRevision.content)
|
||||
)
|
||||
));
|
||||
}
|
||||
@ -278,7 +278,7 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
* FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com
|
||||
* REMOVE external dependency!!!! This is defined in the svg in defs.style
|
||||
*/
|
||||
const content = fullNoteRevision.content;
|
||||
const content = fullRevision.content;
|
||||
|
||||
try {
|
||||
const data = JSON.parse(content)
|
||||
@ -291,7 +291,7 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
||||
const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"});
|
||||
this.$content.html($('<div>').append($svgHtml));
|
||||
} catch (err) {
|
||||
console.error("error parsing fullNoteRevision.content as JSON", fullNoteRevision.content, err);
|
||||
console.error("error parsing fullRevision.content as JSON", fullRevision.content, err);
|
||||
this.$content.html($("<div>").text("Error parsing content. Please check console.error() for more details."));
|
||||
}
|
||||
} else {
|
@ -21,7 +21,7 @@ import SyncOptions from "./options/sync.js";
|
||||
import SearchEngineOptions from "./options/other/search_engine.js";
|
||||
import TrayOptions from "./options/other/tray.js";
|
||||
import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js";
|
||||
import NoteRevisionsSnapshotIntervalOptions from "./options/other/note_revisions_snapshot_interval.js";
|
||||
import RevisionsSnapshotIntervalOptions from "./options/other/revisions_snapshot_interval.js";
|
||||
import NetworkConnectionsOptions from "./options/other/network_connections.js";
|
||||
import AdvancedSyncOptions from "./options/advanced/sync.js";
|
||||
import DatabaseIntegrityCheckOptions from "./options/advanced/database_integrity_check.js";
|
||||
@ -81,7 +81,7 @@ const CONTENT_WIDGETS = {
|
||||
TrayOptions,
|
||||
NoteErasureTimeoutOptions,
|
||||
AttachmentErasureTimeoutOptions,
|
||||
NoteRevisionsSnapshotIntervalOptions,
|
||||
RevisionsSnapshotIntervalOptions,
|
||||
NetworkConnectionsOptions
|
||||
],
|
||||
_optionsAdvanced: [
|
||||
|
@ -12,15 +12,15 @@ const TPL = `
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class NoteRevisionsSnapshotIntervalOptions extends OptionsWidget {
|
||||
export default class RevisionsSnapshotIntervalOptions extends OptionsWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$noteRevisionsTimeInterval = this.$widget.find(".note-revision-snapshot-time-interval-in-seconds");
|
||||
this.$noteRevisionsTimeInterval.on('change', () =>
|
||||
this.updateOption('noteRevisionSnapshotTimeInterval', this.$noteRevisionsTimeInterval.val()));
|
||||
this.$revisionsTimeInterval = this.$widget.find(".note-revision-snapshot-time-interval-in-seconds");
|
||||
this.$revisionsTimeInterval.on('change', () =>
|
||||
this.updateOption('revisionSnapshotTimeInterval', this.$revisionsTimeInterval.val()));
|
||||
}
|
||||
|
||||
async optionsLoaded(options) {
|
||||
this.$noteRevisionsTimeInterval.val(options.noteRevisionSnapshotTimeInterval);
|
||||
this.$revisionsTimeInterval.val(options.revisionSnapshotTimeInterval);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ function updateFile(req) {
|
||||
const note = becca.getNoteOrThrow(req.params.noteId);
|
||||
|
||||
const file = req.file;
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
|
||||
note.mime = file.mimetype.toLowerCase();
|
||||
note.save();
|
||||
@ -35,7 +35,7 @@ function updateFile(req) {
|
||||
function updateAttachment(req) {
|
||||
const attachment = becca.getAttachmentOrThrow(req.params.attachmentId);
|
||||
const file = req.file;
|
||||
attachment.getNote().saveNoteRevision();
|
||||
attachment.getNote().saveRevision();
|
||||
|
||||
attachment.mime = file.mimetype.toLowerCase();
|
||||
attachment.setContent(file.buffer, {forceSave: true});
|
||||
@ -186,7 +186,7 @@ function uploadModifiedFileToNote(req) {
|
||||
|
||||
log.info(`Updating note '${noteId}' with content from '${filePath}'`);
|
||||
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
|
||||
const fileContent = fs.readFileSync(filePath);
|
||||
|
||||
@ -205,7 +205,7 @@ function uploadModifiedFileToAttachment(req) {
|
||||
|
||||
log.info(`Updating attachment '${attachmentId}' with content from '${filePath}'`);
|
||||
|
||||
attachment.getNote().saveNoteRevision();
|
||||
attachment.getNote().saveRevision();
|
||||
|
||||
const fileContent = fs.readFileSync(filePath);
|
||||
|
||||
|
@ -131,7 +131,7 @@ function changeTitle(req) {
|
||||
const noteTitleChanged = note.title !== title;
|
||||
|
||||
if (noteTitleChanged) {
|
||||
noteService.saveNoteRevisionIfNeeded(note);
|
||||
noteService.saveRevisionIfNeeded(note);
|
||||
}
|
||||
|
||||
note.title = title;
|
||||
@ -216,7 +216,7 @@ function getDeleteNotesPreview(req) {
|
||||
};
|
||||
}
|
||||
|
||||
function forceSaveNoteRevision(req) {
|
||||
function forceSaveRevision(req) {
|
||||
const {noteId} = req.params;
|
||||
const note = becca.getNoteOrThrow(noteId);
|
||||
|
||||
@ -224,7 +224,7 @@ function forceSaveNoteRevision(req) {
|
||||
throw new ValidationError(`Note revision of a protected note cannot be created outside of a protected session.`);
|
||||
}
|
||||
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
}
|
||||
|
||||
function convertNoteToAttachment(req) {
|
||||
@ -252,6 +252,6 @@ module.exports = {
|
||||
eraseDeletedNotesNow,
|
||||
eraseUnusedAttachmentsNow,
|
||||
getDeleteNotesPreview,
|
||||
forceSaveNoteRevision,
|
||||
forceSaveRevision,
|
||||
convertNoteToAttachment
|
||||
};
|
||||
|
@ -9,7 +9,7 @@ const ValidationError = require("../../errors/validation_error");
|
||||
const ALLOWED_OPTIONS = new Set([
|
||||
'eraseEntitiesAfterTimeInSeconds',
|
||||
'protectedSessionTimeout',
|
||||
'noteRevisionSnapshotTimeInterval',
|
||||
'revisionSnapshotTimeInterval',
|
||||
'zoomFactor',
|
||||
'theme',
|
||||
'syncServerHost',
|
||||
@ -28,7 +28,7 @@ const ALLOWED_OPTIONS = new Set([
|
||||
'noteInfoWidget',
|
||||
'attributesWidget',
|
||||
'linkMapWidget',
|
||||
'noteRevisionsWidget',
|
||||
'revisionsWidget',
|
||||
'whatLinksHereWidget',
|
||||
'similarNotesWidget',
|
||||
'editedNotesWidget',
|
||||
|
@ -10,25 +10,25 @@ function getRecentChanges(req) {
|
||||
|
||||
let recentChanges = [];
|
||||
|
||||
const noteRevisionRows = sql.getRows(`
|
||||
const revisionRows = sql.getRows(`
|
||||
SELECT
|
||||
notes.noteId,
|
||||
notes.isDeleted AS current_isDeleted,
|
||||
notes.deleteId AS current_deleteId,
|
||||
notes.title AS current_title,
|
||||
notes.isProtected AS current_isProtected,
|
||||
note_revisions.title,
|
||||
note_revisions.utcDateCreated AS utcDate,
|
||||
note_revisions.dateCreated AS date
|
||||
revisions.title,
|
||||
revisions.utcDateCreated AS utcDate,
|
||||
revisions.dateCreated AS date
|
||||
FROM
|
||||
note_revisions
|
||||
revisions
|
||||
JOIN notes USING(noteId)`);
|
||||
|
||||
for (const noteRevisionRow of noteRevisionRows) {
|
||||
const note = becca.getNote(noteRevisionRow.noteId);
|
||||
for (const revisionRow of revisionRows) {
|
||||
const note = becca.getNote(revisionRow.noteId);
|
||||
|
||||
if (note?.hasAncestor(ancestorNoteId)) {
|
||||
recentChanges.push(noteRevisionRow);
|
||||
recentChanges.push(revisionRow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const beccaService = require('../../becca/becca_service');
|
||||
const noteRevisionService = require('../../services/note_revisions');
|
||||
const revisionService = require('../../services/revisions.js');
|
||||
const utils = require('../../services/utils');
|
||||
const sql = require('../../services/sql');
|
||||
const cls = require('../../services/cls');
|
||||
@ -9,50 +9,50 @@ const path = require('path');
|
||||
const becca = require("../../becca/becca");
|
||||
const blobService = require("../../services/blob.js");
|
||||
|
||||
function getNoteRevisionBlob(req) {
|
||||
function getRevisionBlob(req) {
|
||||
const preview = req.query.preview === 'true';
|
||||
|
||||
return blobService.getBlobPojo('note_revisions', req.params.noteRevisionId, { preview });
|
||||
return blobService.getBlobPojo('revisions', req.params.revisionId, { preview });
|
||||
}
|
||||
|
||||
function getNoteRevisions(req) {
|
||||
return becca.getNoteRevisionsFromQuery(`
|
||||
SELECT note_revisions.*,
|
||||
function getRevisions(req) {
|
||||
return becca.getRevisionsFromQuery(`
|
||||
SELECT revisions.*,
|
||||
LENGTH(blobs.content) AS contentLength
|
||||
FROM note_revisions
|
||||
JOIN blobs ON note_revisions.blobId = blobs.blobId
|
||||
FROM revisions
|
||||
JOIN blobs ON revisions.blobId = blobs.blobId
|
||||
WHERE noteId = ?
|
||||
ORDER BY utcDateCreated DESC`, [req.params.noteId]);
|
||||
}
|
||||
|
||||
function getNoteRevision(req) {
|
||||
const noteRevision = becca.getNoteRevision(req.params.noteRevisionId);
|
||||
function getRevision(req) {
|
||||
const revision = becca.getRevision(req.params.revisionId);
|
||||
|
||||
if (noteRevision.type === 'file') {
|
||||
if (noteRevision.hasStringContent()) {
|
||||
noteRevision.content = noteRevision.getContent().substr(0, 10000);
|
||||
if (revision.type === 'file') {
|
||||
if (revision.hasStringContent()) {
|
||||
revision.content = revision.getContent().substr(0, 10000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
noteRevision.content = noteRevision.getContent();
|
||||
revision.content = revision.getContent();
|
||||
|
||||
if (noteRevision.content && noteRevision.type === 'image') {
|
||||
noteRevision.content = noteRevision.content.toString('base64');
|
||||
if (revision.content && revision.type === 'image') {
|
||||
revision.content = revision.content.toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
return noteRevision;
|
||||
return revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BNoteRevision} noteRevision
|
||||
* @param {BRevision} revision
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRevisionFilename(noteRevision) {
|
||||
let filename = utils.formatDownloadTitle(noteRevision.title, noteRevision.type, noteRevision.mime);
|
||||
function getRevisionFilename(revision) {
|
||||
let filename = utils.formatDownloadTitle(revision.title, revision.type, revision.mime);
|
||||
|
||||
const extension = path.extname(filename);
|
||||
const date = noteRevision.dateCreated
|
||||
const date = revision.dateCreated
|
||||
.substr(0, 19)
|
||||
.replace(' ', '_')
|
||||
.replace(/[^0-9_]/g, '');
|
||||
@ -67,50 +67,50 @@ function getRevisionFilename(noteRevision) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
function downloadNoteRevision(req, res) {
|
||||
const noteRevision = becca.getNoteRevision(req.params.noteRevisionId);
|
||||
function downloadRevision(req, res) {
|
||||
const revision = becca.getRevision(req.params.revisionId);
|
||||
|
||||
if (!noteRevision.isContentAvailable()) {
|
||||
if (!revision.isContentAvailable()) {
|
||||
return res.setHeader("Content-Type", "text/plain")
|
||||
.status(401)
|
||||
.send("Protected session not available");
|
||||
}
|
||||
|
||||
const filename = getRevisionFilename(noteRevision);
|
||||
const filename = getRevisionFilename(revision);
|
||||
|
||||
res.setHeader('Content-Disposition', utils.getContentDisposition(filename));
|
||||
res.setHeader('Content-Type', noteRevision.mime);
|
||||
res.setHeader('Content-Type', revision.mime);
|
||||
|
||||
res.send(noteRevision.getContent());
|
||||
res.send(revision.getContent());
|
||||
}
|
||||
|
||||
function eraseAllNoteRevisions(req) {
|
||||
const noteRevisionIdsToErase = sql.getColumn('SELECT noteRevisionId FROM note_revisions WHERE noteId = ?',
|
||||
function eraseAllRevisions(req) {
|
||||
const revisionIdsToErase = sql.getColumn('SELECT revisionId FROM revisions WHERE noteId = ?',
|
||||
[req.params.noteId]);
|
||||
|
||||
noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase);
|
||||
revisionService.eraseRevisions(revisionIdsToErase);
|
||||
}
|
||||
|
||||
function eraseNoteRevision(req) {
|
||||
noteRevisionService.eraseNoteRevisions([req.params.noteRevisionId]);
|
||||
function eraseRevision(req) {
|
||||
revisionService.eraseRevisions([req.params.revisionId]);
|
||||
}
|
||||
|
||||
function restoreNoteRevision(req) {
|
||||
const noteRevision = becca.getNoteRevision(req.params.noteRevisionId);
|
||||
function restoreRevision(req) {
|
||||
const revision = becca.getRevision(req.params.revisionId);
|
||||
|
||||
if (noteRevision) {
|
||||
const note = noteRevision.getNote();
|
||||
if (revision) {
|
||||
const note = revision.getNote();
|
||||
|
||||
sql.transactional(() => {
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
|
||||
for (const oldNoteAttachment of note.getAttachments()) {
|
||||
oldNoteAttachment.markAsDeleted();
|
||||
}
|
||||
|
||||
let revisionContent = noteRevision.getContent();
|
||||
let revisionContent = revision.getContent();
|
||||
|
||||
for (const revisionAttachment of noteRevision.getAttachments()) {
|
||||
for (const revisionAttachment of revision.getAttachments()) {
|
||||
const noteAttachment = revisionAttachment.copy();
|
||||
noteAttachment.parentId = note.noteId;
|
||||
noteAttachment.setContent(revisionAttachment.getContent(), { forceSave: true });
|
||||
@ -119,7 +119,7 @@ function restoreNoteRevision(req) {
|
||||
revisionContent = revisionContent.replaceAll(`attachments/${revisionAttachment.attachmentId}`, `attachments/${noteAttachment.attachmentId}`);
|
||||
}
|
||||
|
||||
note.title = noteRevision.title;
|
||||
note.title = revision.title;
|
||||
note.setContent(revisionContent, { forceSave: true });
|
||||
});
|
||||
}
|
||||
@ -134,8 +134,8 @@ function getEditedNotesOnDate(req) {
|
||||
WHERE notes.dateCreated LIKE :date
|
||||
OR notes.dateModified LIKE :date
|
||||
UNION ALL
|
||||
SELECT noteId FROM note_revisions
|
||||
WHERE note_revisions.dateLastEdited LIKE :date
|
||||
SELECT noteId FROM revisions
|
||||
WHERE revisions.dateLastEdited LIKE :date
|
||||
)
|
||||
ORDER BY isDeleted
|
||||
LIMIT 50`, {date: `${req.params.date}%`});
|
||||
@ -186,12 +186,12 @@ function getNotePathData(note) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getNoteRevisionBlob,
|
||||
getNoteRevisions,
|
||||
getNoteRevision,
|
||||
downloadNoteRevision,
|
||||
getRevisionBlob,
|
||||
getRevisions,
|
||||
getRevision,
|
||||
downloadRevision,
|
||||
getEditedNotesOnDate,
|
||||
eraseAllNoteRevisions,
|
||||
eraseNoteRevision,
|
||||
restoreNoteRevision
|
||||
eraseAllRevisions,
|
||||
eraseRevision,
|
||||
restoreRevision
|
||||
};
|
@ -9,10 +9,10 @@ function getNoteSize(req) {
|
||||
FROM blobs
|
||||
LEFT JOIN notes ON notes.blobId = blobs.blobId AND notes.noteId = ? AND notes.isDeleted = 0
|
||||
LEFT JOIN attachments ON attachments.blobId = blobs.blobId AND attachments.parentId = ? AND attachments.isDeleted = 0
|
||||
LEFT JOIN note_revisions ON note_revisions.blobId = blobs.blobId AND note_revisions.noteId = ?
|
||||
LEFT JOIN revisions ON revisions.blobId = blobs.blobId AND revisions.noteId = ?
|
||||
WHERE notes.noteId IS NOT NULL
|
||||
OR attachments.attachmentId IS NOT NULL
|
||||
OR note_revisions.noteRevisionId IS NOT NULL`, [noteId, noteId, noteId]);
|
||||
OR revisions.revisionId IS NOT NULL`, [noteId, noteId, noteId]);
|
||||
|
||||
const noteSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0);
|
||||
|
||||
@ -33,8 +33,8 @@ function getSubtreeSize(req) {
|
||||
FROM param_list
|
||||
JOIN notes ON notes.noteId = param_list.paramId AND notes.isDeleted = 0
|
||||
LEFT JOIN attachments ON attachments.parentId = param_list.paramId AND attachments.isDeleted = 0
|
||||
LEFT JOIN note_revisions ON note_revisions.noteId = param_list.paramId
|
||||
JOIN blobs ON blobs.blobId = notes.blobId OR blobs.blobId = attachments.blobId OR blobs.blobId = note_revisions.blobId`);
|
||||
LEFT JOIN revisions ON revisions.noteId = param_list.paramId
|
||||
JOIN blobs ON blobs.blobId = notes.blobId OR blobs.blobId = attachments.blobId OR blobs.blobId = revisions.blobId`);
|
||||
|
||||
const subTreeSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0);
|
||||
|
||||
|
@ -108,9 +108,9 @@ function forceNoteSync(req) {
|
||||
entityChangesService.moveEntityChangeToTop('attributes', attributeId);
|
||||
}
|
||||
|
||||
for (const noteRevisionId of sql.getColumn("SELECT noteRevisionId FROM note_revisions WHERE noteId = ?", [noteId])) {
|
||||
sql.execute(`UPDATE note_revisions SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]);
|
||||
entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId);
|
||||
for (const revisionId of sql.getColumn("SELECT revisionId FROM revisions WHERE noteId = ?", [noteId])) {
|
||||
sql.execute(`UPDATE revisions SET utcDateModified = ? WHERE revisionId = ?`, [now, revisionId]);
|
||||
entityChangesService.moveEntityChangeToTop('revisions', revisionId);
|
||||
}
|
||||
|
||||
for (const attachmentId of sql.getColumn("SELECT attachmentId FROM attachments WHERE noteId = ?", [noteId])) {
|
||||
|
@ -28,7 +28,7 @@ const branchesApiRoute = require('./api/branches');
|
||||
const attachmentsApiRoute = require('./api/attachments');
|
||||
const autocompleteApiRoute = require('./api/autocomplete');
|
||||
const cloningApiRoute = require('./api/cloning');
|
||||
const noteRevisionsApiRoute = require('./api/note_revisions');
|
||||
const revisionsApiRoute = require('./api/revisions.js');
|
||||
const recentChangesApiRoute = require('./api/recent_changes');
|
||||
const optionsApiRoute = require('./api/options');
|
||||
const passwordApiRoute = require('./api/password');
|
||||
@ -117,7 +117,7 @@ function register(app) {
|
||||
apiRoute(PUT, '/api/notes/:noteId/data', notesApiRoute.updateNoteData);
|
||||
apiRoute(DEL, '/api/notes/:noteId', notesApiRoute.deleteNote);
|
||||
apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote);
|
||||
apiRoute(PST, '/api/notes/:noteId/revision', notesApiRoute.forceSaveNoteRevision);
|
||||
apiRoute(PST, '/api/notes/:noteId/revision', notesApiRoute.forceSaveRevision);
|
||||
apiRoute(PST, '/api/notes/:parentNoteId/children', notesApiRoute.createNote);
|
||||
apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes);
|
||||
apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote);
|
||||
@ -171,13 +171,13 @@ function register(app) {
|
||||
route(PUT, '/api/attachments/:attachmentId/file', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware],
|
||||
filesRoute.updateAttachment, apiResultHandler);
|
||||
|
||||
apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions);
|
||||
apiRoute(DEL, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions);
|
||||
apiRoute(GET, '/api/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision);
|
||||
apiRoute(GET, '/api/revisions/:noteRevisionId/blob', noteRevisionsApiRoute.getNoteRevisionBlob);
|
||||
apiRoute(DEL, '/api/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision);
|
||||
apiRoute(PST, '/api/revisions/:noteRevisionId/restore', noteRevisionsApiRoute.restoreNoteRevision);
|
||||
route(GET, '/api/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision);
|
||||
apiRoute(GET, '/api/notes/:noteId/revisions', revisionsApiRoute.getRevisions);
|
||||
apiRoute(DEL, '/api/notes/:noteId/revisions', revisionsApiRoute.eraseAllRevisions);
|
||||
apiRoute(GET, '/api/revisions/:revisionId', revisionsApiRoute.getRevision);
|
||||
apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob);
|
||||
apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision);
|
||||
apiRoute(PST, '/api/revisions/:revisionId/restore', revisionsApiRoute.restoreRevision);
|
||||
route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision);
|
||||
|
||||
|
||||
route(GET, '/api/branches/:branchId/export/:type/:format/:version/:taskId', [auth.checkApiAuthOrElectron], exportRoute.exportBranch);
|
||||
@ -321,7 +321,7 @@ function register(app) {
|
||||
route(GET, '/api/fonts', [auth.checkApiAuthOrElectron], fontsRoute.getFontCss);
|
||||
apiRoute(GET, '/api/other/icon-usage', otherRoute.getIconUsage);
|
||||
apiRoute(GET, '/api/recent-changes/:ancestorNoteId', recentChangesApiRoute.getRecentChanges);
|
||||
apiRoute(GET, '/api/edited-notes/:date', noteRevisionsApiRoute.getEditedNotesOnDate);
|
||||
apiRoute(GET, '/api/edited-notes/:date', revisionsApiRoute.getEditedNotesOnDate);
|
||||
|
||||
apiRoute(PST, '/api/note-map/:noteId/tree', noteMapRoute.getTreeMap);
|
||||
apiRoute(PST, '/api/note-map/:noteId/link', noteMapRoute.getLinkMap);
|
||||
|
@ -15,7 +15,7 @@ function getFullAnonymizationScript() {
|
||||
UPDATE etapi_tokens SET tokenHash = 'API token hash value';
|
||||
UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share');
|
||||
UPDATE blobs SET content = 'text' WHERE content IS NOT NULL;
|
||||
UPDATE note_revisions SET title = 'title';
|
||||
UPDATE revisions SET title = 'title';
|
||||
|
||||
UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN(${builtinAttrNames});
|
||||
UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${builtinAttrNames});
|
||||
@ -36,7 +36,7 @@ function getLightAnonymizationScript() {
|
||||
return `UPDATE blobs SET content = 'text' WHERE content IS NOT NULL AND blobId NOT IN (
|
||||
SELECT blobId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend')
|
||||
UNION ALL
|
||||
SELECT blobId FROM note_revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend')
|
||||
SELECT blobId FROM revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend')
|
||||
);`;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ const build = require('./build');
|
||||
const packageJson = require('../../package');
|
||||
const {TRILIUM_DATA_DIR} = require('./data_dir');
|
||||
|
||||
const APP_DB_VERSION = 220;
|
||||
const APP_DB_VERSION = 221;
|
||||
const SYNC_VERSION = 30;
|
||||
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
||||
|
||||
|
@ -22,7 +22,7 @@ module.exports = [
|
||||
{ type: 'label', name: 'widget', isDangerous: true },
|
||||
{ type: 'label', name: 'noteInfoWidgetDisabled' },
|
||||
{ type: 'label', name: 'linkMapWidgetDisabled' },
|
||||
{ type: 'label', name: 'noteRevisionsWidgetDisabled' },
|
||||
{ type: 'label', name: 'revisionsWidgetDisabled' },
|
||||
{ type: 'label', name: 'whatLinksHereWidgetDisabled' },
|
||||
{ type: 'label', name: 'similarNotesWidgetDisabled' },
|
||||
{ type: 'label', name: 'workspace' },
|
||||
|
@ -1,5 +1,5 @@
|
||||
const log = require("./log");
|
||||
const noteRevisionService = require("./note_revisions");
|
||||
const revisionService = require("./revisions.js");
|
||||
const becca = require("../becca/becca");
|
||||
const cloningService = require("./cloning");
|
||||
const branchService = require("./branches");
|
||||
@ -17,8 +17,8 @@ const ACTION_HANDLERS = {
|
||||
|
||||
note.deleteNote(deleteId);
|
||||
},
|
||||
deleteNoteRevisions: (action, note) => {
|
||||
noteRevisionService.eraseNoteRevisions(note.getNoteRevisions().map(rev => rev.noteRevisionId));
|
||||
deleteRevisions: (action, note) => {
|
||||
revisionService.eraseRevisions(note.getRevisions().map(rev => rev.revisionId));
|
||||
},
|
||||
deleteLabel: (action, note) => {
|
||||
for (const label of note.getOwnedLabels(action.labelName)) {
|
||||
|
@ -9,7 +9,7 @@ const cls = require('./cls');
|
||||
const entityChangesService = require('./entity_changes');
|
||||
const optionsService = require('./options');
|
||||
const BBranch = require('../becca/entities/bbranch');
|
||||
const noteRevisionService = require('./note_revisions');
|
||||
const revisionService = require('./revisions.js');
|
||||
const becca = require("../becca/becca");
|
||||
const utils = require("../services/utils");
|
||||
const {sanitizeAttributeName} = require("./sanitize_attribute_name");
|
||||
@ -221,7 +221,7 @@ class ConsistencyChecks {
|
||||
WHERE attachments.parentId NOT IN (
|
||||
SELECT noteId FROM notes
|
||||
UNION ALL
|
||||
SELECT noteRevisionId FROM note_revisions
|
||||
SELECT revisionId FROM revisions
|
||||
)
|
||||
AND attachments.isDeleted = 0`,
|
||||
({attachmentId, parentId}) => {
|
||||
@ -461,19 +461,19 @@ class ConsistencyChecks {
|
||||
}
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT note_revisions.noteRevisionId
|
||||
FROM note_revisions
|
||||
SELECT revisions.revisionId
|
||||
FROM revisions
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
WHERE blobs.blobId IS NULL`,
|
||||
({noteRevisionId}) => {
|
||||
({revisionId}) => {
|
||||
if (this.autoFix) {
|
||||
noteRevisionService.eraseNoteRevisions([noteRevisionId]);
|
||||
revisionService.eraseRevisions([revisionId]);
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Note revision content '${noteRevisionId}' was set to erased since its content did not exist.`);
|
||||
logFix(`Note revision content '${revisionId}' was set to erased since its content did not exist.`);
|
||||
} else {
|
||||
logError(`Note revision content '${noteRevisionId}' does not exist`);
|
||||
logError(`Note revision content '${revisionId}' does not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -669,7 +669,7 @@ class ConsistencyChecks {
|
||||
|
||||
findEntityChangeIssues() {
|
||||
this.runEntityChangeChecks("notes", "noteId");
|
||||
this.runEntityChangeChecks("note_revisions", "noteRevisionId");
|
||||
this.runEntityChangeChecks("revisions", "revisionId");
|
||||
this.runEntityChangeChecks("attachments", "attachmentId");
|
||||
this.runEntityChangeChecks("blobs", "blobId");
|
||||
this.runEntityChangeChecks("branches", "branchId");
|
||||
@ -767,7 +767,7 @@ class ConsistencyChecks {
|
||||
return `${tableName}: ${count}`;
|
||||
}
|
||||
|
||||
const tables = [ "notes", "note_revisions", "attachments", "branches", "attributes", "etapi_tokens" ];
|
||||
const tables = [ "notes", "revisions", "attachments", "branches", "attributes", "etapi_tokens" ];
|
||||
|
||||
log.info(`Table counts: ${tables.map(tableName => getTableRowCount(tableName)).join(", ")}`);
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ function fillAllEntityChanges() {
|
||||
|
||||
fillEntityChanges("notes", "noteId");
|
||||
fillEntityChanges("branches", "branchId");
|
||||
fillEntityChanges("note_revisions", "noteRevisionId");
|
||||
fillEntityChanges("revisions", "revisionId");
|
||||
fillEntityChanges("attachments", "attachmentId");
|
||||
fillEntityChanges("blobs", "blobId");
|
||||
fillEntityChanges("attributes", "attributeId");
|
||||
|
@ -70,7 +70,7 @@ function updateImage(noteId, uploadBuffer, originalName) {
|
||||
|
||||
const note = becca.getNote(noteId);
|
||||
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
|
||||
note.setLabel('originalFileName', originalName);
|
||||
|
||||
|
@ -249,7 +249,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
||||
scope: "window"
|
||||
},
|
||||
{
|
||||
actionName: "showNoteRevisions",
|
||||
actionName: "showRevisions",
|
||||
defaultShortcuts: [],
|
||||
description: "Shows Note Revisions dialog",
|
||||
scope: "window"
|
||||
@ -502,7 +502,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
||||
scope: "text-detail"
|
||||
},
|
||||
{
|
||||
actionName: "forceSaveNoteRevision",
|
||||
actionName: "forceSaveRevision",
|
||||
defaultShortcuts: [],
|
||||
description: "Force creating / saving new note revision of the active note",
|
||||
scope: "window"
|
||||
|
@ -8,7 +8,7 @@ const cls = require('../services/cls');
|
||||
const protectedSessionService = require('../services/protected_session');
|
||||
const log = require('../services/log');
|
||||
const utils = require('../services/utils');
|
||||
const noteRevisionService = require('../services/note_revisions');
|
||||
const revisionService = require('./revisions.js');
|
||||
const request = require('./request');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
@ -315,7 +315,7 @@ function protectNote(note, protect) {
|
||||
note.setContent(content, { forceSave: true });
|
||||
}
|
||||
|
||||
noteRevisionService.protectNoteRevisions(note);
|
||||
revisionService.protectRevisions(note);
|
||||
|
||||
for (const attachment of note.getAttachments()) {
|
||||
if (protect !== attachment.isProtected) {
|
||||
@ -666,24 +666,24 @@ function saveLinks(note, content) {
|
||||
}
|
||||
|
||||
/** @param {BNote} note */
|
||||
function saveNoteRevisionIfNeeded(note) {
|
||||
function saveRevisionIfNeeded(note) {
|
||||
// files and images are versioned separately
|
||||
if (note.type === 'file' || note.type === 'image' || note.hasLabel('disableVersioning')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const noteRevisionSnapshotTimeInterval = parseInt(optionService.getOption('noteRevisionSnapshotTimeInterval'));
|
||||
const revisionSnapshotTimeInterval = parseInt(optionService.getOption('revisionSnapshotTimeInterval'));
|
||||
|
||||
const revisionCutoff = dateUtils.utcDateTimeStr(new Date(now.getTime() - noteRevisionSnapshotTimeInterval * 1000));
|
||||
const revisionCutoff = dateUtils.utcDateTimeStr(new Date(now.getTime() - revisionSnapshotTimeInterval * 1000));
|
||||
|
||||
const existingNoteRevisionId = sql.getValue(
|
||||
"SELECT noteRevisionId FROM note_revisions WHERE noteId = ? AND utcDateCreated >= ?", [note.noteId, revisionCutoff]);
|
||||
const existingRevisionId = sql.getValue(
|
||||
"SELECT revisionId FROM revisions WHERE noteId = ? AND utcDateCreated >= ?", [note.noteId, revisionCutoff]);
|
||||
|
||||
const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.utcDateCreated).getTime();
|
||||
|
||||
if (!existingNoteRevisionId && msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) {
|
||||
note.saveNoteRevision();
|
||||
if (!existingRevisionId && msSinceDateCreated >= revisionSnapshotTimeInterval * 1000) {
|
||||
note.saveRevision();
|
||||
}
|
||||
}
|
||||
|
||||
@ -694,7 +694,7 @@ function updateNoteData(noteId, content) {
|
||||
throw new Error(`Note '${noteId}' is not available for change!`);
|
||||
}
|
||||
|
||||
saveNoteRevisionIfNeeded(note);
|
||||
saveRevisionIfNeeded(note);
|
||||
|
||||
const { forceFrontendReload, content: newContent } = saveLinks(note, content);
|
||||
|
||||
@ -839,10 +839,10 @@ function eraseNotes(noteIdsToErase) {
|
||||
|
||||
eraseAttributes(attributeIdsToErase);
|
||||
|
||||
const noteRevisionIdsToErase = sql.getManyRows(`SELECT noteRevisionId FROM note_revisions WHERE noteId IN (???)`, noteIdsToErase)
|
||||
.map(row => row.noteRevisionId);
|
||||
const revisionIdsToErase = sql.getManyRows(`SELECT revisionId FROM revisions WHERE noteId IN (???)`, noteIdsToErase)
|
||||
.map(row => row.revisionId);
|
||||
|
||||
noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase);
|
||||
revisionService.eraseRevisions(revisionIdsToErase);
|
||||
|
||||
log.info(`Erased notes: ${JSON.stringify(noteIdsToErase)}`);
|
||||
}
|
||||
@ -899,10 +899,10 @@ function eraseUnusedBlobs() {
|
||||
FROM blobs
|
||||
LEFT JOIN notes ON notes.blobId = blobs.blobId
|
||||
LEFT JOIN attachments ON attachments.blobId = blobs.blobId
|
||||
LEFT JOIN note_revisions ON note_revisions.blobId = blobs.blobId
|
||||
LEFT JOIN revisions ON revisions.blobId = blobs.blobId
|
||||
WHERE notes.noteId IS NULL
|
||||
AND attachments.attachmentId IS NULL
|
||||
AND note_revisions.noteRevisionId IS NULL`);
|
||||
AND revisions.revisionId IS NULL`);
|
||||
|
||||
if (unusedBlobIds.length === 0) {
|
||||
return;
|
||||
@ -1136,7 +1136,7 @@ module.exports = {
|
||||
eraseDeletedNotesNow,
|
||||
eraseUnusedAttachmentsNow,
|
||||
eraseNotesWithDeleteId,
|
||||
saveNoteRevisionIfNeeded,
|
||||
saveRevisionIfNeeded,
|
||||
downloadImages,
|
||||
asyncPostProcessContent
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ function initNotSyncedOptions(initialized, opts = {}) {
|
||||
}
|
||||
|
||||
const defaultOptions = [
|
||||
{ name: 'noteRevisionSnapshotTimeInterval', value: '600', isSynced: true },
|
||||
{ name: 'revisionSnapshotTimeInterval', value: '600', isSynced: true },
|
||||
{ name: 'protectedSessionTimeout', value: '600', isSynced: true },
|
||||
{ name: 'zoomFactor', value: process.platform === "win32" ? '0.9' : '1.0', isSynced: false },
|
||||
{ name: 'overrideThemeFonts', value: 'false', isSynced: false },
|
||||
|
@ -7,12 +7,12 @@ const protectedSessionService = require("./protected_session");
|
||||
/**
|
||||
* @param {BNote} note
|
||||
*/
|
||||
function protectNoteRevisions(note) {
|
||||
function protectRevisions(note) {
|
||||
if (!protectedSessionService.isProtectedSessionAvailable()) {
|
||||
throw new Error(`Cannot (un)protect revisions of note '${note.noteId}' without active protected session`);
|
||||
}
|
||||
|
||||
for (const revision of note.getNoteRevisions()) {
|
||||
for (const revision of note.getRevisions()) {
|
||||
if (note.isProtected === revision.isProtected) {
|
||||
continue;
|
||||
}
|
||||
@ -25,25 +25,25 @@ function protectNoteRevisions(note) {
|
||||
// this will force de/encryption
|
||||
revision.setContent(content, {forceSave: true});
|
||||
} catch (e) {
|
||||
log.error(`Could not un/protect note revision '${revision.noteRevisionId}'`);
|
||||
log.error(`Could not un/protect note revision '${revision.revisionId}'`);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eraseNoteRevisions(noteRevisionIdsToErase) {
|
||||
if (noteRevisionIdsToErase.length === 0) {
|
||||
function eraseRevisions(revisionIdsToErase) {
|
||||
if (revisionIdsToErase.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Removing note revisions: ${JSON.stringify(noteRevisionIdsToErase)}`);
|
||||
log.info(`Removing note revisions: ${JSON.stringify(revisionIdsToErase)}`);
|
||||
|
||||
sql.executeMany(`DELETE FROM note_revisions WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase);
|
||||
sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_revisions' AND entityId IN (???)`, noteRevisionIdsToErase);
|
||||
sql.executeMany(`DELETE FROM revisions WHERE revisionId IN (???)`, revisionIdsToErase);
|
||||
sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'revisions' AND entityId IN (???)`, revisionIdsToErase);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
protectNoteRevisions,
|
||||
eraseNoteRevisions
|
||||
protectRevisions,
|
||||
eraseRevisions
|
||||
};
|
@ -116,16 +116,16 @@ function loadNeededInfoFromDatabase() {
|
||||
becca.notes[noteId].noteSize = length;
|
||||
}
|
||||
|
||||
const noteRevisionContentLengths = sql.getRows(`
|
||||
const revisionContentLengths = sql.getRows(`
|
||||
SELECT
|
||||
noteId,
|
||||
LENGTH(content) AS length
|
||||
FROM notes
|
||||
JOIN note_revisions USING(noteId)
|
||||
JOIN revisions USING(noteId)
|
||||
JOIN blobs USING(blobId)
|
||||
WHERE notes.isDeleted = 0`);
|
||||
|
||||
for (const {noteId, length} of noteRevisionContentLengths) {
|
||||
for (const {noteId, length} of revisionContentLengths) {
|
||||
if (!(noteId in becca.notes)) {
|
||||
log.error(`Note ${noteId} not found in becca.`);
|
||||
continue;
|
||||
|
@ -113,7 +113,7 @@ function eraseEntity(entityChange, instanceId) {
|
||||
"notes",
|
||||
"branches",
|
||||
"attributes",
|
||||
"note_revisions",
|
||||
"revisions",
|
||||
"attachments",
|
||||
"blobs",
|
||||
];
|
||||
|
@ -127,10 +127,10 @@ function fillInAdditionalProperties(entityChange) {
|
||||
entityChange.entity.title = protectedSessionService.decryptString(entityChange.entity.title);
|
||||
}
|
||||
}
|
||||
} else if (entityChange.entityName === 'note_revisions') {
|
||||
} else if (entityChange.entityName === 'revisions') {
|
||||
entityChange.noteId = sql.getValue(`SELECT noteId
|
||||
FROM note_revisions
|
||||
WHERE noteRevisionId = ?`, [entityChange.entityId]);
|
||||
FROM revisions
|
||||
WHERE revisionId = ?`, [entityChange.entityId]);
|
||||
} else if (entityChange.entityName === 'note_reordering') {
|
||||
entityChange.positions = {};
|
||||
|
||||
@ -165,7 +165,7 @@ const ORDERING = {
|
||||
"branches": 2,
|
||||
"blobs": 0,
|
||||
"note_reordering": 2,
|
||||
"note_revisions": 2,
|
||||
"revisions": 2,
|
||||
"attachments": 3,
|
||||
"notes": 1,
|
||||
"options": 0
|
||||
|
@ -82,7 +82,7 @@ async function start() {
|
||||
isInheritable: Math.random() > 0.1 // 10% are inheritable
|
||||
});
|
||||
|
||||
note.saveNoteRevision();
|
||||
note.saveRevision();
|
||||
|
||||
notes.push(note.noteId);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user