mirror of
https://github.com/zadam/trilium.git
synced 2025-01-18 04:59:56 +08:00
converted cloning and label routes
This commit is contained in:
parent
efffc29649
commit
8550ed72f2
6 changed files with 121 additions and 107 deletions
|
@ -1,4 +1,5 @@
|
|||
import treeService from './tree.js';
|
||||
import server from './server.js';
|
||||
|
||||
async function cloneNoteTo(childNoteId, parentNoteId, prefix) {
|
||||
const resp = await server.put('notes/' + childNoteId + '/clone-to/' + parentNoteId, {
|
||||
|
|
|
@ -1,84 +1,83 @@
|
|||
"use strict";
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const sql = require('../../services/sql');
|
||||
const auth = require('../../services/auth');
|
||||
const utils = require('../../services/utils');
|
||||
const sync_table = require('../../services/sync_table');
|
||||
const wrap = require('express-promise-wrap').wrap;
|
||||
const tree = require('../../services/tree');
|
||||
|
||||
router.put('/:childNoteId/clone-to/:parentNoteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
async function cloneNoteToParent(req) {
|
||||
const parentNoteId = req.params.parentNoteId;
|
||||
const childNoteId = req.params.childNoteId;
|
||||
const prefix = req.body.prefix;
|
||||
const sourceId = req.headers.source_id;
|
||||
|
||||
if (!await tree.validateParentChild(res, parentNoteId, childNoteId)) {
|
||||
return;
|
||||
const validationResult = await tree.validateParentChild(parentNoteId, childNoteId);
|
||||
|
||||
if (!validationResult.success) {
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [parentNoteId]);
|
||||
const newNotePos = maxNotePos === null ? 0 : maxNotePos + 1;
|
||||
|
||||
await sql.doInTransaction(async () => {
|
||||
const branch = {
|
||||
branchId: utils.newBranchId(),
|
||||
noteId: childNoteId,
|
||||
parentNoteId: parentNoteId,
|
||||
prefix: prefix,
|
||||
notePosition: newNotePos,
|
||||
isExpanded: 0,
|
||||
dateModified: utils.nowDate(),
|
||||
isDeleted: 0
|
||||
};
|
||||
const branch = {
|
||||
branchId: utils.newBranchId(),
|
||||
noteId: childNoteId,
|
||||
parentNoteId: parentNoteId,
|
||||
prefix: prefix,
|
||||
notePosition: newNotePos,
|
||||
isExpanded: 0,
|
||||
dateModified: utils.nowDate(),
|
||||
isDeleted: 0
|
||||
};
|
||||
|
||||
await sql.replace("branches", branch);
|
||||
await sql.replace("branches", branch);
|
||||
|
||||
await sync_table.addBranchSync(branch.branchId, sourceId);
|
||||
await sync_table.addBranchSync(branch.branchId, sourceId);
|
||||
|
||||
await sql.execute("UPDATE branches SET isExpanded = 1 WHERE noteId = ?", [parentNoteId]);
|
||||
});
|
||||
await sql.execute("UPDATE branches SET isExpanded = 1 WHERE noteId = ?", [parentNoteId]);
|
||||
|
||||
res.send({ success: true });
|
||||
}));
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
router.put('/:noteId/clone-after/:afterBranchId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
async function cloneNoteAfter(req) {
|
||||
const noteId = req.params.noteId;
|
||||
const afterBranchId = req.params.afterBranchId;
|
||||
const sourceId = req.headers.source_id;
|
||||
|
||||
const afterNote = await tree.getBranch(afterBranchId);
|
||||
|
||||
if (!await tree.validateParentChild(res, afterNote.parentNoteId, noteId)) {
|
||||
return;
|
||||
const validationResult = await tree.validateParentChild(afterNote.parentNoteId, noteId);
|
||||
|
||||
if (!validationResult.result) {
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
await sql.doInTransaction(async () => {
|
||||
// we don't change dateModified so other changes are prioritized in case of conflict
|
||||
// also we would have to sync all those modified note trees otherwise hash checks would fail
|
||||
await sql.execute("UPDATE branches SET notePosition = notePosition + 1 WHERE parentNoteId = ? AND notePosition > ? AND isDeleted = 0",
|
||||
[afterNote.parentNoteId, afterNote.notePosition]);
|
||||
// we don't change dateModified so other changes are prioritized in case of conflict
|
||||
// also we would have to sync all those modified note trees otherwise hash checks would fail
|
||||
await sql.execute("UPDATE branches SET notePosition = notePosition + 1 WHERE parentNoteId = ? AND notePosition > ? AND isDeleted = 0",
|
||||
[afterNote.parentNoteId, afterNote.notePosition]);
|
||||
|
||||
await sync_table.addNoteReorderingSync(afterNote.parentNoteId, sourceId);
|
||||
await sync_table.addNoteReorderingSync(afterNote.parentNoteId, sourceId);
|
||||
|
||||
const branch = {
|
||||
branchId: utils.newBranchId(),
|
||||
noteId: noteId,
|
||||
parentNoteId: afterNote.parentNoteId,
|
||||
notePosition: afterNote.notePosition + 1,
|
||||
isExpanded: 0,
|
||||
dateModified: utils.nowDate(),
|
||||
isDeleted: 0
|
||||
};
|
||||
const branch = {
|
||||
branchId: utils.newBranchId(),
|
||||
noteId: noteId,
|
||||
parentNoteId: afterNote.parentNoteId,
|
||||
notePosition: afterNote.notePosition + 1,
|
||||
isExpanded: 0,
|
||||
dateModified: utils.nowDate(),
|
||||
isDeleted: 0
|
||||
};
|
||||
|
||||
await sql.replace("branches", branch);
|
||||
await sql.replace("branches", branch);
|
||||
|
||||
await sync_table.addBranchSync(branch.branchId, sourceId);
|
||||
});
|
||||
await sync_table.addBranchSync(branch.branchId, sourceId);
|
||||
|
||||
res.send({ success: true });
|
||||
}));
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
module.exports = router;
|
||||
module.exports = {
|
||||
cloneNoteToParent,
|
||||
cloneNoteAfter
|
||||
};
|
|
@ -1,59 +1,53 @@
|
|||
"use strict";
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const sql = require('../../services/sql');
|
||||
const auth = require('../../services/auth');
|
||||
const sync_table = require('../../services/sync_table');
|
||||
const utils = require('../../services/utils');
|
||||
const wrap = require('express-promise-wrap').wrap;
|
||||
const labels = require('../../services/labels');
|
||||
|
||||
router.get('/notes/:noteId/labels', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
async function getNoteLabels(req) {
|
||||
const noteId = req.params.noteId;
|
||||
|
||||
res.send(await sql.getRows("SELECT * FROM labels WHERE isDeleted = 0 AND noteId = ? ORDER BY position, dateCreated", [noteId]));
|
||||
}));
|
||||
return await sql.getRows("SELECT * FROM labels WHERE isDeleted = 0 AND noteId = ? ORDER BY position, dateCreated", [noteId]);
|
||||
}
|
||||
|
||||
router.put('/notes/:noteId/labels', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
async function updateNoteLabels(req, res, next) {
|
||||
const noteId = req.params.noteId;
|
||||
const labels = req.body;
|
||||
const now = utils.nowDate();
|
||||
|
||||
await sql.doInTransaction(async () => {
|
||||
for (const attr of labels) {
|
||||
if (attr.labelId) {
|
||||
await sql.execute("UPDATE labels SET name = ?, value = ?, dateModified = ?, isDeleted = ?, position = ? WHERE labelId = ?",
|
||||
[attr.name, attr.value, now, attr.isDeleted, attr.position, attr.labelId]);
|
||||
}
|
||||
else {
|
||||
// if it was "created" and then immediatelly deleted, we just don't create it at all
|
||||
if (attr.isDeleted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
attr.labelId = utils.newLabelId();
|
||||
|
||||
await sql.insert("labels", {
|
||||
labelId: attr.labelId,
|
||||
noteId: noteId,
|
||||
name: attr.name,
|
||||
value: attr.value,
|
||||
position: attr.position,
|
||||
dateCreated: now,
|
||||
dateModified: now,
|
||||
isDeleted: false
|
||||
});
|
||||
}
|
||||
|
||||
await sync_table.addLabelSync(attr.labelId);
|
||||
for (const attr of labels) {
|
||||
if (attr.labelId) {
|
||||
await sql.execute("UPDATE labels SET name = ?, value = ?, dateModified = ?, isDeleted = ?, position = ? WHERE labelId = ?",
|
||||
[attr.name, attr.value, now, attr.isDeleted, attr.position, attr.labelId]);
|
||||
}
|
||||
});
|
||||
else {
|
||||
// if it was "created" and then immediatelly deleted, we just don't create it at all
|
||||
if (attr.isDeleted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
res.send(await sql.getRows("SELECT * FROM labels WHERE isDeleted = 0 AND noteId = ? ORDER BY position, dateCreated", [noteId]));
|
||||
}));
|
||||
attr.labelId = utils.newLabelId();
|
||||
|
||||
router.get('/labels/names', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
await sql.insert("labels", {
|
||||
labelId: attr.labelId,
|
||||
noteId: noteId,
|
||||
name: attr.name,
|
||||
value: attr.value,
|
||||
position: attr.position,
|
||||
dateCreated: now,
|
||||
dateModified: now,
|
||||
isDeleted: false
|
||||
});
|
||||
}
|
||||
|
||||
await sync_table.addLabelSync(attr.labelId);
|
||||
}
|
||||
|
||||
return await sql.getRows("SELECT * FROM labels WHERE isDeleted = 0 AND noteId = ? ORDER BY position, dateCreated", [noteId]);
|
||||
}
|
||||
|
||||
async function getAllLabelNames(req) {
|
||||
const names = await sql.getColumn("SELECT DISTINCT name FROM labels WHERE isDeleted = 0");
|
||||
|
||||
for (const attr of labels.BUILTIN_LABELS) {
|
||||
|
@ -64,15 +58,18 @@ router.get('/labels/names', auth.checkApiAuth, wrap(async (req, res, next) => {
|
|||
|
||||
names.sort();
|
||||
|
||||
res.send(names);
|
||||
}));
|
||||
return names;
|
||||
}
|
||||
|
||||
router.get('/labels/values/:labelName', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
async function getValuesForLabel(req) {
|
||||
const labelName = req.params.labelName;
|
||||
|
||||
const values = await sql.getColumn("SELECT DISTINCT value FROM labels WHERE isDeleted = 0 AND name = ? AND value != '' ORDER BY value", [labelName]);
|
||||
return await sql.getColumn("SELECT DISTINCT value FROM labels WHERE isDeleted = 0 AND name = ? AND value != '' ORDER BY value", [labelName]);
|
||||
}
|
||||
|
||||
res.send(values);
|
||||
}));
|
||||
|
||||
module.exports = router;
|
||||
module.exports = {
|
||||
getNoteLabels,
|
||||
updateNoteLabels,
|
||||
getAllLabelNames,
|
||||
getValuesForLabel
|
||||
};
|
|
@ -1,14 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const sql = require('../../services/sql');
|
||||
const auth = require('../../services/auth');
|
||||
const utils = require('../../services/utils');
|
||||
const sync_table = require('../../services/sync_table');
|
||||
const tree = require('../../services/tree');
|
||||
const notes = require('../../services/notes');
|
||||
const wrap = require('express-promise-wrap').wrap;
|
||||
|
||||
/**
|
||||
* Code in this file deals with moving and cloning note tree rows. Relationship between note and parent note is unique
|
||||
|
|
|
@ -32,6 +32,7 @@ const senderRoute = require('./api/sender');
|
|||
const filesRoute = require('./api/file_upload');
|
||||
const searchRoute = require('./api/search');
|
||||
|
||||
const log = require('../services/log');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const auth = require('../services/auth');
|
||||
|
@ -41,20 +42,29 @@ const sql = require('../services/sql');
|
|||
function apiRoute(method, path, handler) {
|
||||
router[method](path, auth.checkApiAuth, async (req, res, next) => {
|
||||
try {
|
||||
const resp = await cls.init(async () => {
|
||||
const result = await cls.init(async () => {
|
||||
cls.namespace.set('sourceId', req.headers.source_id);
|
||||
|
||||
return await sql.doInTransaction(async () => {
|
||||
return await handler(req, res, next);
|
||||
});
|
||||
});
|
||||
|
||||
if (Array.isArray(resp)) {
|
||||
res.status(resp[0]).send(resp[1]);
|
||||
// if it's an array and first element is integer then we consider this to be [statusCode, response] format
|
||||
if (Array.isArray(result) && result.length > 0 && Number.isInteger(result[0])) {
|
||||
const [statusCode, response] = result;
|
||||
|
||||
res.status(statusCode).send(response);
|
||||
|
||||
if (statusCode !== 200) {
|
||||
log.info(`${method} ${path} returned ${statusCode} with response ${JSON.stringify(response)}`);
|
||||
}
|
||||
}
|
||||
else if (resp === undefined) {
|
||||
else if (result === undefined) {
|
||||
res.status(200);
|
||||
}
|
||||
else {
|
||||
res.status(200).send(resp);
|
||||
res.status(200).send(result);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -88,8 +98,14 @@ function register(app) {
|
|||
apiRoute(PUT, '/api/notes/:noteId/protect-sub-tree/:isProtected', notesApiRoute.protectBranch);
|
||||
apiRoute(PUT, /\/api\/notes\/(.*)\/type\/(.*)\/mime\/(.*)/, notesApiRoute.setNoteTypeMime);
|
||||
|
||||
app.use('/api/notes', cloningApiRoute);
|
||||
app.use('/api', labelsRoute);
|
||||
apiRoute(PUT, '/api/notes/:childNoteId/clone-to/:parentNoteId', cloningApiRoute.cloneNoteToParent);
|
||||
apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter);
|
||||
|
||||
apiRoute(GET, '/api/notes/:noteId/labels', labelsRoute.getNoteLabels);
|
||||
apiRoute(PUT, '/api/notes/:noteId/labels', labelsRoute.updateNoteLabels);
|
||||
apiRoute(GET, '/api/labels/names', labelsRoute.getAllLabelNames);
|
||||
apiRoute(GET, '/api/labels/values/:labelName', labelsRoute.getValuesForLabel);
|
||||
|
||||
app.use('/api/notes-revisions', noteRevisionsApiRoute);
|
||||
app.use('/api/recent-changes', recentChangesApiRoute);
|
||||
app.use('/api/settings', settingsApiRoute);
|
||||
|
|
|
@ -9,8 +9,13 @@ function wrap(callback) {
|
|||
return async () => await init(callback);
|
||||
}
|
||||
|
||||
function getSourceId() {
|
||||
return namespace.get('sourceId');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init,
|
||||
wrap,
|
||||
namespace
|
||||
namespace,
|
||||
getSourceId
|
||||
};
|
Loading…
Reference in a new issue