cycle check when cloning notes

This commit is contained in:
azivner 2017-11-23 21:50:12 -05:00
parent c72e5ef93b
commit c9ccf797da

View file

@ -93,12 +93,17 @@ router.put('/:childNoteId/cloneTo/:parentNoteId', auth.checkApiAuth, async (req,
const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND note_pid = ?', [childNoteId, parentNoteId]); const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND note_pid = ?', [childNoteId, parentNoteId]);
if (existing && !existing.is_deleted) { if (existing && !existing.is_deleted) {
res.send({ return res.send({
success: false, success: false,
message: 'This note already exists in target parent note.' message: 'This note already exists in target parent note.'
}); });
}
return; if (!await checkCycle(parentNoteId, childNoteId)) {
return res.send({
success: false,
message: 'Cloning note here would create cycle.'
});
} }
const maxNotePos = await sql.getSingleValue('SELECT MAX(note_pos) FROM notes_tree WHERE note_pid = ? AND is_deleted = 0', [parentNoteId]); const maxNotePos = await sql.getSingleValue('SELECT MAX(note_pos) FROM notes_tree WHERE note_pid = ? AND is_deleted = 0', [parentNoteId]);
@ -132,19 +137,23 @@ router.put('/:noteId/cloneAfter/:afterNoteTreeId', async (req, res, next) => {
const afterNote = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]); const afterNote = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]);
if (!afterNote) { if (!afterNote) {
res.status(500).send("After note " + afterNoteTreeId + " doesn't exist."); return res.status(500).send("After note " + afterNoteTreeId + " doesn't exist.");
return; }
if (!await checkCycle(afterNote.note_pid, noteId)) {
return res.send({
success: false,
message: 'Cloning note here would create cycle.'
});
} }
const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND note_pid = ?', [noteId, afterNote.note_pid]); const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND note_pid = ?', [noteId, afterNote.note_pid]);
if (existing && !existing.is_deleted) { if (existing && !existing.is_deleted) {
res.send({ return res.send({
success: false, success: false,
message: 'This note already exists in target parent note.' message: 'This note already exists in target parent note.'
}); });
return;
} }
await sql.doInTransaction(async () => { await sql.doInTransaction(async () => {
@ -174,6 +183,26 @@ router.put('/:noteId/cloneAfter/:afterNoteTreeId', async (req, res, next) => {
}); });
}); });
async function checkCycle(parentNoteId, childNoteId) {
if (parentNoteId === 'root') {
return true;
}
if (parentNoteId === childNoteId) {
return false;
}
const parentNoteIds = await sql.getFlattenedResults("note_pid", "SELECT DISTINCT note_pid FROM notes_tree WHERE note_id = ?", [parentNoteId]);
for (const pid of parentNoteIds) {
if (!await checkCycle(pid, childNoteId)) {
return false;
}
}
return true;
}
router.put('/:noteTreeId/expanded/:expanded', async (req, res, next) => { router.put('/:noteTreeId/expanded/:expanded', async (req, res, next) => {
const noteTreeId = req.params.noteTreeId; const noteTreeId = req.params.noteTreeId;
const expanded = req.params.expanded; const expanded = req.params.expanded;