From 021f02bd8c0ede45ac63657f0763aab1c6677646 Mon Sep 17 00:00:00 2001 From: azivner Date: Sun, 10 Dec 2017 12:56:59 -0500 Subject: [PATCH] converted all timestamps to string representation --- migrations/0050__string_dates.sql | 156 ++++++++++++++++++++++++++++++ public/javascripts/note_editor.js | 2 +- routes/api/import.js | 8 +- routes/api/login.js | 1 - routes/api/notes.js | 3 +- routes/api/notes_move.js | 34 +++---- routes/api/recent_notes.js | 4 +- routes/api/tree.js | 2 +- schema.sql | 30 +++--- services/app_info.js | 2 +- services/auth.js | 5 +- services/backup.js | 10 +- services/event_log.js | 2 +- services/migration.js | 11 +-- services/notes.js | 44 +++++---- services/options.js | 4 +- services/ping_job.js | 4 +- services/source_id.js | 2 +- services/sql.js | 44 +++++++-- services/sync.js | 4 +- services/sync_table.js | 2 +- services/utils.js | 26 +++++ 22 files changed, 304 insertions(+), 96 deletions(-) create mode 100644 migrations/0050__string_dates.sql diff --git a/migrations/0050__string_dates.sql b/migrations/0050__string_dates.sql new file mode 100644 index 000000000..0e214b1ae --- /dev/null +++ b/migrations/0050__string_dates.sql @@ -0,0 +1,156 @@ +DROP TABLE migrations; + +-- Sync +CREATE TABLE `sync_mig` ( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `entity_name` TEXT NOT NULL, + `entity_id` TEXT NOT NULL, + `source_id` TEXT NOT NULL, + `sync_date` TEXT NOT NULL); + +INSERT INTO sync_mig (id, entity_name, entity_id, source_id, sync_date) + SELECT id, entity_name, entity_id, source_id, datetime(sync_date, 'unixepoch') || '.000' FROM sync; + +DROP TABLE sync; +ALTER TABLE sync_mig RENAME TO sync; + +CREATE UNIQUE INDEX `IDX_sync_entity_name_id` ON `sync` ( + `entity_name`, + `entity_id` +); + +CREATE INDEX `IDX_sync_sync_date` ON `sync` ( + `sync_date` +); + +-- Options + +UPDATE options SET opt_value = datetime(opt_value, 'unixepoch') || '.000' WHERE opt_name IN ('last_backup_date'); +UPDATE options SET date_modified = datetime(date_modified, 'unixepoch') || '.000'; + +-- Event log + +CREATE TABLE `event_log_mig` ( + `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + `note_id` TEXT, + `comment` TEXT, + `date_added` TEXT NOT NULL +); + +INSERT INTO event_log_mig (id, note_id, comment, date_added) + SELECT id, note_id, comment, datetime(date_added, 'unixepoch') || '.000' FROM event_log; + +DROP TABLE event_log; +ALTER TABLE event_log_mig RENAME TO event_log; + +CREATE INDEX `IDX_event_log_date_added` ON `event_log` ( + `date_added` +); + +-- Notes + +CREATE TABLE IF NOT EXISTS "notes_mig" ( + `note_id` TEXT NOT NULL, + `note_title` TEXT, + `note_text` TEXT, + `is_protected` INT NOT NULL DEFAULT 0, + `is_deleted` INT NOT NULL DEFAULT 0, + `date_created` TEXT NOT NULL, + `date_modified` TEXT NOT NULL, + PRIMARY KEY(`note_id`) +); + +INSERT INTO notes_mig (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) + SELECT note_id, note_title, note_text, is_protected, is_deleted, + datetime(date_created, 'unixepoch') || '.000', + datetime(date_modified, 'unixepoch') || '.000' + FROM notes; + +DROP TABLE notes; +ALTER TABLE notes_mig RENAME TO notes; + +CREATE INDEX `IDX_notes_is_deleted` ON `notes` ( + `is_deleted` +); + +-- note history + +CREATE TABLE IF NOT EXISTS "notes_history_mig" ( + `note_history_id` TEXT NOT NULL PRIMARY KEY, + `note_id` TEXT NOT NULL, + `note_title` TEXT, + `note_text` TEXT, + `is_protected` INT NOT NULL DEFAULT 0, + `date_modified_from` TEXT NOT NULL, + `date_modified_to` TEXT NOT NULL +); + +INSERT INTO notes_history_mig (note_history_id, note_id, note_title, note_text, is_protected, date_modified_from, date_modified_to) + SELECT note_history_id, note_id, note_title, note_text, is_protected, + datetime(date_modified_from, 'unixepoch') || '.000', + datetime(date_modified_to, 'unixepoch') || '.000' + FROM notes_history; + +DROP TABLE notes_history; +ALTER TABLE notes_history_mig RENAME TO notes_history; + +CREATE INDEX `IDX_notes_history_note_id` ON `notes_history` ( + `note_id` +); +CREATE INDEX `IDX_notes_history_note_date_modified_from` ON `notes_history` ( + `date_modified_from` +); +CREATE INDEX `IDX_notes_history_note_date_modified_to` ON `notes_history` ( + `date_modified_to` +); + +-- Source IDs + +DROP TABLE source_ids; + +CREATE TABLE `source_ids` ( + `source_id` TEXT NOT NULL, + `date_created` TEXT NOT NULL, + PRIMARY KEY(`source_id`) +); + +-- Recent notes + +DROP TABLE recent_notes; + +CREATE TABLE `recent_notes` ( + 'note_tree_id'TEXT NOT NULL PRIMARY KEY, + `note_path` TEXT NOT NULL, + `date_accessed` TEXT NOT NULL, + is_deleted INT +); + +-- Notes tree + +CREATE TABLE IF NOT EXISTS "notes_tree_mig" ( + `note_tree_id` TEXT NOT NULL, + `note_id` TEXT NOT NULL, + `note_pid` TEXT NOT NULL, + `note_pos` INTEGER NOT NULL, + `prefix` TEXT, + `is_expanded` BOOLEAN, + `is_deleted` INTEGER NOT NULL DEFAULT 0, + `date_modified` TEXT NOT NULL, + PRIMARY KEY(`note_tree_id`) +); + +INSERT INTO notes_tree_mig (note_tree_id, note_id, note_pid, note_pos, prefix, is_expanded, is_deleted, date_modified) + SELECT note_tree_id, note_id, note_pid, note_pos, prefix, is_expanded, is_deleted, + datetime(date_modified, 'unixepoch') || '.000' + FROM notes_tree; + +DROP TABLE notes_tree; +ALTER TABLE notes_tree_mig RENAME TO notes_tree; + +CREATE INDEX `IDX_notes_tree_note_tree_id` ON `notes_tree` ( + `note_tree_id` +); +CREATE INDEX `IDX_notes_tree_note_id_note_pid` ON `notes_tree` ( + `note_id`, + `note_pid` +); diff --git a/public/javascripts/note_editor.js b/public/javascripts/note_editor.js index e086715e8..4151102dd 100644 --- a/public/javascripts/note_editor.js +++ b/public/javascripts/note_editor.js @@ -100,7 +100,7 @@ const noteEditor = (function() { } async function loadNoteToEditor(noteId) { - currentNote = await server.get('notes/' + noteId); + currentNote = await loadNote(noteId); if (isNewNoteCreated) { isNewNoteCreated = false; diff --git a/routes/api/import.js b/routes/api/import.js index f9e251a6f..0b8fe969e 100644 --- a/routes/api/import.js +++ b/routes/api/import.js @@ -67,6 +67,8 @@ async function importNotes(dir, parentNoteId) { const noteId = utils.newNoteId(); const noteTreeId = utils.newNoteHistoryId(); + const now = utils.nowDate(); + await sql.insert('notes_tree', { note_tree_id: noteTreeId, note_id: noteId, @@ -74,7 +76,7 @@ async function importNotes(dir, parentNoteId) { note_pos: notePos, is_expanded: 0, is_deleted: 0, - date_modified: utils.nowTimestamp() + date_modified: now }); await sync_table.addNoteTreeSync(noteTreeId); @@ -85,8 +87,8 @@ async function importNotes(dir, parentNoteId) { note_text: noteText, is_deleted: 0, is_protected: 0, - date_created: utils.nowTimestamp(), - date_modified: utils.nowTimestamp() + date_created: now, + date_modified: now }); await sync_table.addNoteSync(noteId); diff --git a/routes/api/login.js b/routes/api/login.js index e09063e57..39565f3f9 100644 --- a/routes/api/login.js +++ b/routes/api/login.js @@ -4,7 +4,6 @@ const express = require('express'); const router = express.Router(); const options = require('../../services/options'); const utils = require('../../services/utils'); -const migration = require('../../services/migration'); const source_id = require('../../services/source_id'); const auth = require('../../services/auth'); const password_encryption = require('../../services/password_encryption'); diff --git a/routes/api/notes.js b/routes/api/notes.js index 44d96371b..e87813571 100644 --- a/routes/api/notes.js +++ b/routes/api/notes.js @@ -30,8 +30,7 @@ router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { } res.send({ - detail: detail, - loadTime: utils.nowTimestamp() + detail: detail }); }); diff --git a/routes/api/notes_move.js b/routes/api/notes_move.js index 7d1d105a7..e431e34a1 100644 --- a/routes/api/notes_move.js +++ b/routes/api/notes_move.js @@ -14,7 +14,7 @@ router.put('/:noteTreeId/move-to/:parentNoteId', auth.checkApiAuth, async (req, const maxNotePos = await sql.getSingleValue('SELECT MAX(note_pos) FROM notes_tree WHERE note_pid = ? AND is_deleted = 0', [parentNoteId]); const newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; - const now = utils.nowTimestamp(); + const now = utils.nowDate(); await sql.doInTransaction(async () => { await sql.execute("UPDATE notes_tree SET note_pid = ?, note_pos = ?, date_modified = ? WHERE note_tree_id = ?", @@ -40,7 +40,7 @@ router.put('/:noteTreeId/move-before/:beforeNoteTreeId', async (req, res, next) await sync_table.addNoteReorderingSync(beforeNote.note_pid); - const now = utils.nowTimestamp(); + const now = utils.nowDate(); await sql.execute("UPDATE notes_tree SET note_pid = ?, note_pos = ?, date_modified = ? WHERE note_tree_id = ?", [beforeNote.note_pid, beforeNote.note_pos, now, noteTreeId]); @@ -70,7 +70,7 @@ router.put('/:noteTreeId/move-after/:afterNoteTreeId', async (req, res, next) => await sync_table.addNoteReorderingSync(afterNote.note_pid); await sql.execute("UPDATE notes_tree SET note_pid = ?, note_pos = ?, date_modified = ? WHERE note_tree_id = ?", - [afterNote.note_pid, afterNote.note_pos + 1, utils.nowTimestamp(), noteTreeId]); + [afterNote.note_pid, afterNote.note_pos + 1, utils.nowDate(), noteTreeId]); await sync_table.addNoteTreeSync(noteTreeId); }); @@ -107,13 +107,13 @@ router.put('/:childNoteId/clone-to/:parentNoteId', auth.checkApiAuth, async (req await sql.doInTransaction(async () => { const noteTree = { - 'note_tree_id': utils.newNoteTreeId(), - 'note_id': childNoteId, - 'note_pid': parentNoteId, - 'note_pos': newNotePos, - 'is_expanded': 0, - 'date_modified': utils.nowTimestamp(), - 'is_deleted': 0 + note_tree_id: utils.newNoteTreeId(), + note_id: childNoteId, + note_pid: parentNoteId, + note_pos: newNotePos, + is_expanded: 0, + date_modified: utils.nowDate(), + is_deleted: 0 }; await sql.replace("notes_tree", noteTree); @@ -160,13 +160,13 @@ router.put('/:noteId/clone-after/:afterNoteTreeId', async (req, res, next) => { await sync_table.addNoteReorderingSync(afterNote.note_pid); const noteTree = { - 'note_tree_id': utils.newNoteTreeId(), - 'note_id': noteId, - 'note_pid': afterNote.note_pid, - 'note_pos': afterNote.note_pos + 1, - 'is_expanded': 0, - 'date_modified': utils.nowTimestamp(), - 'is_deleted': 0 + note_tree_id: utils.newNoteTreeId(), + note_id: noteId, + note_pid: afterNote.note_pid, + note_pos: afterNote.note_pos + 1, + is_expanded: 0, + date_modified: utils.nowDate(), + is_deleted: 0 }; await sql.replace("notes_tree", noteTree); diff --git a/routes/api/recent_notes.js b/routes/api/recent_notes.js index eda3cbac7..07f7acdda 100644 --- a/routes/api/recent_notes.js +++ b/routes/api/recent_notes.js @@ -20,7 +20,7 @@ router.put('/:noteTreeId/:notePath', auth.checkApiAuth, async (req, res, next) = await sql.replace('recent_notes', { note_tree_id: noteTreeId, note_path: notePath, - date_accessed: utils.nowTimestamp(), + date_accessed: utils.nowDate(), is_deleted: 0 }); @@ -39,7 +39,7 @@ async function getRecentNotes() { } async function deleteOld() { - const cutoffDateAccessed = utils.nowTimestamp() - 24 * 60 * 60; + const cutoffDateAccessed = utils.dateStr(new Date(Date.now() - 24 * 60 * 60 * 1000)); await sql.doInTransaction(async () => { await sql.execute("DELETE FROM recent_notes WHERE date_accessed < ?", [cutoffDateAccessed]); diff --git a/routes/api/tree.js b/routes/api/tree.js index 6cdab2ee9..1b3a53a8a 100644 --- a/routes/api/tree.js +++ b/routes/api/tree.js @@ -52,7 +52,7 @@ router.put('/:noteTreeId/set-prefix', auth.checkApiAuth, async (req, res, next) const prefix = utils.isEmptyOrWhitespace(req.body.prefix) ? null : req.body.prefix; await sql.doInTransaction(async () => { - await sql.execute("UPDATE notes_tree SET prefix = ?, date_modified = ? WHERE note_tree_id = ?", [prefix, utils.nowTimestamp(), noteTreeId]); + await sql.execute("UPDATE notes_tree SET prefix = ?, date_modified = ? WHERE note_tree_id = ?", [prefix, utils.nowDate(), noteTreeId]); await sync_table.addNoteTreeSync(noteTreeId); }); diff --git a/schema.sql b/schema.sql index 3dbe8b647..374fa0fff 100644 --- a/schema.sql +++ b/schema.sql @@ -68,15 +68,23 @@ CREATE TABLE `source_ids` ( `date_created` INTEGER NOT NULL, PRIMARY KEY(`source_id`) ); +CREATE TABLE `recent_notes` ( + 'note_tree_id'TEXT NOT NULL PRIMARY KEY, + `note_path` TEXT NOT NULL, + `date_accessed` INTEGER NOT NULL , + is_deleted INT +); CREATE TABLE IF NOT EXISTS "notes_tree" ( - [note_tree_id] VARCHAR(30) PRIMARY KEY NOT NULL, - [note_id] VARCHAR(30) NOT NULL, - [note_pid] VARCHAR(30) NOT NULL, - [note_pos] INTEGER NOT NULL, - [is_expanded] BOOLEAN NULL , - date_modified INTEGER NOT NULL DEFAULT 0, - is_deleted INTEGER NOT NULL DEFAULT 0 -, `prefix` TEXT); + `note_tree_id` VARCHAR ( 30 ) NOT NULL, + `note_id` VARCHAR ( 30 ) NOT NULL, + `note_pid` VARCHAR ( 30 ) NOT NULL, + `note_pos` INTEGER NOT NULL, + `is_expanded` BOOLEAN, + `date_modified` TEXT NOT NULL DEFAULT 0, + `is_deleted` INTEGER NOT NULL DEFAULT 0, + `prefix` TEXT, + PRIMARY KEY(`note_tree_id`) +); CREATE INDEX `IDX_notes_tree_note_tree_id` ON `notes_tree` ( `note_tree_id` ); @@ -84,9 +92,3 @@ CREATE INDEX `IDX_notes_tree_note_id_note_pid` ON `notes_tree` ( `note_id`, `note_pid` ); -CREATE TABLE `recent_notes` ( - 'note_tree_id'TEXT NOT NULL PRIMARY KEY, - `note_path` TEXT NOT NULL, - `date_accessed` INTEGER NOT NULL , - is_deleted INT -); diff --git a/services/app_info.js b/services/app_info.js index 88194af3c..0876a135e 100644 --- a/services/app_info.js +++ b/services/app_info.js @@ -3,7 +3,7 @@ const build = require('./build'); const packageJson = require('../package'); -const APP_DB_VERSION = 49; +const APP_DB_VERSION = 50; module.exports = { app_version: packageJson.version, diff --git a/services/auth.js b/services/auth.js index ca5d0a9c7..1531a5395 100644 --- a/services/auth.js +++ b/services/auth.js @@ -1,6 +1,7 @@ "use strict"; const migration = require('./migration'); +const sql = require('./sql'); const utils = require('./utils'); const options = require('./options'); @@ -13,7 +14,7 @@ async function checkAuth(req, res, next) { else if (!req.session.loggedIn && !utils.isElectron()) { res.redirect("login"); } - else if (!await migration.isDbUpToDate()) { + else if (!await sql.isDbUpToDate()) { res.redirect("migration"); } else { @@ -34,7 +35,7 @@ async function checkApiAuth(req, res, next) { if (!req.session.loggedIn) { res.status(401).send("Not authorized"); } - else if (await migration.isDbUpToDate()) { + else if (await sql.isDbUpToDate()) { next(); } else { diff --git a/services/backup.js b/services/backup.js index 9e355fc9e..3408ed617 100644 --- a/services/backup.js +++ b/services/backup.js @@ -8,10 +8,12 @@ const log = require('./log'); const sql = require('./sql'); async function regularBackup() { - const now = utils.nowTimestamp(); - const last_backup_date = parseInt(await options.getOption('last_backup_date')); + const now = new Date(); + const lastBackupDate = utils.parseDate(await options.getOption('last_backup_date')); - if (now - last_backup_date > 43200) { + console.log(lastBackupDate); + + if (now.getTime() - lastBackupDate.getTime() > 43200 * 1000) { await backupNow(); } @@ -19,7 +21,7 @@ async function regularBackup() { } async function backupNow() { - const now = utils.nowTimestamp(); + const now = utils.nowDate(); const date_str = new Date().toISOString().substr(0, 19).replace(/:/g, ''); diff --git a/services/event_log.js b/services/event_log.js index 881b352af..49d115cc9 100644 --- a/services/event_log.js +++ b/services/event_log.js @@ -10,7 +10,7 @@ async function addNoteEvent(noteId, comment) { await sql.insert('event_log', { note_id : noteId, comment: comment, - date_added: utils.nowTimestamp() + date_added: utils.nowDate() }); log.info("Event log for " + noteId + ": " + comment); diff --git a/services/migration.js b/services/migration.js index f331c2341..c663e9703 100644 --- a/services/migration.js +++ b/services/migration.js @@ -70,6 +70,8 @@ async function migrate() { await options.setOption("db_version", mig.dbVersion); }); + sql.setDbReadyAsResolved(); + log.info("Migration to version " + mig.dbVersion + " has been successful."); mig['success'] = true; @@ -87,13 +89,6 @@ async function migrate() { return migrations; } -async function isDbUpToDate() { - const dbVersion = parseInt(await options.getOption('db_version')); - - return dbVersion >= app_info.db_version; -} - module.exports = { - migrate, - isDbUpToDate + migrate }; \ No newline at end of file diff --git a/services/notes.js b/services/notes.js index 7cbf41d8b..6bd94bbe6 100644 --- a/services/notes.js +++ b/services/notes.js @@ -23,7 +23,7 @@ async function createNewNote(parentNoteId, note) { newNotePos = afterNote.note_pos + 1; 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]); + [utils.nowDate(), parentNoteId, afterNote.note_pos]); await sync_table.addNoteReorderingSync(parentNoteId); } @@ -31,28 +31,27 @@ async function createNewNote(parentNoteId, note) { throw new Error('Unknown target: ' + note.target); } - - const now = utils.nowTimestamp(); + const now = utils.nowDate(); await sql.insert("notes", { - 'note_id': noteId, - 'note_title': note.note_title, - 'note_text': '', - 'date_created': now, - 'date_modified': now, - 'is_protected': note.is_protected + note_id: noteId, + note_title: note.note_title, + note_text: '', + date_created: now, + date_modified: now, + is_protected: note.is_protected }); await sync_table.addNoteSync(noteId); await sql.insert("notes_tree", { - 'note_tree_id': noteTreeId, - 'note_id': noteId, - 'note_pid': parentNoteId, - 'note_pos': newNotePos, - 'is_expanded': 0, - 'date_modified': now, - 'is_deleted': 0 + note_tree_id: noteTreeId, + note_id: noteId, + note_pid: parentNoteId, + note_pos: newNotePos, + is_expanded: 0, + date_modified: now, + is_deleted: 0 }); await sync_table.addNoteTreeSync(noteTreeId); @@ -142,16 +141,19 @@ async function updateNote(noteId, newNote, ctx) { await encryptNote(newNote, ctx); } - const now = utils.nowTimestamp(); + const now = new Date(); const historySnapshotTimeInterval = parseInt(await options.getOption('history_snapshot_time_interval')); - const historyCutoff = now - historySnapshotTimeInterval; + const historyCutoff = utils.dateStr(new Date(now.getTime() - historySnapshotTimeInterval * 1000)); - const existingNoteHistoryId = await sql.getSingleValue("SELECT note_history_id FROM notes_history WHERE note_id = ? AND date_modified_to >= ?", [noteId, historyCutoff]); + const existingNoteHistoryId = await sql.getSingleValue( + "SELECT note_history_id FROM notes_history WHERE note_id = ? AND date_modified_to >= ?", [noteId, historyCutoff]); await sql.doInTransaction(async () => { - if (!existingNoteHistoryId && (now - newNote.detail.date_created) >= historySnapshotTimeInterval) { + const msSinceDateCreated = now.getTime() - utils.parseDate(newNote.detail.date_created).getTime(); + + if (!existingNoteHistoryId && msSinceDateCreated >= historySnapshotTimeInterval * 1000) { const oldNote = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteId]); if (oldNote.is_protected) { @@ -188,7 +190,7 @@ async function updateNote(noteId, newNote, ctx) { } async function deleteNote(noteTreeId) { - const now = utils.nowTimestamp(); + const now = utils.nowDate(); await sql.execute("UPDATE notes_tree SET is_deleted = 1, date_modified = ? WHERE note_tree_id = ?", [now, noteTreeId]); await sync_table.addNoteTreeSync(noteTreeId); diff --git a/services/options.js b/services/options.js index 129a9e991..2e08f400d 100644 --- a/services/options.js +++ b/services/options.js @@ -24,7 +24,7 @@ async function setOption(optName, optValue) { await sql.replace("options", { opt_name: optName, opt_value: optValue, - date_modified: utils.nowTimestamp() + date_modified: utils.nowDate() }); } @@ -42,7 +42,7 @@ async function initOptions(startNotePath) { await setOption('start_note_path', startNotePath); await setOption('protected_session_timeout', 600); await setOption('history_snapshot_time_interval', 600); - await setOption('last_backup_date', utils.nowTimestamp()); + await setOption('last_backup_date', utils.nowDate()); await setOption('db_version', app_info.db_version); await setOption('last_synced_pull', app_info.db_version); diff --git a/services/ping_job.js b/services/ping_job.js index 24445d0d1..7e8c1b3b8 100644 --- a/services/ping_job.js +++ b/services/ping_job.js @@ -5,12 +5,12 @@ const messaging = require('./messaging'); const options = require('./options'); const sync = require('./sync'); -let startTime = utils.nowTimestamp(); +let startTime = utils.nowDate(); let sentSyncId = []; async function sendPing() { const syncs = await sql.getResults("SELECT * FROM sync WHERE sync_date >= ? AND source_id != ?", [startTime, source_id.currentSourceId]); - startTime = utils.nowTimestamp(); + startTime = utils.nowDate(); const data = {}; const syncIds = []; diff --git a/services/source_id.js b/services/source_id.js index f5ba89d77..fd6c01503 100644 --- a/services/source_id.js +++ b/services/source_id.js @@ -13,7 +13,7 @@ sql.dbReady.then(async () => { await sql.doInTransaction(async () => { await sql.insert("source_ids", { source_id: currentSourceId, - date_created: utils.nowTimestamp() + date_created: utils.nowDate() }); }); diff --git a/services/sql.js b/services/sql.js index 8c232a3b7..2a788f0ae 100644 --- a/services/sql.js +++ b/services/sql.js @@ -5,6 +5,7 @@ const dataDir = require('./data_dir'); const fs = require('fs'); const sqlite = require('sqlite'); const utils = require('./utils'); +const app_info = require('./app_info'); async function createConnection() { return await sqlite.open(dataDir.DOCUMENT_PATH, {Promise}); @@ -15,7 +16,11 @@ const dbConnected = createConnection(); let dbReadyResolve = null; const dbReady = new Promise((resolve, reject) => { dbConnected.then(async db => { - dbReadyResolve = () => resolve(db); + dbReadyResolve = () => { + log.info("DB ready."); + + resolve(db); + }; const tableResults = await getResults("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'"); if (tableResults.length !== 1) { @@ -27,6 +32,7 @@ const dbReady = new Promise((resolve, reject) => { await executeScript(schema); const noteId = utils.newNoteId(); + const now = utils.nowDate(); await insert('notes_tree', { note_tree_id: utils.newNoteTreeId(), @@ -34,7 +40,7 @@ const dbReady = new Promise((resolve, reject) => { note_pid: 'root', note_pos: 1, is_deleted: 0, - date_modified: utils.nowTimestamp() + date_modified: now }); await insert('notes', { @@ -43,8 +49,8 @@ const dbReady = new Promise((resolve, reject) => { note_text: 'Text', is_protected: 0, is_deleted: 0, - date_created: utils.nowTimestamp(), - date_modified: utils.nowTimestamp() + date_created: now, + date_modified: now }); await require('./options').initOptions(noteId); @@ -56,9 +62,17 @@ const dbReady = new Promise((resolve, reject) => { else { const username = await getSingleValue("SELECT opt_value FROM options WHERE opt_name = 'username'"); - if (username) { - resolve(db); + if (!username) { + log.info("Login/password not initialized. DB not ready."); + + return; } + + if (!await isDbUpToDate()) { + return; + } + + resolve(db); } }) .catch(e => { @@ -202,9 +216,8 @@ async function doInTransaction(func) { await rollback(); transactionActive = false; - resolve(); - throw e; + reject(e); } }); @@ -213,6 +226,18 @@ async function doInTransaction(func) { } } +async function isDbUpToDate() { + const dbVersion = parseInt(await getSingleValue("SELECT opt_value FROM options WHERE opt_name = 'db_version'")); + + const upToDate = dbVersion >= app_info.db_version; + + if (!upToDate) { + log.info("App db version is " + app_info.db_version + ", while db version is " + dbVersion + ". Migration needed."); + } + + return upToDate; +} + module.exports = { dbReady, insert, @@ -226,5 +251,6 @@ module.exports = { execute, executeScript, doInTransaction, - setDbReadyAsResolved + setDbReadyAsResolved, + isDbUpToDate }; \ No newline at end of file diff --git a/services/sync.js b/services/sync.js index 91d350eb3..e7e5719e5 100644 --- a/services/sync.js +++ b/services/sync.js @@ -37,9 +37,7 @@ async function sync() { syncInProgress = true; try { - if (!await migration.isDbUpToDate()) { - log.info("DB not up to date"); - + if (!await sql.isDbUpToDate()) { return { success: false, message: "DB not up to date" diff --git a/services/sync_table.js b/services/sync_table.js index e34b2d63c..65348cf1f 100644 --- a/services/sync_table.js +++ b/services/sync_table.js @@ -30,7 +30,7 @@ async function addEntitySync(entityName, entityId, sourceId) { await sql.replace("sync", { entity_name: entityName, entity_id: entityId, - sync_date: utils.nowTimestamp(), + sync_date: utils.nowDate(), source_id: sourceId || source_id.currentSourceId }); } diff --git a/services/utils.js b/services/utils.js index 82e1eec04..bb6bcd0dc 100644 --- a/services/utils.js +++ b/services/utils.js @@ -27,6 +27,29 @@ function nowTimestamp() { return Math.floor(Date.now() / 1000); } +function nowDate() { + return dateStr(new Date()); +} + +function dateStr(date) { + return date.toISOString().replace("T", " ").replace("Z", ""); +} + +/** + * @param str - needs to be in the "YYYY-MM-DD HH:MM:SS.sss" format as outputted by dateStr(). + * also is assumed to be GMT time, *not* local time + */ +function parseDate(str) { + try { + const isoDate = str.replace(" ", "T") + "Z"; + + return new Date(Date.parse(isoDate)); + } + catch (e) { + throw new Error("Can't parse date from " + str + ": " + e.stack); + } +} + function toBase64(plainText) { return Buffer.from(plainText).toString('base64'); } @@ -68,6 +91,9 @@ module.exports = { randomSecureToken, randomString, nowTimestamp, + nowDate, + dateStr, + parseDate, newNoteId, newNoteTreeId, newNoteHistoryId,