2017-11-05 23:41:54 +08:00
const sql = require ( './sql' ) ;
const options = require ( './options' ) ;
const utils = require ( './utils' ) ;
const notes = require ( './notes' ) ;
2017-11-15 10:54:12 +08:00
const data _encryption = require ( './data_encryption' ) ;
2017-11-17 10:50:00 +08:00
const sync _table = require ( './sync_table' ) ;
2017-11-05 23:41:54 +08:00
2017-11-25 09:51:44 +08:00
async function createNewNote ( parentNoteId , note ) {
2017-11-05 23:41:54 +08:00
const noteId = utils . newNoteId ( ) ;
2017-11-19 21:47:22 +08:00
const noteTreeId = utils . newNoteTreeId ( ) ;
2017-11-05 23:41:54 +08:00
let newNotePos = 0 ;
2017-11-27 12:10:23 +08:00
await sql . doInTransaction ( async ( ) => {
if ( note . target === 'into' ) {
const maxNotePos = await sql . getSingleValue ( 'SELECT MAX(note_pos) FROM notes_tree WHERE note_pid = ? AND is_deleted = 0' , [ parentNoteId ] ) ;
2017-11-05 23:41:54 +08:00
2017-11-27 12:10:23 +08:00
newNotePos = maxNotePos === null ? 0 : maxNotePos + 1 ;
}
else if ( note . target === 'after' ) {
const afterNote = await sql . getSingleResult ( 'SELECT note_pos FROM notes_tree WHERE note_tree_id = ?' , [ note . target _note _tree _id ] ) ;
2017-11-05 23:41:54 +08:00
2017-11-27 12:10:23 +08:00
newNotePos = afterNote . note _pos + 1 ;
2017-11-05 23:41:54 +08:00
2017-11-27 12:10:23 +08:00
await sql . execute ( 'UPDATE notes_tree SET note_pos = note_pos + 1, date_modified = ? WHERE note_pid = ? AND note_pos > ? AND is_deleted = 0' ,
[ utils . nowTimestamp ( ) , parentNoteId , afterNote . note _pos ] ) ;
}
else {
throw new Error ( 'Unknown target: ' + note . target ) ;
}
2017-11-05 23:41:54 +08:00
2017-11-20 05:35:35 +08:00
await sync _table . addNoteTreeSync ( noteTreeId ) ;
2017-11-17 10:50:00 +08:00
await sync _table . addNoteSync ( noteId ) ;
2017-11-05 23:41:54 +08:00
const now = utils . nowTimestamp ( ) ;
await sql . insert ( "notes" , {
'note_id' : noteId ,
'note_title' : note . note _title ,
'note_text' : '' ,
'date_created' : now ,
'date_modified' : now ,
2017-11-15 10:54:12 +08:00
'is_protected' : note . is _protected
2017-11-05 23:41:54 +08:00
} ) ;
await sql . insert ( "notes_tree" , {
2017-11-19 06:05:50 +08:00
'note_tree_id' : noteTreeId ,
2017-11-05 23:41:54 +08:00
'note_id' : noteId ,
'note_pid' : parentNoteId ,
'note_pos' : newNotePos ,
'is_expanded' : 0 ,
2017-11-20 05:35:35 +08:00
'date_modified' : now ,
2017-11-05 23:41:54 +08:00
'is_deleted' : 0
} ) ;
} ) ;
2017-11-19 06:05:50 +08:00
return {
noteId ,
noteTreeId
} ;
2017-11-05 23:41:54 +08:00
}
2017-11-15 10:54:12 +08:00
async function encryptNote ( note , ctx ) {
2017-11-19 01:53:17 +08:00
note . detail . note _title = data _encryption . encrypt ( ctx . getDataKey ( ) , data _encryption . noteTitleIv ( note . detail . note _id ) , note . detail . note _title ) ;
note . detail . note _text = data _encryption . encrypt ( ctx . getDataKey ( ) , data _encryption . noteTextIv ( note . detail . note _id ) , note . detail . note _text ) ;
2017-11-15 10:54:12 +08:00
}
2017-11-05 23:41:54 +08:00
2017-11-15 13:04:26 +08:00
async function protectNoteRecursively ( noteId , dataKey , protect ) {
const note = await sql . getSingleResult ( "SELECT * FROM notes WHERE note_id = ?" , [ noteId ] ) ;
await protectNote ( note , dataKey , protect ) ;
const children = await sql . getFlattenedResults ( "note_id" , "SELECT note_id FROM notes_tree WHERE note_pid = ?" , [ noteId ] ) ;
for ( const childNoteId of children ) {
await protectNoteRecursively ( childNoteId , dataKey , protect ) ;
}
}
async function protectNote ( note , dataKey , protect ) {
let changed = false ;
if ( protect && ! note . is _protected ) {
2017-11-19 01:53:17 +08:00
note . note _title = data _encryption . encrypt ( dataKey , data _encryption . noteTitleIv ( note . note _id ) , note . note _title ) ;
note . note _text = data _encryption . encrypt ( dataKey , data _encryption . noteTextIv ( note . note _id ) , note . note _text ) ;
2017-11-15 13:04:26 +08:00
note . is _protected = true ;
changed = true ;
}
else if ( ! protect && note . is _protected ) {
2017-11-19 01:53:17 +08:00
note . note _title = data _encryption . decryptString ( dataKey , data _encryption . noteTitleIv ( note . note _id ) , note . note _title ) ;
note . note _text = data _encryption . decryptString ( dataKey , data _encryption . noteTextIv ( note . note _id ) , note . note _text ) ;
2017-11-15 13:04:26 +08:00
note . is _protected = false ;
changed = true ;
}
if ( changed ) {
console . log ( "Updating..." ) ;
await sql . execute ( "UPDATE notes SET note_title = ?, note_text = ?, is_protected = ? WHERE note_id = ?" ,
[ note . note _title , note . note _text , note . is _protected , note . note _id ] ) ;
2017-11-17 10:50:00 +08:00
await sync _table . addNoteSync ( note . note _id ) ;
2017-11-15 13:04:26 +08:00
}
await protectNoteHistory ( note . note _id , dataKey , protect ) ;
}
async function protectNoteHistory ( noteId , dataKey , protect ) {
const historyToChange = await sql . getResults ( "SELECT * FROM notes_history WHERE note_id = ? AND is_protected != ?" , [ noteId , protect ] ) ;
for ( const history of historyToChange ) {
if ( protect ) {
2017-11-19 01:53:17 +08:00
history . note _title = data _encryption . encrypt ( dataKey , data _encryption . noteTitleIv ( history . note _history _id ) , history . note _title ) ;
history . note _text = data _encryption . encrypt ( dataKey , data _encryption . noteTextIv ( history . note _history _id ) , history . note _text ) ;
2017-11-15 13:04:26 +08:00
history . is _protected = true ;
}
else {
2017-11-19 01:53:17 +08:00
history . note _title = data _encryption . decryptString ( dataKey , data _encryption . noteTitleIv ( history . note _history _id ) , history . note _title ) ;
history . note _text = data _encryption . decryptString ( dataKey , data _encryption . noteTextIv ( history . note _history _id ) , history . note _text ) ;
2017-11-15 13:04:26 +08:00
history . is _protected = false ;
}
await sql . execute ( "UPDATE notes_history SET note_title = ?, note_text = ?, is_protected = ? WHERE note_history_id = ?" ,
[ history . note _title , history . note _text , history . is _protected , history . note _history _id ] ) ;
2017-11-17 10:50:00 +08:00
await sync _table . addNoteHistorySync ( history . note _history _id ) ;
2017-11-15 13:04:26 +08:00
}
}
2017-11-15 10:54:12 +08:00
async function updateNote ( noteId , newNote , ctx ) {
2017-11-16 13:22:00 +08:00
let noteTitleForHistory = newNote . detail . note _title ;
let noteTextForHistory = newNote . detail . note _text ;
2017-11-15 10:54:12 +08:00
if ( newNote . detail . is _protected ) {
await encryptNote ( newNote , ctx ) ;
2017-11-05 23:41:54 +08:00
}
2017-11-21 12:51:28 +08:00
const origNoteDetail = await sql . getSingleResult ( "SELECT * FROM notes WHERE note_id = ?" , [ noteId ] ) ;
2017-11-05 23:41:54 +08:00
const now = utils . nowTimestamp ( ) ;
const historySnapshotTimeInterval = parseInt ( await options . getOption ( 'history_snapshot_time_interval' ) ) ;
const historyCutoff = now - historySnapshotTimeInterval ;
2017-11-21 12:51:28 +08:00
const existingNoteHistoryId = await sql . getSingleValue ( "SELECT note_history_id FROM notes_history WHERE note_id = ? AND date_modified_from >= ?" , [ noteId , historyCutoff ] ) ;
2017-11-05 23:41:54 +08:00
await sql . doInTransaction ( async ( ) => {
2017-11-16 13:22:00 +08:00
if ( ! existingNoteHistoryId ) {
2017-11-19 21:47:22 +08:00
const newNoteHistoryId = utils . newNoteHistoryId ( ) ;
2017-11-05 23:41:54 +08:00
2017-11-21 12:51:28 +08:00
await sql . insert ( 'notes_history' , {
note _history _id : newNoteHistoryId ,
note _id : noteId ,
note _title : noteTitleForHistory ,
note _text : noteTextForHistory ,
is _protected : false , // we don't care about encryption - this will be handled in protectNoteHistory()
date _modified _from : now ,
date _modified _to : now
} ) ;
2017-11-16 13:22:00 +08:00
2017-11-17 10:50:00 +08:00
await sync _table . addNoteHistorySync ( newNoteHistoryId ) ;
2017-11-05 23:41:54 +08:00
}
2017-11-18 07:56:52 +08:00
await protectNoteHistory ( noteId , ctx . getDataKeyOrNull ( ) , newNote . detail . is _protected ) ;
2017-11-15 11:21:56 +08:00
2017-11-21 12:51:28 +08:00
await sql . execute ( "UPDATE notes SET note_title = ?, note_text = ?, is_protected = ?, date_modified = ? WHERE note_id = ?" , [
2017-11-05 23:41:54 +08:00
newNote . detail . note _title ,
newNote . detail . note _text ,
2017-11-15 10:54:12 +08:00
newNote . detail . is _protected ,
2017-11-05 23:41:54 +08:00
now ,
noteId ] ) ;
await sql . remove ( "images" , noteId ) ;
for ( const img of newNote . images ) {
img . image _data = atob ( img . image _data ) ;
await sql . insert ( "images" , img ) ;
}
await sql . remove ( "links" , noteId ) ;
for ( const link in newNote . links ) {
2017-11-21 08:43:48 +08:00
//await sql.insert("links", link);
2017-11-05 23:41:54 +08:00
}
2017-11-17 10:50:00 +08:00
await sync _table . addNoteSync ( noteId ) ;
2017-11-05 23:41:54 +08:00
} ) ;
}
2017-11-25 09:51:44 +08:00
async function deleteNote ( noteTreeId ) {
2017-11-05 23:41:54 +08:00
const now = utils . nowTimestamp ( ) ;
2017-11-21 12:51:28 +08:00
await sql . execute ( "UPDATE notes_tree SET is_deleted = 1, date_modified = ? WHERE note_tree_id = ?" , [ now , noteTreeId ] ) ;
2017-11-20 12:12:39 +08:00
await sync _table . addNoteTreeSync ( noteTreeId ) ;
2017-11-05 23:41:54 +08:00
2017-11-20 12:12:39 +08:00
const noteId = await sql . getSingleValue ( "SELECT note_id FROM notes_tree WHERE note_tree_id = ?" , [ noteTreeId ] ) ;
2017-11-05 23:41:54 +08:00
2017-11-24 12:54:54 +08:00
const notDeletedNoteTreesCount = await sql . getSingleValue ( "SELECT COUNT(*) FROM notes_tree WHERE note_id = ? AND is_deleted = 0" , [ noteId ] ) ;
2017-11-20 12:12:39 +08:00
if ( ! notDeletedNoteTreesCount ) {
2017-11-24 12:54:54 +08:00
await sql . execute ( "UPDATE notes SET is_deleted = 1, date_modified = ? WHERE note_id = ?" , [ now , noteId ] ) ;
await sync _table . addNoteSync ( noteId ) ;
2017-11-05 23:41:54 +08:00
2017-11-24 12:54:54 +08:00
const children = await sql . getResults ( "SELECT note_tree_id FROM notes_tree WHERE note_pid = ? AND is_deleted = 0" , [ noteId ] ) ;
2017-11-05 23:41:54 +08:00
2017-11-20 12:12:39 +08:00
for ( const child of children ) {
2017-11-25 09:51:44 +08:00
await deleteNote ( child . note _tree _id ) ;
2017-11-20 12:12:39 +08:00
}
}
2017-11-05 23:41:54 +08:00
}
module . exports = {
createNewNote ,
updateNote ,
2017-11-15 13:04:26 +08:00
deleteNote ,
protectNoteRecursively
2017-11-06 06:58:55 +08:00
} ;