diff --git a/bin/www b/bin/www index 55cec0b7a..1fd5041c7 100755 --- a/bin/www +++ b/bin/www @@ -5,7 +5,6 @@ process.on('unhandledRejection', error => { console.log(error); // but also try to log it into file - // we're using .info() instead of .error() because simple-node-logger emits weird error for error() require('../services/log').info(error); }); diff --git a/migrations/0012__create_index_on_notes_history.sql b/migrations/0012__create_index_on_notes_history.sql new file mode 100644 index 000000000..235884a79 --- /dev/null +++ b/migrations/0012__create_index_on_notes_history.sql @@ -0,0 +1,5 @@ +CREATE UNIQUE INDEX `IDX_notes_history_note_from_to` ON `notes_history` ( + `note_id`, + `date_modified_from`, + `date_modified_to` +); \ No newline at end of file diff --git a/migrations/0013__last_sync_pulled_pushed.sql b/migrations/0013__last_sync_pulled_pushed.sql new file mode 100644 index 000000000..060e076df --- /dev/null +++ b/migrations/0013__last_sync_pulled_pushed.sql @@ -0,0 +1,3 @@ +UPDATE options SET opt_name = 'last_synced_pull' WHERE opt_name = 'last_synced'; + +INSERT INTO options (opt_name, opt_value) VALUES ('last_synced_push', 0); \ No newline at end of file diff --git a/routes/api/migration.js b/routes/api/migration.js index dc497fab9..058b6ba64 100644 --- a/routes/api/migration.js +++ b/routes/api/migration.js @@ -6,14 +6,14 @@ const auth = require('../../services/auth'); const sql = require('../../services/sql'); const migration = require('../../services/migration'); -router.get('', auth.checkApiAuth, async (req, res, next) => { +router.get('', auth.checkApiAuthWithoutMigration, async (req, res, next) => { res.send({ 'db_version': parseInt(await sql.getOption('db_version')), 'app_db_version': migration.APP_DB_VERSION }); }); -router.post('', auth.checkApiAuth, async (req, res, next) => { +router.post('', auth.checkApiAuthWithoutMigration, async (req, res, next) => { const migrations = await migration.migrate(); res.send({ diff --git a/routes/migration.js b/routes/migration.js index 60acbc708..00bfbf7a2 100644 --- a/routes/migration.js +++ b/routes/migration.js @@ -4,7 +4,7 @@ const express = require('express'); const router = express.Router(); const auth = require('../services/auth'); -router.get('', auth.checkAuth, (req, res, next) => { +router.get('', auth.checkAuthWithoutMigration, (req, res, next) => { res.render('migration', {}); }); diff --git a/services/auth.js b/services/auth.js index a52c7e108..3b07009f2 100644 --- a/services/auth.js +++ b/services/auth.js @@ -15,6 +15,15 @@ async function checkAuth(req, res, next) { } } +async function checkAuthWithoutMigration(req, res, next) { + if (!req.session.loggedIn) { + res.redirect("login"); + } + else { + next(); + } +} + async function checkApiAuth(req, res, next) { if (!req.session.loggedIn && req.header("auth") !== "sync") { res.sendStatus(401); @@ -28,7 +37,18 @@ async function checkApiAuth(req, res, next) { } } +async function checkApiAuthWithoutMigration(req, res, next) { + if (!req.session.loggedIn && req.header("auth") !== "sync") { + res.sendStatus(401); + } + else { + next(); + } +} + module.exports = { checkAuth, - checkApiAuth + checkAuthWithoutMigration, + checkApiAuth, + checkApiAuthWithoutMigration }; \ No newline at end of file diff --git a/services/log.js b/services/log.js index 31dbb4cec..755bb4325 100644 --- a/services/log.js +++ b/services/log.js @@ -19,7 +19,8 @@ function info(message) { } function error(message) { - logger.error(message); + // we're using .info() instead of .error() because simple-node-logger emits weird error for error() + logger.info(message); } const requestBlacklist = [ "/api/audit", "/libraries", "/javascripts", "/images", "/stylesheets" ]; diff --git a/services/migration.js b/services/migration.js index 519f31b4b..7b3564a50 100644 --- a/services/migration.js +++ b/services/migration.js @@ -3,7 +3,7 @@ const sql = require('./sql'); const fs = require('fs-extra'); const log = require('./log'); -const APP_DB_VERSION = 11; +const APP_DB_VERSION = 13; const MIGRATIONS_DIR = "./migrations"; async function migrate() { diff --git a/services/sync.js b/services/sync.js index 5f6af12d2..edf901f23 100644 --- a/services/sync.js +++ b/services/sync.js @@ -10,78 +10,92 @@ const SYNC_SERVER = 'http://localhost:3000'; let syncInProgress = false; -async function sync() { - try { - syncInProgress = true; +async function pullSync() { + const lastSynced = parseInt(await sql.getOption('last_synced_pull')); + const resp = await rp({ + uri: SYNC_SERVER + '/api/sync/changed/' + lastSynced, + headers: { + auth: 'sync' + }, + json: true + }); + + try { + await sql.beginTransaction(); + + for (const treeItem of resp.tree) { + delete treeItem['id']; + + await sql.insert("notes_tree", treeItem, true); + + log.info("Syncing notes_tree " + treeItem.note_id); + } + + for (const audit of resp.audit_log) { + delete audit['id']; + + await sql.insert("audit_log", audit, true); + + log.info("Syncing audit_log for noteId=" + audit.note_id); + } + + for (const noteId of resp.notes) { + const note = await rp({ + uri: SYNC_SERVER + "/api/sync/note/" + noteId + "/" + lastSynced, + headers: { + auth: 'sync' + }, + json: true + }); + + console.log(noteId); + + await sql.insert("notes", note.detail, true); + + await sql.remove("images", noteId); + + for (const image of note.images) { + await sql.insert("images", image); + } + + for (const history of note.history) { + delete history['id']; + + await sql.insert("notes_history", history); + } + } + + await sql.setOption('last_synced_pull', syncTimestamp); + + await sql.commit(); + } + catch (e) { + await sql.rollback(); + + throw e; + } +} + +async function pushSync() { + +} + +async function sync() { + if (syncInProgress) { + return; + } + + syncInProgress = true; + + try { if (!await migration.isDbUpToDate()) { return; } - const lastSynced = parseInt(await sql.getOption('last_synced')); + await pushSync(); - const resp = await rp({ - uri: SYNC_SERVER + '/api/sync/changed/' + lastSynced, - headers: { - auth: 'sync' - }, - json: true - }); - - try { - await sql.beginTransaction(); - - for (const treeItem of resp.tree) { - delete treeItem['id']; - - await sql.insert("notes_tree", treeItem, true); - - log.info("Syncing notes_tree " + treeItem.note_id); - } - - for (const audit of resp.audit_log) { - delete audit['id']; - - await sql.insert("audit_log", audit, true); - - log.info("Syncing audit_log for noteId=" + audit.note_id); - } - - for (const noteId of resp.notes) { - const note = await rp({ - uri: SYNC_SERVER + "/api/sync/note/" + noteId + "/" + lastSynced, - headers: { - auth: 'sync' - }, - json: true - }); - - console.log(noteId); - - await sql.insert("notes", note.detail, true); - - await sql.remove("images", noteId); - - for (const image of note.images) { - await sql.insert("images", image); - } - - for (const history of note.history) { - delete history['id']; - - await sql.insert("notes_history", history); - } - } - - await sql.setOption('last_synced', syncTimestamp); - - await sql.commit(); - } - catch (e) { - await sql.rollback(); - - throw e; - } + await pullSync(); } catch (e) { log.error("sync failed: " + e.stack); @@ -93,4 +107,5 @@ async function sync() { setInterval(sync, 60000); +// kickoff initial sync immediately setTimeout(sync, 1000); \ No newline at end of file