diff --git a/node/app.js b/node/app.js index 04b65daad..a5af9b01f 100644 --- a/node/app.js +++ b/node/app.js @@ -14,14 +14,15 @@ const logoutRoute = require('./routes/logout'); const migrationRoute = require('./routes/migration'); // API routes -const treeRoute = require('./routes/api/tree'); -const notesRoute = require('./routes/api/notes'); -const notesMoveRoute = require('./routes/api/notes_move'); -const auditRoute = require('./routes/api/audit'); -const noteHistoryRoute = require('./routes/api/note_history'); -const recentChangesRoute = require('./routes/api/recent_changes'); -const settingsRoute = require('./routes/api/settings'); -const passwordRoute = require('./routes/api/password'); +const treeApiRoute = require('./routes/api/tree'); +const notesApiRoute = require('./routes/api/notes'); +const notesMoveApiRoute = require('./routes/api/notes_move'); +const auditApiRoute = require('./routes/api/audit'); +const noteHistoryApiRoute = require('./routes/api/note_history'); +const recentChangesApiRoute = require('./routes/api/recent_changes'); +const settingsApiRoute = require('./routes/api/settings'); +const passwordApiRoute = require('./routes/api/password'); +const migrationApiRoute = require('./routes/api/migration'); const db = require('sqlite'); @@ -63,14 +64,15 @@ app.use('/login', loginRoute); app.use('/logout', logoutRoute); app.use('/migration', migrationRoute); -app.use('/api/tree', treeRoute); -app.use('/api/notes', notesRoute); -app.use('/api/notes', notesMoveRoute); -app.use('/api/audit', auditRoute); -app.use('/api/notes-history', noteHistoryRoute); -app.use('/api/recent-changes', recentChangesRoute); -app.use('/api/settings', settingsRoute); -app.use('/api/password', passwordRoute); +app.use('/api/tree', treeApiRoute); +app.use('/api/notes', notesApiRoute); +app.use('/api/notes', notesMoveApiRoute); +app.use('/api/audit', auditApiRoute); +app.use('/api/notes-history', noteHistoryApiRoute); +app.use('/api/recent-changes', recentChangesApiRoute); +app.use('/api/settings', settingsApiRoute); +app.use('/api/password', passwordApiRoute); +app.use('/api/migration', migrationApiRoute); // catch 404 and forward to error handler app.use(function (req, res, next) { diff --git a/node/package.json b/node/package.json index 5947455a9..344ed3d55 100644 --- a/node/package.json +++ b/node/package.json @@ -20,6 +20,7 @@ "scrypt": "^6.0.3", "serve-favicon": "~2.4.5", "session-file-store": "^1.1.2", + // https://github.com/kriasoft/node-sqlite "sqlite": "^2.8.0" } } diff --git a/node/routes/api/migration.js b/node/routes/api/migration.js new file mode 100644 index 000000000..8f9401b77 --- /dev/null +++ b/node/routes/api/migration.js @@ -0,0 +1,72 @@ +const express = require('express'); +const router = express.Router(); +const auth = require('../../auth'); +const backup = require('../../backup'); +const sql = require('../../sql'); +const fs = require('fs-extra'); + +const APP_DB_VERSION = 0; +const MIGRATIONS_DIR = "migrations"; + +router.get('', auth.checkApiAuth, async (req, res, next) => { + res.send({ + 'db_version': parseInt(await sql.getOption('db_version')), + 'app_db_version': APP_DB_VERSION + }); +}); + +router.post('', auth.checkApiAuth, async (req, res, next) => { + const migrations = []; + + await backup.backupNow(); + + const currentDbVersion = parseInt(await sql.getOption('db_version')); + + fs.readdirSync(MIGRATIONS_DIR).forEach(file => { + const match = file.match(/([0-9]{4})__([a-zA-Z0-9_ ]+)\.sql/); + + if (match) { + const dbVersion = parseInt(match.group(1)); + + if (dbVersion > currentDbVersion) { + const name = match.group(2); + + const migrationRecord = { + 'db_version': dbVersion, + 'name': name, + 'file': file + }; + + migrations.push(migrationRecord); + } + } + }); + + migrations.sort((a, b) => a.db_version - b.db_version); + + for (const mig of migrations) { + const migrationSql = fs.readFileSync(MIGRATIONS_DIR + "/" + mig.file); + + try { + await sql.beginTransaction(); + + await sql.executeScript(migrationSql); + + await sql.commit(); + + mig['success'] = true; + } + catch (e) { + mig['success'] = false; + mig['error'] = e.stack; + + break; + } + } + + res.send({ + 'migrations': migrations + }); +}); + +module.exports = router; \ No newline at end of file diff --git a/node/sql.js b/node/sql.js index 3ce353e6e..e61f72e7d 100644 --- a/node/sql.js +++ b/node/sql.js @@ -40,6 +40,10 @@ async function execute(query, params = []) { return await db.run(query, ...params); } +async function executeScript(query) { + return await db.exec(query); +} + async function remove(tableName, noteId) { return await execute("DELETE FROM " + tableName + " WHERE note_id = ?", [noteId]); } @@ -67,6 +71,7 @@ module.exports = { getSingleResult, getResults, execute, + executeScript, getOption, setOption, beginTransaction,