syncification

This commit is contained in:
zadam
2020-06-20 12:31:38 +02:00
parent 30062d687f
commit 88348c560c
97 changed files with 1673 additions and 1700 deletions

View File

@@ -2,10 +2,10 @@
const appInfo = require('../../services/app_info');
async function getAppInfo() {
function getAppInfo() {
return appInfo;
}
module.exports = {
getAppInfo
};
};

View File

@@ -6,19 +6,19 @@ const attributeService = require('../../services/attributes');
const repository = require('../../services/repository');
const Attribute = require('../../entities/attribute');
async function getEffectiveNoteAttributes(req) {
const note = await repository.getNote(req.params.noteId);
function getEffectiveNoteAttributes(req) {
const note = repository.getNote(req.params.noteId);
return await note.getAttributes();
return note.getAttributes();
}
async function updateNoteAttribute(req) {
function updateNoteAttribute(req) {
const noteId = req.params.noteId;
const body = req.body;
let attribute;
if (body.attributeId) {
attribute = await repository.getAttribute(body.attributeId);
attribute = repository.getAttribute(body.attributeId);
if (attribute.noteId !== noteId) {
return [400, `Attribute ${body.attributeId} is not owned by ${noteId}`];
@@ -30,11 +30,11 @@ async function updateNoteAttribute(req) {
if (body.type !== 'relation' || !!body.value.trim()) {
const newAttribute = attribute.createClone(body.type, body.name, body.value);
await newAttribute.save();
newAttribute.save();
}
attribute.isDeleted = true;
await attribute.save();
attribute.save();
return {
attributeId: attribute.attributeId
@@ -60,18 +60,18 @@ async function updateNoteAttribute(req) {
attribute.isDeleted = true;
}
await attribute.save();
attribute.save();
return {
attributeId: attribute.attributeId
};
}
async function deleteNoteAttribute(req) {
function deleteNoteAttribute(req) {
const noteId = req.params.noteId;
const attributeId = req.params.attributeId;
const attribute = await repository.getAttribute(attributeId);
const attribute = repository.getAttribute(attributeId);
if (attribute) {
if (attribute.noteId !== noteId) {
@@ -79,17 +79,17 @@ async function deleteNoteAttribute(req) {
}
attribute.isDeleted = true;
await attribute.save();
attribute.save();
}
}
async function updateNoteAttributes2(req) {
function updateNoteAttributes2(req) {
const noteId = req.params.noteId;
const incomingAttributes = req.body;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
let existingAttrs = await note.getAttributes();
let existingAttrs = note.getAttributes();
let position = 0;
@@ -107,14 +107,14 @@ async function updateNoteAttributes2(req) {
if (perfectMatchAttr.position !== position) {
perfectMatchAttr.position = position;
await perfectMatchAttr.save();
perfectMatchAttr.save();
}
continue; // nothing to update
}
if (incAttr.type === 'relation') {
const targetNote = await repository.getNote(incAttr.value);
const targetNote = repository.getNote(incAttr.value);
if (!targetNote || targetNote.isDeleted) {
log.error(`Target note of relation ${JSON.stringify(incAttr)} does not exist or is deleted`);
@@ -130,7 +130,7 @@ async function updateNoteAttributes2(req) {
if (matchedAttr) {
matchedAttr.value = incAttr.value;
matchedAttr.position = position;
await matchedAttr.save();
matchedAttr.save();
existingAttrs = existingAttrs.filter(attr => attr.attributeId !== matchedAttr.attributeId);
continue;
@@ -139,17 +139,17 @@ async function updateNoteAttributes2(req) {
// no existing attribute has been matched so we need to create a new one
// type, name and isInheritable are immutable so even if there is an attribute with matching type & name, we need to create a new one and delete the former one
await note.addAttribute(incAttr.type, incAttr.name, incAttr.value, incAttr.isInheritable, position);
note.addAttribute(incAttr.type, incAttr.name, incAttr.value, incAttr.isInheritable, position);
}
// all the remaining existing attributes are not defined anymore and should be deleted
for (const toDeleteAttr of existingAttrs) {
toDeleteAttr.isDeleted = true;
await toDeleteAttr.save();
toDeleteAttr.save();
}
}
async function updateNoteAttributes(req) {
function updateNoteAttributes(req) {
const noteId = req.params.noteId;
const attributes = req.body;
@@ -157,7 +157,7 @@ async function updateNoteAttributes(req) {
let attributeEntity;
if (attribute.attributeId) {
attributeEntity = await repository.getAttribute(attribute.attributeId);
attributeEntity = repository.getAttribute(attribute.attributeId);
if (attributeEntity.noteId !== noteId) {
return [400, `Attribute ${attributeEntity.noteId} is not owned by ${noteId}`];
@@ -170,11 +170,11 @@ async function updateNoteAttributes(req) {
if (attribute.type !== 'relation' || !!attribute.value.trim()) {
const newAttribute = attributeEntity.createClone(attribute.type, attribute.name, attribute.value, attribute.isInheritable);
await newAttribute.save();
newAttribute.save();
}
attributeEntity.isDeleted = true;
await attributeEntity.save();
attributeEntity.save();
continue;
}
@@ -203,34 +203,34 @@ async function updateNoteAttributes(req) {
attributeEntity.value = attribute.value;
}
await attributeEntity.save();
attributeEntity.save();
}
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
note.invalidateAttributeCache();
return await note.getAttributes();
return note.getAttributes();
}
async function getAttributeNames(req) {
function getAttributeNames(req) {
const type = req.query.type;
const query = req.query.query;
return attributeService.getAttributeNames(type, query);
}
async function getValuesForAttribute(req) {
function getValuesForAttribute(req) {
const attributeName = req.params.attributeName;
return await sql.getColumn("SELECT DISTINCT value FROM attributes WHERE isDeleted = 0 AND name = ? AND type = 'label' AND value != '' ORDER BY value", [attributeName]);
return sql.getColumn("SELECT DISTINCT value FROM attributes WHERE isDeleted = 0 AND name = ? AND type = 'label' AND value != '' ORDER BY value", [attributeName]);
}
async function createRelation(req) {
function createRelation(req) {
const sourceNoteId = req.params.noteId;
const targetNoteId = req.params.targetNoteId;
const name = req.params.name;
let attribute = await repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = 'relation' AND name = ? AND value = ?`, [sourceNoteId, name, targetNoteId]);
let attribute = repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = 'relation' AND name = ? AND value = ?`, [sourceNoteId, name, targetNoteId]);
if (!attribute) {
attribute = new Attribute();
@@ -239,22 +239,22 @@ async function createRelation(req) {
attribute.type = 'relation';
attribute.value = targetNoteId;
await attribute.save();
attribute.save();
}
return attribute;
}
async function deleteRelation(req) {
function deleteRelation(req) {
const sourceNoteId = req.params.noteId;
const targetNoteId = req.params.targetNoteId;
const name = req.params.name;
let attribute = await repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = 'relation' AND name = ? AND value = ?`, [sourceNoteId, name, targetNoteId]);
let attribute = repository.getEntity(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ? AND type = 'relation' AND name = ? AND value = ?`, [sourceNoteId, name, targetNoteId]);
if (attribute) {
attribute.isDeleted = true;
await attribute.save();
attribute.save();
}
}

View File

@@ -7,7 +7,7 @@ const log = require('../../services/log');
const utils = require('../../services/utils');
const optionService = require('../../services/options');
async function getAutocomplete(req) {
function getAutocomplete(req) {
const query = req.query.query.trim();
const activeNoteId = req.query.activeNoteId || 'none';
@@ -16,10 +16,10 @@ async function getAutocomplete(req) {
const timestampStarted = Date.now();
if (query.length === 0) {
results = await getRecentNotes(activeNoteId);
results = getRecentNotes(activeNoteId);
}
else {
results = await searchService.searchNotesForAutocomplete(query);
results = searchService.searchNotesForAutocomplete(query);
}
const msTaken = Date.now() - timestampStarted;
@@ -31,15 +31,15 @@ async function getAutocomplete(req) {
return results;
}
async function getRecentNotes(activeNoteId) {
function getRecentNotes(activeNoteId) {
let extraCondition = '';
const hoistedNoteId = await optionService.getOption('hoistedNoteId');
const hoistedNoteId = optionService.getOption('hoistedNoteId');
if (hoistedNoteId !== 'root') {
extraCondition = `AND recent_notes.notePath LIKE '%${utils.sanitizeSql(hoistedNoteId)}%'`;
}
const recentNotes = await repository.getEntities(`
const recentNotes = repository.getEntities(`
SELECT
recent_notes.*
FROM

View File

@@ -4,7 +4,7 @@ const fs = require('fs');
const dateUtils = require('../../services/date_utils');
const {LOG_DIR} = require('../../services/data_dir.js');
async function getBackendLog() {
function getBackendLog() {
const file = `${LOG_DIR}/trilium-${dateUtils.localNowDate()}.log`;
return fs.readFileSync(file, 'utf8');
@@ -12,4 +12,4 @@ async function getBackendLog() {
module.exports = {
getBackendLog
};
};

View File

@@ -13,11 +13,11 @@ const TaskContext = require('../../services/task_context');
* for not deleted branches. There may be multiple deleted note-parent note relationships.
*/
async function moveBranchToParent(req) {
function moveBranchToParent(req) {
const {branchId, parentBranchId} = req.params;
const parentBranch = await repository.getBranch(parentBranchId);
const branchToMove = await repository.getBranch(branchId);
const parentBranch = repository.getBranch(parentBranchId);
const branchToMove = repository.getBranch(branchId);
if (!parentBranch || !branchToMove) {
return [400, `One or both branches ${branchId}, ${parentBranchId} have not been found`];
@@ -27,35 +27,35 @@ async function moveBranchToParent(req) {
return { success: true }; // no-op
}
const validationResult = await treeService.validateParentChild(parentBranch.noteId, branchToMove.noteId, branchId);
const validationResult = treeService.validateParentChild(parentBranch.noteId, branchToMove.noteId, branchId);
if (!validationResult.success) {
return [200, validationResult];
}
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [parentBranch.noteId]);
const maxNotePos = sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [parentBranch.noteId]);
const newNotePos = maxNotePos === null ? 0 : maxNotePos + 10;
// expanding so that the new placement of the branch is immediately visible
parentBranch.isExpanded = true;
await parentBranch.save();
parentBranch.save();
const newBranch = branchToMove.createClone(parentBranch.noteId, newNotePos);
await newBranch.save();
newBranch.save();
branchToMove.isDeleted = true;
await branchToMove.save();
branchToMove.save();
return { success: true };
}
async function moveBranchBeforeNote(req) {
function moveBranchBeforeNote(req) {
const {branchId, beforeBranchId} = req.params;
const branchToMove = await repository.getBranch(branchId);
const beforeNote = await repository.getBranch(beforeBranchId);
const branchToMove = repository.getBranch(branchId);
const beforeNote = repository.getBranch(beforeBranchId);
const validationResult = await treeService.validateParentChild(beforeNote.parentNoteId, branchToMove.noteId, branchId);
const validationResult = treeService.validateParentChild(beforeNote.parentNoteId, branchToMove.noteId, branchId);
if (!validationResult.success) {
return [200, validationResult];
@@ -63,33 +63,33 @@ async function moveBranchBeforeNote(req) {
// we don't change utcDateModified so other changes are prioritized in case of conflict
// also we would have to sync all those modified branches otherwise hash checks would fail
await sql.execute("UPDATE branches SET notePosition = notePosition + 10 WHERE parentNoteId = ? AND notePosition >= ? AND isDeleted = 0",
sql.execute("UPDATE branches SET notePosition = notePosition + 10 WHERE parentNoteId = ? AND notePosition >= ? AND isDeleted = 0",
[beforeNote.parentNoteId, beforeNote.notePosition]);
await syncTableService.addNoteReorderingSync(beforeNote.parentNoteId);
syncTableService.addNoteReorderingSync(beforeNote.parentNoteId);
if (branchToMove.parentNoteId === beforeNote.parentNoteId) {
branchToMove.notePosition = beforeNote.notePosition;
await branchToMove.save();
branchToMove.save();
}
else {
const newBranch = branchToMove.createClone(beforeNote.parentNoteId, beforeNote.notePosition);
await newBranch.save();
newBranch.save();
branchToMove.isDeleted = true;
await branchToMove.save();
branchToMove.save();
}
return { success: true };
}
async function moveBranchAfterNote(req) {
function moveBranchAfterNote(req) {
const {branchId, afterBranchId} = req.params;
const branchToMove = await repository.getBranch(branchId);
const afterNote = await repository.getBranch(afterBranchId);
const branchToMove = repository.getBranch(branchId);
const afterNote = repository.getBranch(afterBranchId);
const validationResult = await treeService.validateParentChild(afterNote.parentNoteId, branchToMove.noteId, branchId);
const validationResult = treeService.validateParentChild(afterNote.parentNoteId, branchToMove.noteId, branchId);
if (!validationResult.success) {
return [200, validationResult];
@@ -97,42 +97,42 @@ async function moveBranchAfterNote(req) {
// we don't change utcDateModified so other changes are prioritized in case of conflict
// also we would have to sync all those modified branches otherwise hash checks would fail
await sql.execute("UPDATE branches SET notePosition = notePosition + 10 WHERE parentNoteId = ? AND notePosition > ? AND isDeleted = 0",
sql.execute("UPDATE branches SET notePosition = notePosition + 10 WHERE parentNoteId = ? AND notePosition > ? AND isDeleted = 0",
[afterNote.parentNoteId, afterNote.notePosition]);
await syncTableService.addNoteReorderingSync(afterNote.parentNoteId);
syncTableService.addNoteReorderingSync(afterNote.parentNoteId);
const movedNotePosition = afterNote.notePosition + 10;
if (branchToMove.parentNoteId === afterNote.parentNoteId) {
branchToMove.notePosition = movedNotePosition;
await branchToMove.save();
branchToMove.save();
}
else {
const newBranch = branchToMove.createClone(afterNote.parentNoteId, movedNotePosition);
await newBranch.save();
newBranch.save();
branchToMove.isDeleted = true;
await branchToMove.save();
branchToMove.save();
}
return { success: true };
}
async function setExpanded(req) {
function setExpanded(req) {
const {branchId, expanded} = req.params;
if (branchId !== 'root') {
await sql.execute("UPDATE branches SET isExpanded = ? WHERE branchId = ?", [expanded, branchId]);
sql.execute("UPDATE branches SET isExpanded = ? WHERE branchId = ?", [expanded, branchId]);
// we don't sync expanded label
// also this does not trigger updates to the frontend, this would trigger too many reloads
}
}
async function setExpandedForSubtree(req) {
function setExpandedForSubtree(req) {
const {branchId, expanded} = req.params;
let branchIds = await sql.getColumn(`
let branchIds = sql.getColumn(`
WITH RECURSIVE
tree(branchId, noteId) AS (
SELECT branchId, noteId FROM branches WHERE branchId = ?
@@ -146,20 +146,20 @@ async function setExpandedForSubtree(req) {
// root is always expanded
branchIds = branchIds.filter(branchId => branchId !== 'root');
await sql.executeMany(`UPDATE branches SET isExpanded = ${expanded} WHERE branchId IN (???)`, branchIds);
sql.executeMany(`UPDATE branches SET isExpanded = ${expanded} WHERE branchId IN (???)`, branchIds);
return {
branchIds
};
}
async function deleteBranch(req) {
function deleteBranch(req) {
const last = req.query.last === 'true';
const branch = await repository.getBranch(req.params.branchId);
const branch = repository.getBranch(req.params.branchId);
const taskContext = TaskContext.getInstance(req.query.taskId, 'delete-notes');
const deleteId = utils.randomString(10);
const noteDeleted = await noteService.deleteBranch(branch, deleteId, taskContext);
const noteDeleted = noteService.deleteBranch(branch, deleteId, taskContext);
if (last) {
taskContext.taskSucceeded();
@@ -170,13 +170,13 @@ async function deleteBranch(req) {
};
}
async function setPrefix(req) {
function setPrefix(req) {
const branchId = req.params.branchId;
const prefix = utils.isEmptyOrWhitespace(req.body.prefix) ? null : req.body.prefix;
const branch = await repository.getBranch(branchId);
const branch = repository.getBranch(branchId);
branch.prefix = prefix;
await branch.save();
branch.save();
}
module.exports = {

View File

@@ -12,11 +12,11 @@ const utils = require('../../services/utils');
const path = require('path');
const Attribute = require('../../entities/attribute');
async function findClippingNote(todayNote, pageUrl) {
const notes = await todayNote.getDescendantNotesWithLabel('pageUrl', pageUrl);
function findClippingNote(todayNote, pageUrl) {
const notes = todayNote.getDescendantNotesWithLabel('pageUrl', pageUrl);
for (const note of notes) {
if (await note.getOwnedLabelValue('clipType') === 'clippings') {
if (note.getOwnedLabelValue('clipType') === 'clippings') {
return note;
}
}
@@ -24,76 +24,76 @@ async function findClippingNote(todayNote, pageUrl) {
return null;
}
async function getClipperInboxNote() {
let clipperInbox = await attributeService.getNoteWithLabel('clipperInbox');
function getClipperInboxNote() {
let clipperInbox = attributeService.getNoteWithLabel('clipperInbox');
if (!clipperInbox) {
clipperInbox = await dateNoteService.getDateNote(dateUtils.localNowDate());
clipperInbox = dateNoteService.getDateNote(dateUtils.localNowDate());
}
return clipperInbox;
}
async function addClipping(req) {
function addClipping(req) {
const {title, content, pageUrl, images} = req.body;
const clipperInbox = await getClipperInboxNote();
const clipperInbox = getClipperInboxNote();
let clippingNote = await findClippingNote(clipperInbox, pageUrl);
let clippingNote = findClippingNote(clipperInbox, pageUrl);
if (!clippingNote) {
clippingNote = (await noteService.createNewNote({
clippingNote = (noteService.createNewNote({
parentNoteId: clipperInbox.noteId,
title: title,
content: '',
type: 'text'
})).note;
await clippingNote.setLabel('clipType', 'clippings');
await clippingNote.setLabel('pageUrl', pageUrl);
clippingNote.setLabel('clipType', 'clippings');
clippingNote.setLabel('pageUrl', pageUrl);
}
const rewrittenContent = await addImagesToNote(images, clippingNote, content);
const rewrittenContent = addImagesToNote(images, clippingNote, content);
const existingContent = await clippingNote.getContent();
const existingContent = clippingNote.getContent();
await clippingNote.setContent(existingContent + (existingContent.trim() ? "<br/>" : "") + rewrittenContent);
clippingNote.setContent(existingContent + (existingContent.trim() ? "<br/>" : "") + rewrittenContent);
return {
noteId: clippingNote.noteId
};
}
async function createNote(req) {
function createNote(req) {
const {title, content, pageUrl, images, clipType} = req.body;
log.info(`Creating clipped note from ${pageUrl}`);
const clipperInbox = await getClipperInboxNote();
const clipperInbox = getClipperInboxNote();
const {note} = await noteService.createNewNote({
const {note} = noteService.createNewNote({
parentNoteId: clipperInbox.noteId,
title,
content,
type: 'text'
});
await note.setLabel('clipType', clipType);
note.setLabel('clipType', clipType);
if (pageUrl) {
await note.setLabel('pageUrl', pageUrl);
note.setLabel('pageUrl', pageUrl);
}
const rewrittenContent = await addImagesToNote(images, note, content);
const rewrittenContent = addImagesToNote(images, note, content);
await note.setContent(rewrittenContent);
note.setContent(rewrittenContent);
return {
noteId: note.noteId
};
}
async function addImagesToNote(images, note, content) {
function addImagesToNote(images, note, content) {
let rewrittenContent = content;
if (images) {
@@ -107,15 +107,15 @@ async function addImagesToNote(images, note, content) {
const buffer = Buffer.from(dataUrl.split(",")[1], 'base64');
const {note: imageNote, url} = await imageService.saveImage(note.noteId, buffer, filename, true);
const {note: imageNote, url} = imageService.saveImage(note.noteId, buffer, filename, true);
await new Attribute({
new Attribute({
noteId: imageNote.noteId,
type: 'label',
name: 'hideInAutocomplete'
}).save();
await new Attribute({
new Attribute({
noteId: note.noteId,
type: 'relation',
name: 'imageLink',
@@ -131,7 +131,7 @@ async function addImagesToNote(images, note, content) {
return rewrittenContent;
}
async function openNote(req) {
function openNote(req) {
if (utils.isElectron()) {
ws.sendMessageToAllClients({
type: 'open-note',
@@ -149,7 +149,7 @@ async function openNote(req) {
}
}
async function handshake() {
function handshake() {
return {
appName: "trilium",
protocolVersion: appInfo.clipperProtocolVersion

View File

@@ -2,17 +2,17 @@
const cloningService = require('../../services/cloning');
async function cloneNoteToParent(req) {
function cloneNoteToParent(req) {
const {noteId, parentBranchId} = req.params;
const {prefix} = req.body;
return await cloningService.cloneNoteToParent(noteId, parentBranchId, prefix);
return cloningService.cloneNoteToParent(noteId, parentBranchId, prefix);
}
async function cloneNoteAfter(req) {
function cloneNoteAfter(req) {
const {noteId, afterBranchId} = req.params;
return await cloningService.cloneNoteAfter(noteId, afterBranchId);
return cloningService.cloneNoteAfter(noteId, afterBranchId);
}
module.exports = {

View File

@@ -5,24 +5,24 @@ const log = require('../../services/log');
const backupService = require('../../services/backup');
const consistencyChecksService = require('../../services/consistency_checks');
async function anonymize() {
return await backupService.anonymize();
function anonymize() {
return backupService.anonymize();
}
async function backupDatabase() {
function backupDatabase() {
return {
backupFile: await backupService.backupNow("now")
backupFile: backupService.backupNow("now")
};
}
async function vacuumDatabase() {
await sql.execute("VACUUM");
function vacuumDatabase() {
sql.execute("VACUUM");
log.info("Database has been vacuumed.");
}
async function findAndFixConsistencyIssues() {
await consistencyChecksService.runOnDemandChecks(true);
function findAndFixConsistencyIssues() {
consistencyChecksService.runOnDemandChecks(true);
}
module.exports = {

View File

@@ -5,19 +5,19 @@ const sql = require('../../services/sql');
const dateUtils = require('../../services/date_utils');
const noteService = require('../../services/notes');
async function getDateNote(req) {
return await dateNoteService.getDateNote(req.params.date);
function getDateNote(req) {
return dateNoteService.getDateNote(req.params.date);
}
async function getMonthNote(req) {
return await dateNoteService.getMonthNote(req.params.month);
function getMonthNote(req) {
return dateNoteService.getMonthNote(req.params.month);
}
async function getYearNote(req) {
return await dateNoteService.getYearNote(req.params.year);
function getYearNote(req) {
return dateNoteService.getYearNote(req.params.year);
}
async function getDateNotesForMonth(req) {
function getDateNotesForMonth(req) {
const month = req.params.month;
return sql.getMap(`
@@ -33,12 +33,12 @@ async function getDateNotesForMonth(req) {
AND attr.value LIKE '${month}%'`);
}
async function createSqlConsole() {
function createSqlConsole() {
const today = dateUtils.localNowDate();
const todayNote = await dateNoteService.getDateNote(today);
const todayNote = dateNoteService.getDateNote(today);
const {note} = await noteService.createNewNote({
const {note} = noteService.createNewNote({
parentNoteId: todayNote.noteId,
title: 'SQL Console',
content: "SELECT title, isDeleted, isProtected FROM notes WHERE noteId = ''\n\n\n\n",
@@ -46,7 +46,7 @@ async function createSqlConsole() {
mime: 'text/x-sqlite;schema=trilium'
});
await note.setLabel("sqlConsole", today);
note.setLabel("sqlConsole", today);
return note;
}
@@ -57,4 +57,4 @@ module.exports = {
getYearNote,
getDateNotesForMonth,
createSqlConsole
};
};

View File

@@ -7,9 +7,9 @@ const repository = require("../../services/repository");
const TaskContext = require("../../services/task_context");
const log = require("../../services/log");
async function exportBranch(req, res) {
function exportBranch(req, res) {
const {branchId, type, format, version, taskId} = req.params;
const branch = await repository.getBranch(branchId);
const branch = repository.getBranch(branchId);
if (!branch) {
const message = `Cannot export branch ${branchId} since it does not exist.`;
@@ -25,15 +25,15 @@ async function exportBranch(req, res) {
if (type === 'subtree' && (format === 'html' || format === 'markdown')) {
const start = Date.now();
await zipExportService.exportToZip(taskContext, branch, format, res);
zipExportService.exportToZip(taskContext, branch, format, res);
console.log("Export took", Date.now() - start, "ms");
}
else if (type === 'single') {
await singleExportService.exportSingleNote(taskContext, branch, format, res);
singleExportService.exportSingleNote(taskContext, branch, format, res);
}
else if (format === 'opml') {
await opmlExportService.exportToOpml(taskContext, branch, version, res);
opmlExportService.exportToOpml(taskContext, branch, version, res);
}
else {
return [404, "Unrecognized export format " + format];

View File

@@ -5,33 +5,33 @@ const repository = require('../../services/repository');
const utils = require('../../services/utils');
const noteRevisionService = require('../../services/note_revisions');
async function updateFile(req) {
function updateFile(req) {
const {noteId} = req.params;
const file = req.file;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
}
await noteRevisionService.createNoteRevision(note);
noteRevisionService.createNoteRevision(note);
note.mime = file.mimetype.toLowerCase();
await note.setContent(file.buffer);
note.setContent(file.buffer);
await note.setLabel('originalFileName', file.originalname);
note.setLabel('originalFileName', file.originalname);
await noteRevisionService.protectNoteRevisions(note);
noteRevisionService.protectNoteRevisions(note);
return {
uploaded: true
};
}
async function downloadNoteFile(noteId, res, contentDisposition = true) {
const note = await repository.getNote(noteId);
function downloadNoteFile(noteId, res, contentDisposition = true) {
const note = repository.getNote(noteId);
if (!note) {
return res.status(404).send(`Note ${noteId} doesn't exist.`);
@@ -51,19 +51,19 @@ async function downloadNoteFile(noteId, res, contentDisposition = true) {
res.setHeader('Content-Type', note.mime);
res.send(await note.getContent());
res.send(note.getContent());
}
async function downloadFile(req, res) {
function downloadFile(req, res) {
const noteId = req.params.noteId;
return await downloadNoteFile(noteId, res);
return downloadNoteFile(noteId, res);
}
async function openFile(req, res) {
function openFile(req, res) {
const noteId = req.params.noteId;
return await downloadNoteFile(noteId, res, false);
return downloadNoteFile(noteId, res, false);
}
module.exports = {

View File

@@ -5,8 +5,8 @@ const repository = require('../../services/repository');
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
const fs = require('fs');
async function returnImage(req, res) {
const image = await repository.getNote(req.params.noteId);
function returnImage(req, res) {
const image = repository.getNote(req.params.noteId);
if (!image) {
return res.sendStatus(404);
@@ -21,14 +21,14 @@ async function returnImage(req, res) {
res.set('Content-Type', image.mime);
res.send(await image.getContent());
res.send(image.getContent());
}
async function uploadImage(req) {
function uploadImage(req) {
const {noteId} = req.query;
const {file} = req;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
@@ -38,7 +38,7 @@ async function uploadImage(req) {
return [400, "Unknown image type: " + file.mimetype];
}
const {url} = await imageService.saveImage(noteId, file.buffer, file.originalname, true);
const {url} = imageService.saveImage(noteId, file.buffer, file.originalname, true);
return {
uploaded: true,
@@ -46,11 +46,11 @@ async function uploadImage(req) {
};
}
async function updateImage(req) {
function updateImage(req) {
const {noteId} = req.params;
const {file} = req;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} doesn't exist.`];
@@ -63,7 +63,7 @@ async function updateImage(req) {
};
}
await imageService.updateImage(noteId, file.buffer, file.originalname);
imageService.updateImage(noteId, file.buffer, file.originalname);
return { uploaded: true };
}
@@ -72,4 +72,4 @@ module.exports = {
returnImage,
uploadImage,
updateImage
};
};

View File

@@ -12,7 +12,7 @@ const noteCacheService = require('../../services/note_cache/note_cache.js');
const log = require('../../services/log');
const TaskContext = require('../../services/task_context.js');
async function importToBranch(req) {
function importToBranch(req) {
const {parentNoteId} = req.params;
const {taskId, last} = req.body;
@@ -31,7 +31,7 @@ async function importToBranch(req) {
return [400, "No file has been uploaded"];
}
const parentNote = await repository.getNote(parentNoteId);
const parentNote = repository.getNote(parentNoteId);
if (!parentNote) {
return [404, `Note ${parentNoteId} doesn't exist.`];
@@ -49,19 +49,19 @@ async function importToBranch(req) {
try {
if (extension === '.tar' && options.explodeArchives) {
note = await tarImportService.importTar(taskContext, file.buffer, parentNote);
note = tarImportService.importTar(taskContext, file.buffer, parentNote);
} else if (extension === '.zip' && options.explodeArchives) {
const start = Date.now();
note = await zipImportService.importZip(taskContext, file.buffer, parentNote);
note = zipImportService.importZip(taskContext, file.buffer, parentNote);
console.log("Import took", Date.now() - start, "ms");
} else if (extension === '.opml' && options.explodeArchives) {
note = await opmlImportService.importOpml(taskContext, file.buffer, parentNote);
note = opmlImportService.importOpml(taskContext, file.buffer, parentNote);
} else if (extension === '.enex' && options.explodeArchives) {
note = await enexImportService.importEnex(taskContext, file, parentNote);
note = enexImportService.importEnex(taskContext, file, parentNote);
} else {
note = await singleImportService.importSingleFile(taskContext, file, parentNote);
note = singleImportService.importSingleFile(taskContext, file, parentNote);
}
}
catch (e) {

View File

@@ -3,12 +3,12 @@
const keyboardActions = require('../../services/keyboard_actions');
const sql = require('../../services/sql');
async function getKeyboardActions() {
return await keyboardActions.getKeyboardActions();
function getKeyboardActions() {
return keyboardActions.getKeyboardActions();
}
async function getShortcutsForNotes() {
return await sql.getMap(`
function getShortcutsForNotes() {
return sql.getMap(`
SELECT value, noteId
FROM attributes
WHERE isDeleted = 0
@@ -19,4 +19,4 @@ async function getShortcutsForNotes() {
module.exports = {
getKeyboardActions,
getShortcutsForNotes
};
};

View File

@@ -2,8 +2,8 @@
const sql = require('../../services/sql');
async function getRelations(noteIds) {
return (await sql.getManyRows(`
function getRelations(noteIds) {
return (sql.getManyRows(`
SELECT noteId, name, value AS targetNoteId
FROM attributes
WHERE (noteId IN (???) OR value IN (???))
@@ -14,7 +14,7 @@ async function getRelations(noteIds) {
`, Array.from(noteIds)));
}
async function getLinkMap(req) {
function getLinkMap(req) {
const {noteId} = req.params;
const {maxNotes, maxDepth} = req.body;
@@ -24,7 +24,7 @@ async function getLinkMap(req) {
let depth = 0;
while (noteIds.size < maxNotes) {
relations = await getRelations(noteIds);
relations = getRelations(noteIds);
if (depth === maxDepth) {
break;
@@ -58,4 +58,4 @@ async function getLinkMap(req) {
module.exports = {
getLinkMap
};
};

View File

@@ -14,8 +14,8 @@ const sql = require('../../services/sql');
const optionService = require('../../services/options');
const ApiToken = require('../../entities/api_token');
async function loginSync(req) {
if (!await sqlInit.schemaExists()) {
function loginSync(req) {
if (!sqlInit.schemaExists()) {
return [500, { message: "DB schema does not exist, can't sync." }];
}
@@ -36,7 +36,7 @@ async function loginSync(req) {
return [400, { message: `Non-matching sync versions, local is version ${appInfo.syncVersion}, remote is ${syncVersion}. It is recommended to run same version of Trilium on both sides of sync.` }];
}
const documentSecret = await options.getOption('documentSecret');
const documentSecret = options.getOption('documentSecret');
const expectedHash = utils.hmac(documentSecret, timestampStr);
const givenHash = req.body.hash;
@@ -49,28 +49,28 @@ async function loginSync(req) {
return {
sourceId: sourceIdService.getCurrentSourceId(),
maxSyncId: await sql.getValue("SELECT MAX(id) FROM sync WHERE isSynced = 1")
maxSyncId: sql.getValue("SELECT MAX(id) FROM sync WHERE isSynced = 1")
};
}
async function loginToProtectedSession(req) {
function loginToProtectedSession(req) {
const password = req.body.password;
if (!await passwordEncryptionService.verifyPassword(password)) {
if (!passwordEncryptionService.verifyPassword(password)) {
return {
success: false,
message: "Given current password doesn't match hash"
};
}
const decryptedDataKey = await passwordEncryptionService.getDataKey(password);
const decryptedDataKey = passwordEncryptionService.getDataKey(password);
const protectedSessionId = protectedSessionService.setDataKey(decryptedDataKey);
// this is set here so that event handlers have access to the protected session
cls.set('protectedSessionId', protectedSessionId);
await eventService.emit(eventService.ENTER_PROTECTED_SESSION);
eventService.emit(eventService.ENTER_PROTECTED_SESSION);
return {
success: true,
@@ -78,18 +78,18 @@ async function loginToProtectedSession(req) {
};
}
async function token(req) {
function token(req) {
const username = req.body.username;
const password = req.body.password;
const isUsernameValid = username === await optionService.getOption('username');
const isPasswordValid = await passwordEncryptionService.verifyPassword(password);
const isUsernameValid = username === optionService.getOption('username');
const isPasswordValid = passwordEncryptionService.verifyPassword(password);
if (!isUsernameValid || !isPasswordValid) {
return [401, "Incorrect username/password"];
}
const apiToken = await new ApiToken({
const apiToken = new ApiToken({
token: utils.randomSecureToken()
}).save();

View File

@@ -7,23 +7,23 @@ const noteRevisionService = require('../../services/note_revisions');
const utils = require('../../services/utils');
const path = require('path');
async function getNoteRevisions(req) {
return await repository.getEntities(`
function getNoteRevisions(req) {
return repository.getEntities(`
SELECT * FROM note_revisions
WHERE noteId = ? AND isErased = 0
ORDER BY utcDateCreated DESC`, [req.params.noteId]);
}
async function getNoteRevision(req) {
const noteRevision = await repository.getNoteRevision(req.params.noteRevisionId);
function getNoteRevision(req) {
const noteRevision = repository.getNoteRevision(req.params.noteRevisionId);
if (noteRevision.type === 'file') {
if (noteRevision.isStringNote()) {
noteRevision.content = (await noteRevision.getContent()).substr(0, 10000);
noteRevision.content = (noteRevision.getContent()).substr(0, 10000);
}
}
else {
noteRevision.content = await noteRevision.getContent();
noteRevision.content = noteRevision.getContent();
if (noteRevision.content && noteRevision.type === 'image') {
noteRevision.content = noteRevision.content.toString('base64');
@@ -57,8 +57,8 @@ function getRevisionFilename(noteRevision) {
return filename;
}
async function downloadNoteRevision(req, res) {
const noteRevision = await repository.getNoteRevision(req.params.noteRevisionId);
function downloadNoteRevision(req, res) {
const noteRevision = repository.getNoteRevision(req.params.noteRevisionId);
if (noteRevision.noteId !== req.params.noteId) {
return res.status(400).send(`Note revision ${req.params.noteRevisionId} does not belong to note ${req.params.noteId}`);
@@ -73,55 +73,55 @@ async function downloadNoteRevision(req, res) {
res.setHeader('Content-Disposition', utils.getContentDisposition(filename));
res.setHeader('Content-Type', noteRevision.mime);
res.send(await noteRevision.getContent());
res.send(noteRevision.getContent());
}
/**
* @param {NoteRevision} noteRevision
*/
async function eraseOneNoteRevision(noteRevision) {
function eraseOneNoteRevision(noteRevision) {
noteRevision.isErased = true;
noteRevision.title = null;
await noteRevision.setContent(null);
await noteRevision.save();
noteRevision.setContent(null);
noteRevision.save();
}
async function eraseAllNoteRevisions(req) {
const noteRevisionsToErase = await repository.getEntities(
function eraseAllNoteRevisions(req) {
const noteRevisionsToErase = repository.getEntities(
'SELECT * FROM note_revisions WHERE isErased = 0 AND noteId = ?',
[req.params.noteId]);
for (const noteRevision of noteRevisionsToErase) {
await eraseOneNoteRevision(noteRevision);
eraseOneNoteRevision(noteRevision);
}
}
async function eraseNoteRevision(req) {
const noteRevision = await repository.getNoteRevision(req.params.noteRevisionId);
function eraseNoteRevision(req) {
const noteRevision = repository.getNoteRevision(req.params.noteRevisionId);
if (noteRevision && !noteRevision.isErased) {
await eraseOneNoteRevision(noteRevision);
eraseOneNoteRevision(noteRevision);
}
}
async function restoreNoteRevision(req) {
const noteRevision = await repository.getNoteRevision(req.params.noteRevisionId);
function restoreNoteRevision(req) {
const noteRevision = repository.getNoteRevision(req.params.noteRevisionId);
if (noteRevision && !noteRevision.isErased) {
const note = await noteRevision.getNote();
const note = noteRevision.getNote();
await noteRevisionService.createNoteRevision(note);
noteRevisionService.createNoteRevision(note);
note.title = noteRevision.title;
await note.setContent(await noteRevision.getContent());
await note.save();
note.setContent(noteRevision.getContent());
note.save();
}
}
async function getEditedNotesOnDate(req) {
function getEditedNotesOnDate(req) {
const date = utils.sanitizeSql(req.params.date);
const notes = await repository.getEntities(`
const notes = repository.getEntities(`
SELECT notes.*
FROM notes
WHERE noteId IN (

View File

@@ -6,16 +6,16 @@ const repository = require('../../services/repository');
const utils = require('../../services/utils');
const TaskContext = require('../../services/task_context');
async function getNote(req) {
function getNote(req) {
const noteId = req.params.noteId;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note) {
return [404, "Note " + noteId + " has not been found."];
}
if (note.isStringNote()) {
note.content = await note.getContent();
note.content = note.getContent();
if (note.type === 'file') {
note.content = note.content.substr(0, 10000);
@@ -25,13 +25,13 @@ async function getNote(req) {
return note;
}
async function createNote(req) {
function createNote(req) {
const params = Object.assign({}, req.body); // clone
params.parentNoteId = req.params.parentNoteId;
const { target, targetBranchId } = req.query;
const { note, branch } = await noteService.createNewNoteWithTarget(target, targetBranchId, params);
const { note, branch } = noteService.createNewNoteWithTarget(target, targetBranchId, params);
return {
note,
@@ -39,14 +39,14 @@ async function createNote(req) {
};
}
async function updateNote(req) {
function updateNote(req) {
const note = req.body;
const noteId = req.params.noteId;
return await noteService.updateNote(noteId, note);
return noteService.updateNote(noteId, note);
}
async function deleteNote(req) {
function deleteNote(req) {
const noteId = req.params.noteId;
const taskId = req.query.taskId;
const last = req.query.last === 'true';
@@ -54,61 +54,61 @@ async function deleteNote(req) {
// note how deleteId is separate from taskId - single taskId produces separate deleteId for each "top level" deleted note
const deleteId = utils.randomString(10);
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
const taskContext = TaskContext.getInstance(taskId, 'delete-notes');
for (const branch of await note.getBranches()) {
await noteService.deleteBranch(branch, deleteId, taskContext);
for (const branch of note.getBranches()) {
noteService.deleteBranch(branch, deleteId, taskContext);
}
if (last) {
await taskContext.taskSucceeded();
taskContext.taskSucceeded();
}
}
async function undeleteNote(req) {
const note = await repository.getNote(req.params.noteId);
function undeleteNote(req) {
const note = repository.getNote(req.params.noteId);
const taskContext = TaskContext.getInstance(utils.randomString(10), 'undelete-notes');
await noteService.undeleteNote(note, note.deleteId, taskContext);
noteService.undeleteNote(note, note.deleteId, taskContext);
await taskContext.taskSucceeded();
taskContext.taskSucceeded();
}
async function sortNotes(req) {
function sortNotes(req) {
const noteId = req.params.noteId;
await treeService.sortNotesAlphabetically(noteId);
treeService.sortNotesAlphabetically(noteId);
}
async function protectNote(req) {
function protectNote(req) {
const noteId = req.params.noteId;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
const protect = !!parseInt(req.params.isProtected);
const includingSubTree = !!parseInt(req.query.subtree);
const taskContext = new TaskContext(utils.randomString(10), 'protect-notes', {protect});
await noteService.protectNoteRecursively(note, protect, includingSubTree, taskContext);
noteService.protectNoteRecursively(note, protect, includingSubTree, taskContext);
taskContext.taskSucceeded();
}
async function setNoteTypeMime(req) {
function setNoteTypeMime(req) {
// can't use [] destructuring because req.params is not iterable
const noteId = req.params[0];
const type = req.params[1];
const mime = req.params[2];
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
note.type = type;
note.mime = mime;
await note.save();
note.save();
}
async function getRelationMap(req) {
function getRelationMap(req) {
const noteIds = req.body.noteIds;
const resp = {
// noteId => title
@@ -126,12 +126,12 @@ async function getRelationMap(req) {
const questionMarks = noteIds.map(noteId => '?').join(',');
const notes = await repository.getEntities(`SELECT * FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
const notes = repository.getEntities(`SELECT * FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
for (const note of notes) {
resp.noteTitles[note.noteId] = note.title;
resp.relations = resp.relations.concat((await note.getRelations())
resp.relations = resp.relations.concat((note.getRelations())
.filter(relation => noteIds.includes(relation.value))
.map(relation => ({
attributeId: relation.attributeId,
@@ -140,7 +140,7 @@ async function getRelationMap(req) {
name: relation.name
})));
for (const relationDefinition of await note.getRelationDefinitions()) {
for (const relationDefinition of note.getRelationDefinitions()) {
if (relationDefinition.value.inverseRelation) {
resp.inverseRelations[relationDefinition.name] = relationDefinition.value.inverseRelation;
}
@@ -150,11 +150,11 @@ async function getRelationMap(req) {
return resp;
}
async function changeTitle(req) {
function changeTitle(req) {
const noteId = req.params.noteId;
const title = req.body.title;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} has not been found`];
@@ -166,15 +166,15 @@ async function changeTitle(req) {
note.title = title;
await note.save();
note.save();
return note;
}
async function duplicateNote(req) {
function duplicateNote(req) {
const {noteId, parentNoteId} = req.params;
return await noteService.duplicateNote(noteId, parentNoteId);
return noteService.duplicateNote(noteId, parentNoteId);
}
module.exports = {
@@ -189,4 +189,4 @@ module.exports = {
getRelationMap,
changeTitle,
duplicateNote
};
};

View File

@@ -40,8 +40,8 @@ const ALLOWED_OPTIONS = new Set([
'nativeTitleBarVisible'
]);
async function getOptions() {
const optionMap = await optionService.getOptionsMap();
function getOptions() {
const optionMap = optionService.getOptionsMap();
const resultMap = {};
for (const optionName in optionMap) {
@@ -53,17 +53,17 @@ async function getOptions() {
return resultMap;
}
async function updateOption(req) {
function updateOption(req) {
const {name, value} = req.params;
if (!await update(name, value)) {
if (!update(name, value)) {
return [400, "not allowed option to change"];
}
}
async function updateOptions(req) {
function updateOptions(req) {
for (const optionName in req.body) {
if (!await update(optionName, req.body[optionName])) {
if (!update(optionName, req.body[optionName])) {
// this should be improved
// it should return 400 instead of current 500, but at least it now rollbacks transaction
throw new Error(`${optionName} is not allowed to change`);
@@ -71,7 +71,7 @@ async function updateOptions(req) {
}
}
async function update(name, value) {
function update(name, value) {
if (!isAllowed(name)) {
return false;
}
@@ -80,18 +80,18 @@ async function update(name, value) {
log.info(`Updating option ${name} to ${value}`);
}
await optionService.setOption(name, value);
optionService.setOption(name, value);
return true;
}
async function getUserThemes() {
const notes = await attributes.getNotesWithLabel('appTheme');
function getUserThemes() {
const notes = attributes.getNotesWithLabel('appTheme');
const ret = [];
for (const note of notes) {
let value = await note.getOwnedLabelValue('appTheme');
let value = note.getOwnedLabelValue('appTheme');
if (!value) {
value = note.title.toLowerCase().replace(/[^a-z0-9]/gi, '-');
@@ -120,4 +120,4 @@ module.exports = {
updateOption,
updateOptions,
getUserThemes
};
};

View File

@@ -2,10 +2,10 @@
const changePasswordService = require('../../services/change_password');
async function changePassword(req) {
return await changePasswordService.changePassword(req.body.current_password, req.body.new_password);
function changePassword(req) {
return changePasswordService.changePassword(req.body.current_password, req.body.new_password);
}
module.exports = {
changePassword
};
};

View File

@@ -5,12 +5,12 @@ const protectedSessionService = require('../../services/protected_session');
const noteService = require('../../services/notes');
const noteCacheService = require('../../services/note_cache/note_cache.js');
async function getRecentChanges(req) {
function getRecentChanges(req) {
const {ancestorNoteId} = req.params;
let recentChanges = [];
const noteRevisions = await sql.getRows(`
const noteRevisions = sql.getRows(`
SELECT
notes.noteId,
notes.isDeleted AS current_isDeleted,
@@ -31,7 +31,7 @@ async function getRecentChanges(req) {
}
}
const notes = await sql.getRows(`
const notes = sql.getRows(`
SELECT
notes.noteId,
notes.isDeleted AS current_isDeleted,
@@ -75,7 +75,7 @@ async function getRecentChanges(req) {
else {
const deleteId = change.current_deleteId;
const undeletedParentBranches = await 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;

View File

@@ -2,8 +2,8 @@
const RecentNote = require('../../entities/recent_note');
async function addRecentNote(req) {
await new RecentNote({
function addRecentNote(req) {
new RecentNote({
noteId: req.body.noteId,
notePath: req.body.notePath
}).save();
@@ -11,4 +11,4 @@ async function addRecentNote(req) {
module.exports = {
addRecentNote
};
};

View File

@@ -5,15 +5,15 @@ const attributeService = require('../../services/attributes');
const repository = require('../../services/repository');
const syncService = require('../../services/sync');
async function exec(req) {
function exec(req) {
try {
const result = await scriptService.executeScript(req.body.script, req.body.params, req.body.startNoteId,
const result = scriptService.executeScript(req.body.script, req.body.params, req.body.startNoteId,
req.body.currentNoteId, req.body.originEntityName, req.body.originEntityId);
return {
success: true,
executionResult: result,
maxSyncId: await syncService.getMaxSyncId()
maxSyncId: syncService.getMaxSyncId()
};
}
catch (e) {
@@ -21,21 +21,21 @@ async function exec(req) {
}
}
async function run(req) {
const note = await repository.getNote(req.params.noteId);
function run(req) {
const note = repository.getNote(req.params.noteId);
const result = await scriptService.executeNote(note, { originEntity: note });
const result = scriptService.executeNote(note, { originEntity: note });
return { executionResult: result };
}
async function getBundlesWithLabel(label, value) {
const notes = await attributeService.getNotesWithLabel(label, value);
function getBundlesWithLabel(label, value) {
const notes = attributeService.getNotesWithLabel(label, value);
const bundles = [];
for (const note of notes) {
const bundle = await scriptService.getScriptBundleForFrontend(note);
const bundle = scriptService.getScriptBundleForFrontend(note);
if (bundle) {
bundles.push(bundle);
@@ -45,20 +45,20 @@ async function getBundlesWithLabel(label, value) {
return bundles;
}
async function getStartupBundles() {
return await getBundlesWithLabel("run", "frontendStartup");
function getStartupBundles() {
return getBundlesWithLabel("run", "frontendStartup");
}
async function getWidgetBundles() {
return await getBundlesWithLabel("widget");
function getWidgetBundles() {
return getBundlesWithLabel("widget");
}
async function getRelationBundles(req) {
function getRelationBundles(req) {
const noteId = req.params.noteId;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
const relationName = req.params.relationName;
const attributes = await note.getAttributes();
const attributes = note.getAttributes();
const filtered = attributes.filter(attr => attr.type === 'relation' && attr.name === relationName);
const targetNoteIds = filtered.map(relation => relation.value);
const uniqueNoteIds = Array.from(new Set(targetNoteIds));
@@ -66,13 +66,13 @@ async function getRelationBundles(req) {
const bundles = [];
for (const noteId of uniqueNoteIds) {
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note.isJavaScript() || note.getScriptEnv() !== 'frontend') {
continue;
}
const bundle = await scriptService.getScriptBundleForFrontend(note);
const bundle = scriptService.getScriptBundleForFrontend(note);
if (bundle) {
bundles.push(bundle);
@@ -82,10 +82,10 @@ async function getRelationBundles(req) {
return bundles;
}
async function getBundle(req) {
const note = await repository.getNote(req.params.noteId);
function getBundle(req) {
const note = repository.getNote(req.params.noteId);
return await scriptService.getScriptBundleForFrontend(note);
return scriptService.getScriptBundleForFrontend(note);
}
module.exports = {
@@ -95,4 +95,4 @@ module.exports = {
getWidgetBundles,
getRelationBundles,
getBundle
};
};

View File

@@ -6,8 +6,8 @@ const log = require('../../services/log');
const scriptService = require('../../services/script');
const searchService = require('../../services/search/search');
async function searchNotes(req) {
const {count, results} = await searchService.searchNotes(req.params.searchString);
function searchNotes(req) {
const {count, results} = searchService.searchNotes(req.params.searchString);
try {
return {
@@ -23,8 +23,8 @@ async function searchNotes(req) {
}
}
async function searchFromNote(req) {
const note = await repository.getNote(req.params.noteId);
function searchFromNote(req) {
const note = repository.getNote(req.params.noteId);
if (!note) {
return [404, `Note ${req.params.noteId} has not been found.`];
@@ -38,7 +38,7 @@ async function searchFromNote(req) {
return [400, `Note ${req.params.noteId} is not search note.`]
}
const json = await note.getJsonContent();
const json = note.getJsonContent();
if (!json || !json.searchString) {
return [];
@@ -50,9 +50,9 @@ async function searchFromNote(req) {
if (json.searchString.startsWith('=')) {
const relationName = json.searchString.substr(1).trim();
noteIds = await searchFromRelation(note, relationName);
noteIds = searchFromRelation(note, relationName);
} else {
noteIds = await searchService.searchForNoteIds(json.searchString);
noteIds = searchService.searchForNoteIds(json.searchString);
}
}
catch (e) {
@@ -71,8 +71,8 @@ async function searchFromNote(req) {
return noteIds.map(noteCacheService.getNotePath).filter(res => !!res);
}
async function searchFromRelation(note, relationName) {
const scriptNote = await note.getRelationTarget(relationName);
function searchFromRelation(note, relationName) {
const scriptNote = note.getRelationTarget(relationName);
if (!scriptNote) {
log.info(`Search note's relation ${relationName} has not been found.`);
@@ -92,7 +92,7 @@ async function searchFromRelation(note, relationName) {
return [];
}
const result = await scriptService.executeNote(scriptNote, { originEntity: note });
const result = scriptService.executeNote(scriptNote, { originEntity: note });
if (!Array.isArray(result)) {
log.info(`Result from ${scriptNote.noteId} is not an array.`);

View File

@@ -5,7 +5,7 @@ const imageService = require('../../services/image');
const dateNoteService = require('../../services/date_notes');
const noteService = require('../../services/notes');
async function uploadImage(req) {
function uploadImage(req) {
const file = req.file;
if (!["image/png", "image/jpeg", "image/gif"].includes(file.mimetype)) {
@@ -14,19 +14,19 @@ async function uploadImage(req) {
const originalName = "Sender image." + imageType(file.buffer).ext;
const parentNote = await dateNoteService.getDateNote(req.headers['x-local-date']);
const parentNote = dateNoteService.getDateNote(req.headers['x-local-date']);
const {noteId} = await imageService.saveImage(parentNote.noteId, file.buffer, originalName, true);
const {noteId} = imageService.saveImage(parentNote.noteId, file.buffer, originalName, true);
return {
noteId: noteId
};
}
async function saveNote(req) {
const parentNote = await dateNoteService.getDateNote(req.headers['x-local-date']);
function saveNote(req) {
const parentNote = dateNoteService.getDateNote(req.headers['x-local-date']);
const {note, branch} = await noteService.createNewNote({
const {note, branch} = noteService.createNewNote({
parentNoteId: parentNote.noteId,
title: req.body.title,
content: req.body.content,
@@ -44,4 +44,4 @@ async function saveNote(req) {
module.exports = {
uploadImage,
saveNote
};
};

View File

@@ -5,27 +5,27 @@ const setupService = require('../../services/setup');
const log = require('../../services/log');
const appInfo = require('../../services/app_info');
async function getStatus() {
function getStatus() {
return {
isInitialized: await sqlInit.isDbInitialized(),
schemaExists: await sqlInit.schemaExists(),
isInitialized: sqlInit.isDbInitialized(),
schemaExists: sqlInit.schemaExists(),
syncVersion: appInfo.syncVersion
};
}
async function setupNewDocument(req) {
function setupNewDocument(req) {
const { username, password, theme } = req.body;
await sqlInit.createInitialDatabase(username, password, theme);
sqlInit.createInitialDatabase(username, password, theme);
}
async function setupSyncFromServer(req) {
function setupSyncFromServer(req) {
const { syncServerHost, syncProxy, username, password } = req.body;
return await setupService.setupSyncFromSyncServer(syncServerHost, syncProxy, username, password);
return setupService.setupSyncFromSyncServer(syncServerHost, syncProxy, username, password);
}
async function saveSyncSeed(req) {
function saveSyncSeed(req) {
const {options, syncVersion} = req.body;
if (appInfo.syncVersion !== syncVersion) {
@@ -38,14 +38,14 @@ async function saveSyncSeed(req) {
}]
}
await sqlInit.createDatabaseForSync(options);
sqlInit.createDatabaseForSync(options);
}
async function getSyncSeed() {
function getSyncSeed() {
log.info("Serving sync seed.");
return {
options: await setupService.getSyncSeedOptions(),
options: setupService.getSyncSeedOptions(),
syncVersion: appInfo.syncVersion
};
}
@@ -56,4 +56,4 @@ module.exports = {
setupSyncFromServer,
getSyncSeed,
saveSyncSeed
};
};

View File

@@ -3,16 +3,16 @@
const noteCacheService = require('../../services/note_cache/note_cache_service');
const repository = require('../../services/repository');
async function getSimilarNotes(req) {
function getSimilarNotes(req) {
const noteId = req.params.noteId;
const note = await repository.getNote(noteId);
const note = repository.getNote(noteId);
if (!note) {
return [404, `Note ${noteId} not found.`];
}
const results = await noteCacheService.findSimilarNotes(noteId);
const results = noteCacheService.findSimilarNotes(noteId);
return results
.filter(note => note.noteId !== noteId);

View File

@@ -2,21 +2,21 @@
const sql = require('../../services/sql');
async function getSchema() {
const tableNames = await sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
function getSchema() {
const tableNames = sql.getColumn(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name`);
const tables = [];
for (const tableName of tableNames) {
tables.push({
name: tableName,
columns: await sql.getRows(`PRAGMA table_info(${tableName})`)
columns: sql.getRows(`PRAGMA table_info(${tableName})`)
});
}
return tables;
}
async function execute(req) {
function execute(req) {
const queries = req.body.query.split("\n---");
try {
@@ -27,7 +27,7 @@ async function execute(req) {
continue;
}
results.push(await sql.getRows(query));
results.push(sql.getRows(query));
}
return {
@@ -46,4 +46,4 @@ async function execute(req) {
module.exports = {
getSchema,
execute
};
};

View File

@@ -13,13 +13,13 @@ const dateUtils = require('../../services/date_utils');
const entityConstructor = require('../../entities/entity_constructor');
const utils = require('../../services/utils');
async function testSync() {
function testSync() {
try {
if (!await syncOptions.isSyncSetup()) {
if (!syncOptions.isSyncSetup()) {
return { success: false, message: "Sync server host is not configured. Please configure sync first." };
}
await syncService.login();
syncService.login();
// login was successful so we'll kick off sync now
// this is important in case when sync server has been just initialized
@@ -35,40 +35,40 @@ async function testSync() {
}
}
async function getStats() {
if (!await sqlInit.schemaExists()) {
function getStats() {
if (!sqlInit.schemaExists()) {
// fail silently but prevent errors from not existing options table
return {};
}
return {
initialized: await optionService.getOption('initialized') === 'true',
initialized: optionService.getOption('initialized') === 'true',
stats: syncService.stats
};
}
async function checkSync() {
function checkSync() {
return {
entityHashes: await contentHashService.getEntityHashes(),
maxSyncId: await sql.getValue('SELECT MAX(id) FROM sync WHERE isSynced = 1')
entityHashes: contentHashService.getEntityHashes(),
maxSyncId: sql.getValue('SELECT MAX(id) FROM sync WHERE isSynced = 1')
};
}
async function syncNow() {
function syncNow() {
log.info("Received request to trigger sync now.");
return await syncService.sync();
return syncService.sync();
}
async function fillSyncRows() {
await syncTableService.fillAllSyncRows();
function fillSyncRows() {
syncTableService.fillAllSyncRows();
log.info("Sync rows have been filled.");
}
async function forceFullSync() {
await optionService.setOption('lastSyncedPull', 0);
await optionService.setOption('lastSyncedPush', 0);
function forceFullSync() {
optionService.setOption('lastSyncedPull', 0);
optionService.setOption('lastSyncedPush', 0);
log.info("Forcing full sync.");
@@ -76,38 +76,38 @@ async function forceFullSync() {
syncService.sync();
}
async function forceNoteSync(req) {
function forceNoteSync(req) {
const noteId = req.params.noteId;
const now = dateUtils.utcNowDateTime();
await sql.execute(`UPDATE notes SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]);
await syncTableService.addNoteSync(noteId);
sql.execute(`UPDATE notes SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]);
syncTableService.addNoteSync(noteId);
await sql.execute(`UPDATE note_contents SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]);
await syncTableService.addNoteContentSync(noteId);
sql.execute(`UPDATE note_contents SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]);
syncTableService.addNoteContentSync(noteId);
for (const branchId of await sql.getColumn("SELECT branchId FROM branches WHERE noteId = ?", [noteId])) {
await sql.execute(`UPDATE branches SET utcDateModified = ? WHERE branchId = ?`, [now, branchId]);
for (const branchId of sql.getColumn("SELECT branchId FROM branches WHERE noteId = ?", [noteId])) {
sql.execute(`UPDATE branches SET utcDateModified = ? WHERE branchId = ?`, [now, branchId]);
await syncTableService.addBranchSync(branchId);
syncTableService.addBranchSync(branchId);
}
for (const attributeId of await sql.getColumn("SELECT attributeId FROM attributes WHERE noteId = ?", [noteId])) {
await sql.execute(`UPDATE attributes SET utcDateModified = ? WHERE attributeId = ?`, [now, attributeId]);
for (const attributeId of sql.getColumn("SELECT attributeId FROM attributes WHERE noteId = ?", [noteId])) {
sql.execute(`UPDATE attributes SET utcDateModified = ? WHERE attributeId = ?`, [now, attributeId]);
await syncTableService.addAttributeSync(attributeId);
syncTableService.addAttributeSync(attributeId);
}
for (const noteRevisionId of await sql.getColumn("SELECT noteRevisionId FROM note_revisions WHERE noteId = ?", [noteId])) {
await sql.execute(`UPDATE note_revisions SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]);
await syncTableService.addNoteRevisionSync(noteRevisionId);
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]);
syncTableService.addNoteRevisionSync(noteRevisionId);
await sql.execute(`UPDATE note_revision_contents SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]);
await syncTableService.addNoteRevisionContentSync(noteRevisionId);
sql.execute(`UPDATE note_revision_contents SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]);
syncTableService.addNoteRevisionContentSync(noteRevisionId);
}
await syncTableService.addRecentNoteSync(noteId);
syncTableService.addRecentNoteSync(noteId);
log.info("Forcing note sync for " + noteId);
@@ -115,16 +115,16 @@ async function forceNoteSync(req) {
syncService.sync();
}
async function getChanged(req) {
function getChanged(req) {
const startTime = Date.now();
const lastSyncId = parseInt(req.query.lastSyncId);
const syncs = await sql.getRows("SELECT * FROM sync WHERE isSynced = 1 AND id > ? LIMIT 1000", [lastSyncId]);
const syncs = sql.getRows("SELECT * FROM sync WHERE isSynced = 1 AND id > ? LIMIT 1000", [lastSyncId]);
const ret = {
syncs: await syncService.getSyncRecords(syncs),
maxSyncId: await sql.getValue('SELECT MAX(id) FROM sync WHERE isSynced = 1')
syncs: syncService.getSyncRecords(syncs),
maxSyncId: sql.getValue('SELECT MAX(id) FROM sync WHERE isSynced = 1')
};
if (ret.syncs.length > 0) {
@@ -134,28 +134,28 @@ async function getChanged(req) {
return ret;
}
async function update(req) {
function update(req) {
const sourceId = req.body.sourceId;
const entities = req.body.entities;
for (const {sync, entity} of entities) {
await syncUpdateService.updateEntity(sync, entity, sourceId);
syncUpdateService.updateEntity(sync, entity, sourceId);
}
}
async function syncFinished() {
function syncFinished() {
// after first sync finishes, the application is ready to be used
// this is meaningless but at the same time harmless (idempotent) for further syncs
await sqlInit.dbInitialized();
sqlInit.dbInitialized();
}
async function queueSector(req) {
function queueSector(req) {
const entityName = utils.sanitizeSqlIdentifier(req.params.entityName);
const sector = utils.sanitizeSqlIdentifier(req.params.sector);
const entityPrimaryKey = entityConstructor.getEntityFromEntityName(entityName).primaryKeyName;
await syncTableService.addEntitySyncsForSector(entityName, entityPrimaryKey, sector);
syncTableService.addEntitySyncsForSector(entityName, entityPrimaryKey, sector);
}
module.exports = {

View File

@@ -4,15 +4,15 @@ const sql = require('../../services/sql');
const optionService = require('../../services/options');
const treeService = require('../../services/tree');
async function getNotesAndBranchesAndAttributes(noteIds) {
function getNotesAndBranchesAndAttributes(noteIds) {
noteIds = Array.from(new Set(noteIds));
const notes = await treeService.getNotes(noteIds);
const notes = treeService.getNotes(noteIds);
noteIds = notes.map(note => note.noteId);
// joining child note to filter out not completely synchronised notes which would then cause errors later
// cannot do that with parent because of root note's 'none' parent
const branches = await sql.getManyRows(`
const branches = sql.getManyRows(`
SELECT
branches.branchId,
branches.noteId,
@@ -28,7 +28,7 @@ async function getNotesAndBranchesAndAttributes(noteIds) {
// sorting in memory is faster
branches.sort((a, b) => a.notePosition - b.notePosition < 0 ? -1 : 1);
const attributes = await sql.getManyRows(`
const attributes = sql.getManyRows(`
SELECT
attributeId,
noteId,
@@ -50,12 +50,12 @@ async function getNotesAndBranchesAndAttributes(noteIds) {
};
}
async function getTree() {
const hoistedNoteId = await optionService.getOption('hoistedNoteId');
function getTree() {
const hoistedNoteId = optionService.getOption('hoistedNoteId');
// we fetch all branches of notes, even if that particular branch isn't visible
// this allows us to e.g. detect and properly display clones
const noteIds = await sql.getColumn(`
const noteIds = sql.getColumn(`
WITH RECURSIVE
tree(branchId, noteId, isExpanded) AS (
SELECT branchId, noteId, isExpanded FROM branches WHERE noteId = ?
@@ -68,11 +68,11 @@ async function getTree() {
noteIds.push('root');
return await getNotesAndBranchesAndAttributes(noteIds);
return getNotesAndBranchesAndAttributes(noteIds);
}
async function load(req) {
return await getNotesAndBranchesAndAttributes(req.body.noteIds);
function load(req) {
return getNotesAndBranchesAndAttributes(req.body.noteIds);
}
module.exports = {