2017-10-21 21:10:33 -04:00
"use strict" ;
2018-04-01 21:27:46 -04:00
const noteService = require ( '../../services/notes' ) ;
const treeService = require ( '../../services/tree' ) ;
2021-03-14 22:54:39 +01:00
const sql = require ( '../../services/sql' ) ;
2019-10-18 22:27:38 +02:00
const utils = require ( '../../services/utils' ) ;
2021-02-28 23:40:15 +01:00
const log = require ( '../../services/log' ) ;
2019-10-18 22:27:38 +02:00
const TaskContext = require ( '../../services/task_context' ) ;
2021-04-24 11:39:44 +02:00
const fs = require ( 'fs' ) ;
2021-06-29 22:15:57 +02:00
const becca = require ( "../../becca/becca" ) ;
2022-12-09 16:13:22 +01:00
const ValidationError = require ( "../../errors/validation_error" ) ;
const NotFoundError = require ( "../../errors/not_found_error" ) ;
2023-05-05 16:37:39 +02:00
const blobService = require ( "../../services/blob" ) ;
2017-10-14 23:31:44 -04:00
2020-06-20 12:31:38 +02:00
function getNote ( req ) {
2023-05-05 16:37:39 +02:00
const note = becca . getNote ( req . params . noteId ) ;
2018-03-30 12:57:22 -04:00
if ( ! note ) {
2023-05-05 16:37:39 +02:00
throw new NotFoundError ( ` Note ' ${ req . params . noteId } ' has not been found. ` ) ;
2017-11-26 23:10:23 -05:00
}
2021-06-03 21:47:25 +02:00
const pojo = note . getPojo ( ) ;
2023-05-05 16:37:39 +02:00
if ( note . hasStringContent ( ) ) {
2021-06-03 21:47:25 +02:00
pojo . content = note . getContent ( ) ;
2019-02-06 20:19:25 +01:00
2023-05-05 16:37:39 +02:00
// FIXME: use blobs instead
2021-06-03 21:47:25 +02:00
if ( note . type === 'file' && pojo . content . length > 10000 ) {
2022-12-21 15:19:05 +01:00
pojo . content = ` ${ pojo . content . substr ( 0 , 10000 ) } \r \n \r \n ... and ${ pojo . content . length - 10000 } more characters. ` ;
2019-02-07 22:16:40 +01:00
}
2018-02-18 21:28:24 -05:00
}
2020-08-16 22:57:48 +02:00
const contentMetadata = note . getContentMetadata ( ) ;
2021-06-03 21:47:25 +02:00
pojo . contentLength = contentMetadata . contentLength ;
2020-08-18 22:20:47 +02:00
2021-06-03 21:47:25 +02:00
pojo . combinedUtcDateModified = note . utcDateModified > contentMetadata . utcDateModified ? note . utcDateModified : contentMetadata . utcDateModified ;
pojo . combinedDateModified = note . utcDateModified > contentMetadata . utcDateModified ? note . dateModified : contentMetadata . dateModified ;
2020-08-16 22:57:48 +02:00
2021-06-03 21:47:25 +02:00
return pojo ;
2018-03-30 12:57:22 -04:00
}
2017-10-14 23:31:44 -04:00
2023-05-05 16:37:39 +02:00
function getNoteBlob ( req ) {
const full = req . query . full === 'true' ;
return blobService . getBlobPojo ( 'notes' , req . params . noteId , { full } ) ;
}
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-03-16 11:03:28 +01: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-03-16 11:03:28 +01: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
2019-10-19 00:11:07 +02:00
const taskContext = TaskContext . getInstance ( taskId , 'delete-notes' ) ;
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 ) {
noteService . eraseNotesWithDeleteId ( deleteId ) ;
}
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 ;
2021-05-02 11:23:58 +02:00
const note = becca . getNote ( noteId ) ;
2018-10-30 22:18:20 +01:00
if ( ! note ) {
2022-12-09 16:04:13 +01:00
throw new NotFoundError ( ` Note ' ${ noteId } ' has not been found ` ) ;
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 ) {
2022-06-02 17:25:58 +02:00
noteService . saveNoteRevisionIfNeeded ( 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 ( ) {
noteService . eraseDeletedNotesNow ( ) ;
}
2023-04-24 21:22:34 +02:00
function eraseUnusedAttachmentsNow ( ) {
noteService . eraseUnusedAttachmentsNow ( ) ;
}
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
} ;
}
2022-11-08 22:36:15 +01:00
function forceSaveNoteRevision ( req ) {
const { noteId } = req . params ;
const note = becca . getNote ( noteId ) ;
if ( ! note ) {
2022-12-09 16:04:13 +01:00
throw new NotFoundError ( ` Note ' ${ noteId } ' not found. ` ) ;
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
}
note . saveNoteRevision ( ) ;
}
2023-05-02 22:46:39 +02:00
function convertNoteToAttachment ( req ) {
const { noteId } = req . params ;
const note = becca . getNote ( noteId ) ;
if ( ! note ) {
throw new NotFoundError ( ` Note ' ${ noteId } ' not found. ` ) ;
}
return {
attachment : note . convertToParentAttachment ( { force : true } )
} ;
}
2018-03-30 12:57:22 -04:00
module . exports = {
getNote ,
2023-05-05 16:37:39 +02:00
getNoteBlob ,
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-05-02 22:46:39 +02:00
forceSaveNoteRevision ,
convertNoteToAttachment
2020-06-20 12:31:38 +02:00
} ;