2018-04-03 22:15:28 -04:00
"use strict" ;
2025-01-09 18:07:02 +02:00
import sql from "./sql.js" ;
import eventChangesService from "./entity_changes.js" ;
import treeService from "./tree.js" ;
import BBranch from "../becca/entities/bbranch.js" ;
import becca from "../becca/becca.js" ;
import log from "./log.js" ;
2024-07-18 22:41:58 +03:00
2024-07-18 22:58:12 +03:00
export interface CloneResponse {
2024-07-18 22:41:58 +03:00
success : boolean ;
message? : string ;
branchId? : string ;
notePath? : string ;
}
function cloneNoteToParentNote ( noteId : string , parentNoteId : string , prefix : string | null = null ) : CloneResponse {
2023-06-05 09:23:42 +02:00
if ( ! ( noteId in becca . notes ) || ! ( parentNoteId in becca . notes ) ) {
2025-01-09 18:07:02 +02:00
return { success : false , message : "Note cannot be cloned because either the cloned note or the intended parent is deleted." } ;
2023-06-05 09:23:42 +02:00
}
2022-06-16 20:02:40 +02:00
const parentNote = becca . getNote ( parentNoteId ) ;
2024-07-18 22:41:58 +03:00
if ( ! parentNote ) {
2025-01-09 18:07:02 +02:00
return { success : false , message : "Note cannot be cloned because the parent note could not be found." } ;
2024-07-18 22:41:58 +03:00
}
2022-06-16 20:02:40 +02:00
2025-01-09 18:07:02 +02:00
if ( parentNote . type === "search" ) {
2022-06-16 20:02:40 +02:00
return {
success : false ,
message : "Can't clone into a search note"
} ;
}
2021-12-27 23:39:46 +01:00
const validationResult = treeService . validateParentChild ( parentNoteId , noteId ) ;
2018-04-03 22:15:28 -04:00
if ( ! validationResult . success ) {
return validationResult ;
}
2023-01-03 13:52:37 +01:00
const branch = new BBranch ( {
2018-04-03 22:15:28 -04:00
noteId : noteId ,
2021-12-27 23:39:46 +01:00
parentNoteId : parentNoteId ,
2018-04-03 22:15:28 -04:00
prefix : prefix ,
2024-07-18 22:41:58 +03:00
isExpanded : false
2018-04-03 22:15:28 -04:00
} ) . save ( ) ;
2023-04-15 00:06:13 +02:00
log . info ( ` Cloned note ' ${ noteId } ' to a new parent note ' ${ parentNoteId } ' with prefix ' ${ prefix } ' ` ) ;
2022-02-05 12:06:23 +01:00
2021-06-06 11:01:10 +02:00
return {
success : true ,
branchId : branch.branchId ,
2023-04-16 11:28:24 +02:00
notePath : ` ${ parentNote . getBestNotePathString ( ) } / ${ noteId } `
2021-06-06 11:01:10 +02:00
} ;
2018-04-03 22:15:28 -04:00
}
2024-07-18 22:58:12 +03:00
function cloneNoteToBranch ( noteId : string , parentBranchId : string , prefix? : string ) {
2021-12-27 23:39:46 +01:00
const parentBranch = becca . getBranch ( parentBranchId ) ;
if ( ! parentBranch ) {
2023-05-04 22:16:18 +02:00
return { success : false , message : ` Parent branch ' ${ parentBranchId } ' does not exist. ` } ;
2021-12-27 23:39:46 +01:00
}
2023-04-15 00:06:13 +02:00
const ret = cloneNoteToParentNote ( noteId , parentBranch . noteId , prefix ) ;
2021-12-27 23:39:46 +01:00
2022-06-16 20:02:40 +02:00
parentBranch . isExpanded = true ; // the new target should be expanded, so it immediately shows up to the user
2021-12-27 23:39:46 +01:00
parentBranch . save ( ) ;
return ret ;
}
2024-04-05 20:47:07 +03:00
function ensureNoteIsPresentInParent ( noteId : string , parentNoteId : string , prefix? : string ) {
2023-06-29 23:32:19 +02:00
if ( ! ( noteId in becca . notes ) ) {
2023-05-01 12:41:22 -05:00
return { branch : null , success : false , message : ` Note ' ${ noteId } ' is deleted. ` } ;
2023-06-29 23:32:19 +02:00
} else if ( ! ( parentNoteId in becca . notes ) ) {
2023-05-01 12:41:22 -05:00
return { branch : null , success : false , message : ` Note ' ${ parentNoteId } ' is deleted. ` } ;
2019-01-17 23:24:59 +01:00
}
2022-06-16 20:02:40 +02:00
const parentNote = becca . getNote ( parentNoteId ) ;
2024-07-18 22:41:58 +03:00
if ( ! parentNote ) {
return { branch : null , success : false , message : "Can't find parent note." } ;
}
2025-01-09 18:07:02 +02:00
if ( parentNote . type === "search" ) {
2023-05-01 12:41:22 -05:00
return { branch : null , success : false , message : "Can't clone into a search note" } ;
2022-06-16 20:02:40 +02:00
}
2020-06-20 12:31:38 +02:00
const validationResult = treeService . validateParentChild ( parentNoteId , noteId ) ;
2018-08-13 10:59:31 +02:00
if ( ! validationResult . success ) {
return validationResult ;
}
2023-01-03 13:52:37 +01:00
const branch = new BBranch ( {
2018-08-13 10:59:31 +02:00
noteId : noteId ,
parentNoteId : parentNoteId ,
prefix : prefix ,
2024-07-18 22:41:58 +03:00
isExpanded : false
2018-08-13 10:59:31 +02:00
} ) . save ( ) ;
2022-02-05 12:06:23 +01:00
2022-12-27 21:17:40 +01:00
log . info ( ` Ensured note ' ${ noteId } ' is in parent note ' ${ parentNoteId } ' with prefix ' ${ branch . prefix } ' ` ) ;
2022-06-16 20:02:40 +02:00
2023-05-01 12:41:22 -05:00
return { branch : branch , success : true } ;
2018-08-11 19:45:55 +02:00
}
2024-02-18 13:16:54 +02:00
function ensureNoteIsAbsentFromParent ( noteId : string , parentNoteId : string ) {
2024-07-18 22:41:58 +03:00
const branchId = sql . getValue < string > ( ` SELECT branchId FROM branches WHERE noteId = ? AND parentNoteId = ? AND isDeleted = 0 ` , [ noteId , parentNoteId ] ) ;
2021-05-11 22:00:16 +02:00
const branch = becca . getBranch ( branchId ) ;
2018-08-11 19:45:55 +02:00
if ( branch ) {
2022-12-04 13:16:05 +01:00
if ( ! branch . isWeak && branch . getNote ( ) . getStrongParentBranches ( ) . length <= 1 ) {
return {
success : false ,
message : ` Cannot remove branch ' ${ branch . branchId } ' between child ' ${ noteId } ' and parent ' ${ parentNoteId } ' because this would delete the note as well. `
} ;
2022-01-31 22:09:39 +01:00
}
2022-04-19 23:06:46 +02:00
branch . deleteBranch ( ) ;
2022-02-05 12:06:23 +01:00
2022-12-04 13:16:05 +01:00
log . info ( ` Ensured note ' ${ noteId } ' is NOT in parent note ' ${ parentNoteId } ' ` ) ;
return { success : true } ;
2018-08-11 19:45:55 +02:00
}
}
2024-04-05 20:47:07 +03:00
function toggleNoteInParent ( present : boolean , noteId : string , parentNoteId : string , prefix? : string ) {
2018-08-13 13:53:08 +02:00
if ( present ) {
2022-12-04 13:16:05 +01:00
return ensureNoteIsPresentInParent ( noteId , parentNoteId , prefix ) ;
2025-01-09 18:07:02 +02:00
} else {
2022-12-04 13:16:05 +01:00
return ensureNoteIsAbsentFromParent ( noteId , parentNoteId ) ;
2018-08-13 13:53:08 +02:00
}
}
2024-02-18 13:16:54 +02:00
function cloneNoteAfter ( noteId : string , afterBranchId : string ) {
2025-01-09 18:07:02 +02:00
if ( [ "_hidden" , "root" ] . includes ( noteId ) ) {
2022-12-23 20:40:58 +01:00
return { success : false , message : ` Cloning the note ' ${ noteId } ' is forbidden. ` } ;
}
const afterBranch = becca . getBranch ( afterBranchId ) ;
if ( ! afterBranch ) {
return { success : false , message : ` Branch ' ${ afterBranchId } ' does not exist. ` } ;
}
2025-01-09 18:07:02 +02:00
if ( afterBranch . noteId === "_hidden" ) {
return { success : false , message : "Cannot clone after the hidden branch." } ;
2022-11-26 14:57:39 +01:00
}
2021-05-02 11:23:58 +02:00
const afterNote = becca . getBranch ( afterBranchId ) ;
2018-04-03 22:15:28 -04:00
2023-06-29 22:10:13 +02:00
if ( ! ( noteId in becca . notes ) ) {
return { success : false , message : ` Note to be cloned ' ${ noteId } ' is deleted or does not exist. ` } ;
2024-07-18 22:41:58 +03:00
} else if ( ! afterNote || ! ( afterNote . parentNoteId in becca . notes ) ) {
return { success : false , message : ` After note ' ${ afterNote ? . parentNoteId } ' is deleted or does not exist. ` } ;
2019-01-17 23:24:59 +01:00
}
2022-06-16 20:02:40 +02:00
const parentNote = becca . getNote ( afterNote . parentNoteId ) ;
2025-01-09 18:07:02 +02:00
if ( ! parentNote || parentNote . type === "search" ) {
2022-06-16 20:02:40 +02:00
return {
success : false ,
message : "Can't clone into a search note"
} ;
}
2020-06-20 12:31:38 +02:00
const validationResult = treeService . validateParentChild ( afterNote . parentNoteId , noteId ) ;
2018-04-03 22:15:28 -04:00
2019-10-26 21:14:06 +02:00
if ( ! validationResult . success ) {
2018-04-03 22:15:28 -04:00
return validationResult ;
}
2023-06-30 11:18:34 +02:00
// we don't change utcDateModified, so other changes are prioritized in case of conflict
2018-04-03 22:15:28 -04:00
// also we would have to sync all those modified branches otherwise hash checks would fail
2025-01-09 18:07:02 +02:00
sql . execute ( "UPDATE branches SET notePosition = notePosition + 10 WHERE parentNoteId = ? AND notePosition > ? AND isDeleted = 0" , [ afterNote . parentNoteId , afterNote . notePosition ] ) ;
2018-04-03 22:15:28 -04:00
2023-07-29 23:25:02 +02:00
eventChangesService . putNoteReorderingEntityChange ( afterNote . parentNoteId ) ;
2018-04-03 22:15:28 -04:00
2023-01-03 13:52:37 +01:00
const branch = new BBranch ( {
2018-04-03 22:15:28 -04:00
noteId : noteId ,
parentNoteId : afterNote.parentNoteId ,
2019-10-19 12:36:16 +02:00
notePosition : afterNote.notePosition + 10 ,
2024-07-18 22:41:58 +03:00
isExpanded : false
2018-04-03 22:15:28 -04:00
} ) . save ( ) ;
2022-12-27 10:22:50 +01:00
log . info ( ` Cloned note ' ${ noteId } ' into parent note ' ${ afterNote . parentNoteId } ' after note ' ${ afterNote . noteId } ', branch ' ${ afterBranchId } ' ` ) ;
2022-02-05 12:06:23 +01:00
2019-03-18 22:33:19 +01:00
return { success : true , branchId : branch.branchId } ;
2018-04-03 22:15:28 -04:00
}
2024-07-18 21:47:30 +03:00
export default {
2021-12-27 23:39:46 +01:00
cloneNoteToBranch ,
2023-04-15 00:06:13 +02:00
cloneNoteToParentNote ,
2018-08-11 19:45:55 +02:00
ensureNoteIsPresentInParent ,
ensureNoteIsAbsentFromParent ,
2018-08-13 13:53:08 +02:00
toggleNoteInParent ,
2018-04-03 22:15:28 -04:00
cloneNoteAfter
2020-05-31 22:33:02 +02:00
} ;