2017-10-21 21:10:33 -04:00
"use strict" ;
2023-11-22 19:34:48 +01:00
const noteService = require ( '../../services/notes.js' ) ;
const eraseService = require ( '../../services/erase.js' ) ;
const treeService = require ( '../../services/tree.js' ) ;
2024-02-16 22:44:12 +02:00
const sql = require ( '../../services/sql' ) ;
2024-02-16 21:38:09 +02:00
const utils = require ( '../../services/utils' ) ;
2024-02-16 21:17:33 +02:00
const log = require ( '../../services/log' ) ;
2023-11-22 19:34:48 +01:00
const TaskContext = require ( '../../services/task_context.js' ) ;
const becca = require ( '../../becca/becca.js' ) ;
2024-02-16 22:50:49 +02:00
const ValidationError = require ( '../../errors/validation_error' ) ;
2023-11-22 19:34:48 +01:00
const blobService = require ( '../../services/blob.js' ) ;
2017-10-14 23:31:44 -04:00
2020-06-20 12:31:38 +02:00
function getNote ( req ) {
2023-05-08 00:02:08 +02:00
return becca . getNoteOrThrow ( req . params . noteId ) ;
2023-05-05 22:21:51 +02:00
}
2021-06-03 21:47:25 +02:00
2023-05-05 22:21:51 +02:00
function getNoteBlob ( req ) {
2023-07-25 22:27:15 +02:00
return blobService . getBlobPojo ( 'notes' , req . params . noteId ) ;
2023-05-05 22:21:51 +02:00
}
function getNoteMetadata ( req ) {
2023-05-08 00:02:08 +02:00
const note = becca . getNoteOrThrow ( req . params . noteId ) ;
2020-08-16 22:57:48 +02:00
2023-05-05 22:21:51 +02:00
return {
dateCreated : note . dateCreated ,
2023-09-06 22:54:31 +02:00
utcDateCreated : note . utcDateCreated ,
dateModified : note . dateModified ,
utcDateModified : note . utcDateModified ,
2023-05-05 22:21:51 +02:00
} ;
2023-05-05 16:37:39 +02:00
}
2020-06-20 12:31:38 +02:00
function createNote ( req ) {
2019-11-16 11:09:52 +01:00
const params = Object . assign ( { } , req . body ) ; // clone
params . parentNoteId = req . params . parentNoteId ;
2017-10-14 23:31:44 -04:00
2019-11-16 12:28:47 +01:00
const { target , targetBranchId } = req . query ;
2017-10-14 23:31:44 -04:00
2020-06-20 12:31:38 +02:00
const { note , branch } = noteService . createNewNoteWithTarget ( target , targetBranchId , params ) ;
2017-10-14 23:31:44 -04:00
2018-03-30 12:57:22 -04:00
return {
2018-04-01 11:42:12 -04:00
note ,
branch
2018-03-30 12:57:22 -04:00
} ;
}
2017-10-14 23:31:44 -04:00
2023-01-24 09:19:49 +01:00
function updateNoteData ( req ) {
2023-09-08 21:53:57 +02:00
const { content , attachments } = req . body ;
2022-06-13 22:38:59 +02:00
const { noteId } = req . params ;
2017-11-05 10:41:54 -05:00
2023-09-08 21:53:57 +02:00
return noteService . updateNoteData ( noteId , content , attachments ) ;
2018-03-30 12:57:22 -04:00
}
2017-10-14 23:31:44 -04:00
2020-06-20 12:31:38 +02:00
function deleteNote ( req ) {
2018-11-14 23:30:28 +01:00
const noteId = req . params . noteId ;
2019-10-19 00:11:07 +02:00
const taskId = req . query . taskId ;
2021-09-16 14:38:09 +02:00
const eraseNotes = req . query . eraseNotes === 'true' ;
2019-10-19 00:11:07 +02:00
const last = req . query . last === 'true' ;
2018-11-14 23:30:28 +01:00
2020-01-03 10:48:36 +01:00
// note how deleteId is separate from taskId - single taskId produces separate deleteId for each "top level" deleted note
const deleteId = utils . randomString ( 10 ) ;
2021-05-02 11:23:58 +02:00
const note = becca . getNote ( noteId ) ;
2018-11-14 23:30:28 +01:00
2023-05-09 00:05:27 +02:00
const taskContext = TaskContext . getInstance ( taskId , 'deleteNotes' ) ;
2019-10-18 22:27:38 +02:00
2022-04-19 23:06:46 +02:00
note . deleteNote ( deleteId , taskContext ) ;
2019-10-19 00:11:07 +02:00
2021-09-16 14:38:09 +02:00
if ( eraseNotes ) {
2023-07-27 23:57:12 +02:00
eraseService . eraseNotesWithDeleteId ( deleteId ) ;
2021-09-16 14:38:09 +02:00
}
2019-10-19 00:11:07 +02:00
if ( last ) {
2020-06-20 12:31:38 +02:00
taskContext . taskSucceeded ( ) ;
2019-10-19 00:11:07 +02:00
}
2018-11-14 23:30:28 +01:00
}
2020-06-20 12:31:38 +02:00
function undeleteNote ( req ) {
2021-04-24 11:39:44 +02:00
const taskContext = TaskContext . getInstance ( utils . randomString ( 10 ) , 'undeleteNotes' ) ;
2020-01-03 13:14:43 +01:00
2021-05-09 11:12:53 +02:00
noteService . undeleteNote ( req . params . noteId , taskContext ) ;
2020-01-03 13:14:43 +01:00
2020-06-20 12:31:38 +02:00
taskContext . taskSucceeded ( ) ;
2020-01-03 13:14:43 +01:00
}
2021-02-28 23:40:15 +01:00
function sortChildNotes ( req ) {
2018-01-13 17:00:40 -05:00
const noteId = req . params . noteId ;
2023-03-30 11:06:10 +08:00
const { sortBy , sortDirection , foldersFirst , sortNatural , sortLocale } = req . body ;
2018-01-13 17:00:40 -05:00
2023-03-30 11:06:10 +08:00
log . info ( ` Sorting ' ${ noteId } ' children with ${ sortBy } ${ sortDirection } , foldersFirst= ${ foldersFirst } , sortNatural= ${ sortNatural } , sortLocale= ${ sortLocale } ` ) ;
2021-02-28 23:40:15 +01:00
const reverse = sortDirection === 'desc' ;
2023-03-30 11:06:10 +08:00
treeService . sortNotes ( noteId , sortBy , reverse , foldersFirst , sortNatural , sortLocale ) ;
2018-03-30 12:57:22 -04:00
}
2018-01-13 17:00:40 -05:00
2020-06-20 12:31:38 +02:00
function protectNote ( req ) {
2018-01-13 20:53:00 -05:00
const noteId = req . params . noteId ;
2021-04-25 22:02:32 +02:00
const note = becca . notes [ noteId ] ;
2018-03-31 10:51:37 -04:00
const protect = ! ! parseInt ( req . params . isProtected ) ;
2020-02-26 16:37:17 +01:00
const includingSubTree = ! ! parseInt ( req . query . subtree ) ;
2018-01-13 17:00:40 -05:00
2021-04-24 11:39:44 +02:00
const taskContext = new TaskContext ( utils . randomString ( 10 ) , 'protectNotes' , { protect } ) ;
2019-10-19 09:58:18 +02:00
2020-06-20 12:31:38 +02:00
noteService . protectNoteRecursively ( note , protect , includingSubTree , taskContext ) ;
2019-10-19 09:58:18 +02:00
taskContext . taskSucceeded ( ) ;
2018-03-30 12:57:22 -04:00
}
2018-01-13 17:00:40 -05:00
2020-06-20 12:31:38 +02:00
function setNoteTypeMime ( req ) {
2018-04-04 23:04:31 -04:00
// can't use [] destructuring because req.params is not iterable
2021-12-08 22:36:09 +01:00
const { noteId } = req . params ;
const { type , mime } = req . body ;
2018-01-20 21:56:03 -05:00
2021-05-02 11:23:58 +02:00
const note = becca . getNote ( noteId ) ;
2018-04-01 17:38:24 -04:00
note . type = type ;
note . mime = mime ;
2020-06-20 12:31:38 +02:00
note . save ( ) ;
2018-03-30 12:57:22 -04:00
}
2018-01-20 21:56:03 -05:00
2020-06-20 12:31:38 +02:00
function changeTitle ( req ) {
2018-10-30 22:18:20 +01:00
const noteId = req . params . noteId ;
const title = req . body . title ;
2023-05-08 00:02:08 +02:00
const note = becca . getNoteOrThrow ( noteId ) ;
2018-10-30 22:18:20 +01:00
2021-05-17 22:35:36 +02:00
if ( ! note . isContentAvailable ( ) ) {
2022-12-09 16:04:13 +01:00
throw new ValidationError ( ` Note ' ${ noteId } ' is not available for change ` ) ;
2018-10-30 22:18:20 +01:00
}
2020-06-23 22:03:01 +02:00
const noteTitleChanged = note . title !== title ;
2021-12-08 21:04:22 +01:00
if ( noteTitleChanged ) {
2023-06-04 23:01:40 +02:00
noteService . saveRevisionIfNeeded ( note ) ;
2021-12-08 21:04:22 +01:00
}
2018-10-30 22:18:20 +01:00
note . title = title ;
2020-06-20 12:31:38 +02:00
note . save ( ) ;
2020-01-19 20:18:02 +01:00
2020-06-23 22:03:01 +02:00
if ( noteTitleChanged ) {
2020-06-24 22:29:53 +02:00
noteService . triggerNoteTitleChanged ( note ) ;
2020-06-23 22:03:01 +02:00
}
2020-01-19 20:18:02 +01:00
return note ;
2018-10-30 22:18:20 +01:00
}
2020-11-19 14:06:32 +01:00
function duplicateSubtree ( req ) {
2019-10-19 12:36:16 +02:00
const { noteId , parentNoteId } = req . params ;
2020-11-19 14:06:32 +01:00
return noteService . duplicateSubtree ( noteId , parentNoteId ) ;
2019-10-19 12:36:16 +02:00
}
2020-12-06 22:11:49 +01:00
function eraseDeletedNotesNow ( ) {
2023-07-27 23:57:12 +02:00
eraseService . eraseDeletedNotesNow ( ) ;
2020-12-06 22:11:49 +01:00
}
2023-04-24 21:22:34 +02:00
function eraseUnusedAttachmentsNow ( ) {
2023-07-27 23:57:12 +02:00
eraseService . eraseUnusedAttachmentsNow ( ) ;
2023-04-24 21:22:34 +02:00
}
2021-03-14 22:54:39 +01:00
function getDeleteNotesPreview ( req ) {
2021-03-18 23:42:30 +01:00
const { branchIdsToDelete , deleteAllClones } = req . body ;
2021-03-14 22:54:39 +01:00
const noteIdsToBeDeleted = new Set ( ) ;
2022-12-24 13:15:19 +01:00
const strongBranchCountToDelete = { } ; // noteId => count (integer)
2021-03-14 22:54:39 +01:00
function branchPreviewDeletion ( branch ) {
2022-12-24 13:15:19 +01:00
if ( branch . isWeak ) {
return ;
}
strongBranchCountToDelete [ branch . branchId ] = strongBranchCountToDelete [ branch . branchId ] || 0 ;
strongBranchCountToDelete [ branch . branchId ] ++ ;
2021-03-14 22:54:39 +01:00
const note = branch . getNote ( ) ;
2022-12-24 13:15:19 +01:00
if ( deleteAllClones || note . getStrongParentBranches ( ) . length <= strongBranchCountToDelete [ branch . branchId ] ) {
2021-03-14 22:54:39 +01:00
noteIdsToBeDeleted . add ( note . noteId ) ;
for ( const childBranch of note . getChildBranches ( ) ) {
branchPreviewDeletion ( childBranch ) ;
}
}
}
for ( const branchId of branchIdsToDelete ) {
2021-05-02 11:23:58 +02:00
const branch = becca . getBranch ( branchId ) ;
2021-03-14 22:54:39 +01:00
if ( ! branch ) {
log . error ( ` Branch ${ branchId } was not found and delete preview can't be calculated for this note. ` ) ;
continue ;
}
branchPreviewDeletion ( branch ) ;
}
let brokenRelations = [ ] ;
2021-03-18 23:23:35 +01:00
if ( noteIdsToBeDeleted . size > 0 ) {
2021-03-14 22:54:39 +01:00
sql . fillParamList ( noteIdsToBeDeleted ) ;
2023-04-14 16:49:06 +02:00
// FIXME: No need to do this in database, can be done with becca data
2021-03-14 22:54:39 +01:00
brokenRelations = sql . getRows ( `
SELECT attr . noteId , attr . name , attr . value
FROM attributes attr
JOIN param _list ON param _list . paramId = attr . value
WHERE attr . isDeleted = 0
AND attr . type = 'relation' ` ).filter(attr => !noteIdsToBeDeleted.has(attr.noteId));
}
return {
noteIdsToBeDeleted : Array . from ( noteIdsToBeDeleted ) ,
brokenRelations
} ;
}
2023-06-04 23:01:40 +02:00
function forceSaveRevision ( req ) {
2022-11-08 22:36:15 +01:00
const { noteId } = req . params ;
2023-05-08 00:02:08 +02:00
const note = becca . getNoteOrThrow ( noteId ) ;
2022-11-08 22:36:15 +01:00
if ( ! note . isContentAvailable ( ) ) {
2022-12-09 16:04:13 +01:00
throw new ValidationError ( ` Note revision of a protected note cannot be created outside of a protected session. ` ) ;
2022-11-08 22:36:15 +01:00
}
2023-06-04 23:01:40 +02:00
note . saveRevision ( ) ;
2022-11-08 22:36:15 +01:00
}
2023-05-02 22:46:39 +02:00
function convertNoteToAttachment ( req ) {
const { noteId } = req . params ;
2023-05-08 00:02:08 +02:00
const note = becca . getNoteOrThrow ( noteId ) ;
2023-05-02 22:46:39 +02:00
return {
2023-07-14 18:24:15 +02:00
attachment : note . convertToParentAttachment ( )
2023-05-02 22:46:39 +02:00
} ;
}
2018-03-30 12:57:22 -04:00
module . exports = {
getNote ,
2023-05-05 16:37:39 +02:00
getNoteBlob ,
2023-05-05 22:21:51 +02:00
getNoteMetadata ,
2023-01-24 09:19:49 +01:00
updateNoteData ,
2018-11-14 23:30:28 +01:00
deleteNote ,
2020-01-03 13:14:43 +01:00
undeleteNote ,
2018-03-30 12:57:22 -04:00
createNote ,
2021-02-28 23:40:15 +01:00
sortChildNotes ,
2020-02-26 16:37:17 +01:00
protectNote ,
2018-10-21 10:26:14 +02:00
setNoteTypeMime ,
2019-10-19 12:36:16 +02:00
changeTitle ,
2020-12-06 22:11:49 +01:00
duplicateSubtree ,
2021-03-14 22:54:39 +01:00
eraseDeletedNotesNow ,
2023-04-24 21:22:34 +02:00
eraseUnusedAttachmentsNow ,
2021-04-24 11:39:44 +02:00
getDeleteNotesPreview ,
2023-06-04 23:01:40 +02:00
forceSaveRevision ,
2023-05-02 22:46:39 +02:00
convertNoteToAttachment
2020-06-20 12:31:38 +02:00
} ;