mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
db upgrades are now handled transparently in the background without bothering the user, closes #119
This commit is contained in:
parent
4c8eeb2e6f
commit
14c704d6db
@ -21,10 +21,7 @@ class Entity {
|
||||
contentToHash += "|" + this[propertyName];
|
||||
}
|
||||
|
||||
// this IF is to ease the migration from before hashed options, can be later removed
|
||||
if (this.constructor.tableName !== 'options' || this.isSynced) {
|
||||
this["hash"] = utils.hash(contentToHash).substr(0, 10);
|
||||
}
|
||||
this["hash"] = utils.hash(contentToHash).substr(0, 10);
|
||||
}
|
||||
|
||||
async save() {
|
||||
|
@ -1,46 +0,0 @@
|
||||
import server from './services/server.js';
|
||||
|
||||
$(document).ready(async () => {
|
||||
const {appDbVersion, dbVersion} = await server.get('migration');
|
||||
|
||||
console.log("HI", {appDbVersion, dbVersion});
|
||||
|
||||
if (appDbVersion === dbVersion) {
|
||||
$("#up-to-date").show();
|
||||
}
|
||||
else {
|
||||
$("#need-to-migrate").show();
|
||||
|
||||
$("#app-db-version").html(appDbVersion);
|
||||
$("#db-version").html(dbVersion);
|
||||
}
|
||||
});
|
||||
|
||||
$("#run-migration").click(async () => {
|
||||
$("#run-migration").prop("disabled", true);
|
||||
|
||||
$("#migration-result").show();
|
||||
|
||||
const result = await server.post('migration');
|
||||
|
||||
for (const migration of result.migrations) {
|
||||
const row = $('<tr>')
|
||||
.append($('<td>').html(migration.dbVersion))
|
||||
.append($('<td>').html(migration.name))
|
||||
.append($('<td>').html(migration.success ? 'Yes' : 'No'))
|
||||
.append($('<td>').html(migration.success ? 'N/A' : migration.error));
|
||||
|
||||
if (!migration.success) {
|
||||
row.addClass("danger");
|
||||
}
|
||||
|
||||
$("#migration-table").append(row);
|
||||
}
|
||||
});
|
||||
|
||||
// copy of this shortcut to be able to debug migration problems
|
||||
$(document).bind('keydown', 'ctrl+shift+i', () => {
|
||||
require('electron').remote.getCurrentWindow().toggleDevTools();
|
||||
|
||||
return false;
|
||||
});
|
@ -5,7 +5,7 @@ import infoService from "./info.js";
|
||||
function getHeaders() {
|
||||
let protectedSessionId = null;
|
||||
|
||||
try { // this is because protected session might not be declared in some cases - like when it's included in migration page
|
||||
try { // this is because protected session might not be declared in some cases
|
||||
protectedSessionId = protectedSessionHolder.getProtectedSessionId();
|
||||
}
|
||||
catch(e) {}
|
||||
|
@ -1,25 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const optionService = require('../../services/options');
|
||||
const migrationService = require('../../services/migration');
|
||||
const appInfo = require('../../services/app_info');
|
||||
|
||||
async function getMigrationInfo() {
|
||||
return {
|
||||
dbVersion: parseInt(await optionService.getOption('dbVersion')),
|
||||
appDbVersion: appInfo.dbVersion
|
||||
};
|
||||
}
|
||||
|
||||
async function executeMigration() {
|
||||
const migrations = await migrationService.migrate();
|
||||
|
||||
return {
|
||||
migrations: migrations
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getMigrationInfo,
|
||||
executeMigration
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
function migrationPage(req, res) {
|
||||
res.render('migration', {});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
migrationPage
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
const indexRoute = require('./index');
|
||||
const loginRoute = require('./login');
|
||||
const migrationRoute = require('./migration');
|
||||
const setupRoute = require('./setup');
|
||||
const multer = require('multer')();
|
||||
|
||||
@ -14,7 +13,6 @@ const noteRevisionsApiRoute = require('./api/note_revisions');
|
||||
const recentChangesApiRoute = require('./api/recent_changes');
|
||||
const optionsApiRoute = require('./api/options');
|
||||
const passwordApiRoute = require('./api/password');
|
||||
const migrationApiRoute = require('./api/migration');
|
||||
const syncApiRoute = require('./api/sync');
|
||||
const loginApiRoute = require('./api/login');
|
||||
const eventLogRoute = require('./api/event_log');
|
||||
@ -96,7 +94,6 @@ function register(app) {
|
||||
route(GET, '/login', [], loginRoute.loginPage);
|
||||
route(POST, '/login', [], loginRoute.login);
|
||||
route(POST, '/logout', [auth.checkAuth], loginRoute.logout);
|
||||
route(GET, '/migration', [auth.checkAuthForMigrationPage], migrationRoute.migrationPage);
|
||||
route(GET, '/setup', [auth.checkAppNotInitialized], setupRoute.setupPage);
|
||||
|
||||
apiRoute(GET, '/api/tree', treeApiRoute.getTree);
|
||||
@ -180,9 +177,6 @@ function register(app) {
|
||||
apiRoute(GET, '/api/search/:searchString', searchRoute.searchNotes);
|
||||
apiRoute(POST, '/api/search/:searchString', searchRoute.saveSearchToNote);
|
||||
|
||||
route(GET, '/api/migration', [auth.checkApiAuthForMigrationPage], migrationApiRoute.getMigrationInfo, apiResultHandler);
|
||||
route(POST, '/api/migration', [auth.checkApiAuthForMigrationPage], migrationApiRoute.executeMigration, apiResultHandler);
|
||||
|
||||
route(POST, '/api/login/sync', [], loginApiRoute.loginSync, apiResultHandler);
|
||||
// this is for entering protected mode so user has to be already logged-in (that's the reason we don't require username)
|
||||
apiRoute(POST, '/api/login/protected', loginApiRoute.loginToProtectedSession);
|
||||
|
@ -12,18 +12,6 @@ async function checkAuth(req, res, next) {
|
||||
else if (!req.session.loggedIn && !utils.isElectron()) {
|
||||
res.redirect("login");
|
||||
}
|
||||
else if (!await sqlInit.isDbUpToDate()) {
|
||||
res.redirect("migration");
|
||||
}
|
||||
else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAuthForMigrationPage(req, res, next) {
|
||||
if (!req.session.loggedIn && !utils.isElectron()) {
|
||||
res.redirect("login");
|
||||
}
|
||||
else {
|
||||
next();
|
||||
}
|
||||
@ -35,27 +23,12 @@ async function checkApiAuthOrElectron(req, res, next) {
|
||||
if (!req.session.loggedIn && !utils.isElectron()) {
|
||||
res.status(401).send("Not authorized");
|
||||
}
|
||||
else if (await sqlInit.isDbUpToDate()) {
|
||||
next();
|
||||
}
|
||||
else {
|
||||
res.status(409).send("Mismatched app versions"); // need better response than that
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
async function checkApiAuth(req, res, next) {
|
||||
if (!req.session.loggedIn) {
|
||||
res.status(401).send("Not authorized");
|
||||
}
|
||||
else if (await sqlInit.isDbUpToDate()) {
|
||||
next();
|
||||
}
|
||||
else {
|
||||
res.status(409).send("Mismatched app versions"); // need better response than that
|
||||
}
|
||||
}
|
||||
|
||||
async function checkApiAuthForMigrationPage(req, res, next) {
|
||||
if (!req.session.loggedIn) {
|
||||
res.status(401).send("Not authorized");
|
||||
}
|
||||
@ -79,19 +52,14 @@ async function checkSenderToken(req, res, next) {
|
||||
if (await sql.getValue("SELECT COUNT(*) FROM api_tokens WHERE isDeleted = 0 AND token = ?", [token]) === 0) {
|
||||
res.status(401).send("Not authorized");
|
||||
}
|
||||
else if (await sqlInit.isDbUpToDate()) {
|
||||
next();
|
||||
}
|
||||
else {
|
||||
res.status(409).send("Mismatched app versions"); // need better response than that
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkAuth,
|
||||
checkAuthForMigrationPage,
|
||||
checkApiAuth,
|
||||
checkApiAuthForMigrationPage,
|
||||
checkAppNotInitialized,
|
||||
checkApiAuthOrElectron,
|
||||
checkSenderToken
|
||||
|
@ -2,7 +2,6 @@ const repository = require('./repository');
|
||||
const utils = require('./utils');
|
||||
const dateUtils = require('./date_utils');
|
||||
const appInfo = require('./app_info');
|
||||
const Option = require('../entities/option');
|
||||
|
||||
async function getOption(name) {
|
||||
const option = await repository.getOption(name);
|
||||
@ -27,6 +26,9 @@ async function setOption(name, value) {
|
||||
}
|
||||
|
||||
async function createOption(name, value, isSynced) {
|
||||
// to avoid circular dependency, need to find better solution
|
||||
const Option = require('../entities/option');
|
||||
|
||||
await new Option({
|
||||
name: name,
|
||||
value: value,
|
||||
|
@ -42,7 +42,10 @@ const dbReady = new Promise((resolve, reject) => {
|
||||
}
|
||||
|
||||
if (!await isDbUpToDate()) {
|
||||
return;
|
||||
// avoiding circular dependency
|
||||
const migrationService = require('./migration');
|
||||
|
||||
await migrationService.migrate();
|
||||
}
|
||||
|
||||
resolve(db);
|
||||
|
@ -22,13 +22,6 @@ let syncServerCertificate = null;
|
||||
async function sync() {
|
||||
try {
|
||||
await syncMutexService.doExclusively(async () => {
|
||||
if (!await sqlInit.isDbUpToDate()) {
|
||||
return {
|
||||
success: false,
|
||||
message: "DB not up to date"
|
||||
};
|
||||
}
|
||||
|
||||
const syncContext = await login();
|
||||
|
||||
await pushSync(syncContext);
|
||||
|
@ -1,72 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Migration</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 800px; margin: auto;">
|
||||
<h1>Migration</h1>
|
||||
|
||||
<div id="up-to-date" style="display:none;">
|
||||
<p>Your database is up-to-date with the application.</p>
|
||||
|
||||
<a href="/" class="btn btn-success">Continue to app</a>
|
||||
</div>
|
||||
|
||||
<div id="need-to-migrate" style="display:none;">
|
||||
<p>Your database needs to be migrated to new version before you can use the application again.
|
||||
Database will be backed up before migration in case of something going wrong.</p>
|
||||
|
||||
<table class="table table-bordered" style="width: 200px;">
|
||||
<tr>
|
||||
<th>Application version:</th>
|
||||
<td id="app-db-version" style="text-align: right;"></td>
|
||||
<tr>
|
||||
<th>Database version:</th>
|
||||
<td id="db-version" style="text-align: right;"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<button class="btn btn-warning" id="run-migration">Run migration</button>
|
||||
</div>
|
||||
|
||||
<div id="migration-result" style="display:none;">
|
||||
<h2>Migration result</h2>
|
||||
|
||||
<table id="migration-table" class="table">
|
||||
<tr>
|
||||
<th>Database version</th>
|
||||
<th>Name</th>
|
||||
<th>Success</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<a href="/" class="btn btn-success">Continue to app</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
const baseApiUrl = 'api/';
|
||||
</script>
|
||||
|
||||
<!-- Required for correct loading of scripts in Electron -->
|
||||
<script>
|
||||
if (typeof module === 'object') {
|
||||
window.module = module; module = undefined;
|
||||
}
|
||||
|
||||
const glob = {
|
||||
sourceId: ''
|
||||
};
|
||||
</script>
|
||||
|
||||
<script src="libraries/jquery.min.js"></script>
|
||||
|
||||
<link href="libraries/bootstrap/css/bootstrap.css" rel="stylesheet">
|
||||
<script src="libraries/bootstrap/js/bootstrap.js"></script>
|
||||
|
||||
<script src="javascripts/migration.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user