mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	#98, new option "initialized" which indicates if setup has been finished
This commit is contained in:
		
							
								
								
									
										2
									
								
								db/migrations/0103__add_initialized_option.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								db/migrations/0103__add_initialized_option.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | INSERT INTO options (name, value, dateCreated, dateModified, isSynced) | ||||||
|  | VALUES ('initialized', 'true', '2018-06-01T03:35:55.041Z', '2018-06-01T03:35:55.041Z', 0); | ||||||
| @@ -47,7 +47,7 @@ const sessionParser = session({ | |||||||
|     cookie: { |     cookie: { | ||||||
|         //    path: "/", |         //    path: "/", | ||||||
|         httpOnly: true, |         httpOnly: true, | ||||||
|         maxAge:  1800000 |         maxAge:  24 * 60 * 60 * 1000 // in milliseconds | ||||||
|     }, |     }, | ||||||
|     store: new FileStore({ |     store: new FileStore({ | ||||||
|         ttl: 30 * 24 * 3600, |         ttl: 30 * 24 * 3600, | ||||||
|   | |||||||
| @@ -1,7 +1,11 @@ | |||||||
| import utils from "./services/utils.js"; | import utils from "./services/utils.js"; | ||||||
|  |  | ||||||
| function SetupModel() { | function SetupModel() { | ||||||
|     this.step = ko.observable("setup-type"); |     if (syncInProgress) { | ||||||
|  |         setInterval(checkOutstandingSyncs, 1000); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     this.step = ko.observable(syncInProgress ? "sync-in-progress" : "setup-type"); | ||||||
|     this.setupType = ko.observable(); |     this.setupType = ko.observable(); | ||||||
|  |  | ||||||
|     this.setupNewDocument = ko.observable(false); |     this.setupNewDocument = ko.observable(false); | ||||||
| @@ -93,8 +97,6 @@ function SetupModel() { | |||||||
|             if (resp.result === 'success') { |             if (resp.result === 'success') { | ||||||
|                 this.step('sync-in-progress'); |                 this.step('sync-in-progress'); | ||||||
|  |  | ||||||
|                 checkOutstandingSyncs(); |  | ||||||
|  |  | ||||||
|                 setInterval(checkOutstandingSyncs, 1000); |                 setInterval(checkOutstandingSyncs, 1000); | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
| @@ -105,7 +107,12 @@ function SetupModel() { | |||||||
| } | } | ||||||
|  |  | ||||||
| async function checkOutstandingSyncs() { | async function checkOutstandingSyncs() { | ||||||
|     const stats = await $.get('/api/sync/stats'); |     const { stats, initialized } = await $.get('/api/sync/stats'); | ||||||
|  |  | ||||||
|  |     if (initialized) { | ||||||
|  |         window.location.replace("/"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     const totalOutstandingSyncs = stats.outstandingPushes + stats.outstandingPulls; |     const totalOutstandingSyncs = stats.outstandingPushes + stats.outstandingPulls; | ||||||
|  |  | ||||||
|     $("#outstanding-syncs").html(totalOutstandingSyncs); |     $("#outstanding-syncs").html(totalOutstandingSyncs); | ||||||
|   | |||||||
| @@ -1,11 +1,7 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
|  |  | ||||||
| const sqlInit = require('../../services/sql_init'); | const sqlInit = require('../../services/sql_init'); | ||||||
| const sql = require('../../services/sql'); | const setupService = require('../../services/setup'); | ||||||
| const rp = require('request-promise'); |  | ||||||
| const Option = require('../../entities/option'); |  | ||||||
| const syncService = require('../../services/sync'); |  | ||||||
| const log = require('../../services/log'); |  | ||||||
|  |  | ||||||
| async function setupNewDocument(req) { | async function setupNewDocument(req) { | ||||||
|     const { username, password } = req.body; |     const { username, password } = req.body; | ||||||
| @@ -16,44 +12,7 @@ async function setupNewDocument(req) { | |||||||
| async function setupSyncFromServer(req) { | async function setupSyncFromServer(req) { | ||||||
|     const { serverAddress, username, password } = req.body; |     const { serverAddress, username, password } = req.body; | ||||||
|  |  | ||||||
|     try { |     return await setupService.setupSyncFromSyncServer(serverAddress, username, password); | ||||||
|         log.info("Getting document options from sync server."); |  | ||||||
|  |  | ||||||
|         // response is expected to contain documentId and documentSecret options |  | ||||||
|         const options = await rp.get({ |  | ||||||
|             uri: serverAddress + '/api/sync/document', |  | ||||||
|             auth: { |  | ||||||
|                 'user': username, |  | ||||||
|                 'pass': password |  | ||||||
|             }, |  | ||||||
|             json: true |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         log.info("Creating database for sync"); |  | ||||||
|  |  | ||||||
|         await sql.transactional(async () => { |  | ||||||
|             await sqlInit.createDatabaseForSync(serverAddress); |  | ||||||
|  |  | ||||||
|             for (const opt of options) { |  | ||||||
|                 await new Option(opt).save(); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         log.info("Triggering sync."); |  | ||||||
|  |  | ||||||
|         // it's ok to not wait for it here |  | ||||||
|         syncService.sync(); |  | ||||||
|  |  | ||||||
|         return { result: 'success' }; |  | ||||||
|     } |  | ||||||
|     catch (e) { |  | ||||||
|         log.error("Sync failed: " + e.message); |  | ||||||
|  |  | ||||||
|         return { |  | ||||||
|             result: 'failure', |  | ||||||
|             error: e.message |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   | |||||||
| @@ -24,7 +24,10 @@ async function testSync() { | |||||||
| } | } | ||||||
|  |  | ||||||
| async function getStats() { | async function getStats() { | ||||||
|     return syncService.stats; |     return { | ||||||
|  |         initialized: await optionService.getOption('initialized') === 'true', | ||||||
|  |         stats: syncService.stats | ||||||
|  |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
| async function checkSync() { | async function checkSync() { | ||||||
|   | |||||||
| @@ -1,7 +1,25 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
|  |  | ||||||
| function setupPage(req, res) { | const sqlInit = require('../services/sql_init'); | ||||||
|     res.render('setup', {}); | const setupService = require('../services/setup'); | ||||||
|  |  | ||||||
|  | async function setupPage(req, res) { | ||||||
|  |     if (await sqlInit.isDbInitialized()) { | ||||||
|  |         res.redirect('/'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // we got here because DB is not completely initialized so if schema exists | ||||||
|  |     // it means we're in sync in progress state. | ||||||
|  |     const syncInProgress = await sqlInit.schemaExists(); | ||||||
|  |  | ||||||
|  |     if (syncInProgress) { | ||||||
|  |         // trigger sync if it's not already running | ||||||
|  |         setupService.triggerSync(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     res.render('setup', { | ||||||
|  |         syncInProgress: syncInProgress | ||||||
|  |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
| const build = require('./build'); | const build = require('./build'); | ||||||
| const packageJson = require('../../package'); | const packageJson = require('../../package'); | ||||||
|  |  | ||||||
| const APP_DB_VERSION = 102; | const APP_DB_VERSION = 103; | ||||||
| const SYNC_VERSION = 1; | const SYNC_VERSION = 1; | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ async function initSyncedOptions(username, password) { | |||||||
|     await passwordEncryptionService.setDataKey(password, utils.randomSecureToken(16)); |     await passwordEncryptionService.setDataKey(password, utils.randomSecureToken(16)); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function initNotSyncedOptions(startNotePath = '', syncServerHost = '') { | async function initNotSyncedOptions(initialized, startNotePath = '', syncServerHost = '') { | ||||||
|     await optionService.createOption('startNotePath', startNotePath, false); |     await optionService.createOption('startNotePath', startNotePath, false); | ||||||
|     await optionService.createOption('lastBackupDate', dateUtils.nowDate(), false); |     await optionService.createOption('lastBackupDate', dateUtils.nowDate(), false); | ||||||
|     await optionService.createOption('dbVersion', appInfo.dbVersion, false); |     await optionService.createOption('dbVersion', appInfo.dbVersion, false); | ||||||
| @@ -43,6 +43,8 @@ async function initNotSyncedOptions(startNotePath = '', syncServerHost = '') { | |||||||
|     await optionService.createOption('syncServerHost', syncServerHost, false); |     await optionService.createOption('syncServerHost', syncServerHost, false); | ||||||
|     await optionService.createOption('syncServerTimeout', 5000, false); |     await optionService.createOption('syncServerTimeout', 5000, false); | ||||||
|     await optionService.createOption('syncProxy', '', false); |     await optionService.createOption('syncProxy', '', false); | ||||||
|  |  | ||||||
|  |     await optionService.createOption('initialized', initialized ? 'true' : 'false', false); | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								src/services/setup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/services/setup.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | const sqlInit = require('./sql_init'); | ||||||
|  | const sql = require('./sql'); | ||||||
|  | const rp = require('request-promise'); | ||||||
|  | const Option = require('../entities/option'); | ||||||
|  | const syncService = require('./sync'); | ||||||
|  | const log = require('./log'); | ||||||
|  | const optionService = require('./options'); | ||||||
|  |  | ||||||
|  | function triggerSync() { | ||||||
|  | // it's ok to not wait for it here | ||||||
|  |     syncService.sync().then(async () => { | ||||||
|  |         await optionService.setOption('initialized', 'true'); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function setupSyncFromSyncServer(serverAddress, username, password) { | ||||||
|  |     if (await sqlInit.isDbInitialized()) { | ||||||
|  |         return { | ||||||
|  |             result: 'failure', | ||||||
|  |             error: 'DB is already initialized.' | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |         log.info("Getting document options from sync server."); | ||||||
|  |  | ||||||
|  |         // response is expected to contain documentId and documentSecret options | ||||||
|  |         const options = await rp.get({ | ||||||
|  |             uri: serverAddress + '/api/sync/document', | ||||||
|  |             auth: { | ||||||
|  |                 'user': username, | ||||||
|  |                 'pass': password | ||||||
|  |             }, | ||||||
|  |             json: true | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         log.info("Creating database for sync"); | ||||||
|  |  | ||||||
|  |         await sql.transactional(async () => { | ||||||
|  |             await sqlInit.createDatabaseForSync(serverAddress); | ||||||
|  |  | ||||||
|  |             for (const opt of options) { | ||||||
|  |                 await new Option(opt).save(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         log.info("Triggering sync."); | ||||||
|  |  | ||||||
|  |         triggerSync(); | ||||||
|  |  | ||||||
|  |         return { result: 'success' }; | ||||||
|  |     } | ||||||
|  |     catch (e) { | ||||||
|  |         log.error("Sync failed: " + e.message); | ||||||
|  |  | ||||||
|  |         return { | ||||||
|  |             result: 'failure', | ||||||
|  |             error: e.message | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     setupSyncFromSyncServer, | ||||||
|  |     triggerSync | ||||||
|  | }; | ||||||
| @@ -22,12 +22,22 @@ const dbReady = new Promise(async (resolve, reject) => { | |||||||
|     initDbConnection(); |     initDbConnection(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| async function isDbInitialized() { | async function schemaExists() { | ||||||
|     const tableResults = await sql.getRows("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'"); |     const tableResults = await sql.getRows("SELECT name FROM sqlite_master WHERE type='table' AND name='options'"); | ||||||
|  |  | ||||||
|     return tableResults.length === 1; |     return tableResults.length === 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function isDbInitialized() { | ||||||
|  |     if (!await schemaExists()) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const initialized = await sql.getValue("SELECT value FROM options WHERE name = 'initialized'"); | ||||||
|  |  | ||||||
|  |     return initialized === 'true'; | ||||||
|  | } | ||||||
|  |  | ||||||
| async function initDbConnection() { | async function initDbConnection() { | ||||||
|     await cls.init(async () => { |     await cls.init(async () => { | ||||||
|         await sql.execute("PRAGMA foreign_keys = ON"); |         await sql.execute("PRAGMA foreign_keys = ON"); | ||||||
| @@ -53,6 +63,10 @@ async function initDbConnection() { | |||||||
| async function createInitialDatabase(username, password) { | async function createInitialDatabase(username, password) { | ||||||
|     log.info("Creating initial database ..."); |     log.info("Creating initial database ..."); | ||||||
|  |  | ||||||
|  |     if (await isDbInitialized()) { | ||||||
|  |         throw new Error("DB is already initialized"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     const schema = fs.readFileSync(resourceDir.DB_INIT_DIR + '/schema.sql', 'UTF-8'); |     const schema = fs.readFileSync(resourceDir.DB_INIT_DIR + '/schema.sql', 'UTF-8'); | ||||||
|     const notesSql = fs.readFileSync(resourceDir.DB_INIT_DIR + '/main_notes.sql', 'UTF-8'); |     const notesSql = fs.readFileSync(resourceDir.DB_INIT_DIR + '/main_notes.sql', 'UTF-8'); | ||||||
|     const notesTreeSql = fs.readFileSync(resourceDir.DB_INIT_DIR + '/main_branches.sql', 'UTF-8'); |     const notesTreeSql = fs.readFileSync(resourceDir.DB_INIT_DIR + '/main_branches.sql', 'UTF-8'); | ||||||
| @@ -72,7 +86,7 @@ async function createInitialDatabase(username, password) { | |||||||
|  |  | ||||||
|         await optionsInitService.initDocumentOptions(); |         await optionsInitService.initDocumentOptions(); | ||||||
|         await optionsInitService.initSyncedOptions(username, password); |         await optionsInitService.initSyncedOptions(username, password); | ||||||
|         await optionsInitService.initNotSyncedOptions(startNoteId); |         await optionsInitService.initNotSyncedOptions(true, startNoteId); | ||||||
|  |  | ||||||
|         await require('./sync_table').fillAllSyncRows(); |         await require('./sync_table').fillAllSyncRows(); | ||||||
|     }); |     }); | ||||||
| @@ -90,7 +104,7 @@ async function createDatabaseForSync(syncServerHost) { | |||||||
|     await sql.transactional(async () => { |     await sql.transactional(async () => { | ||||||
|         await sql.executeScript(schema); |         await sql.executeScript(schema); | ||||||
|  |  | ||||||
|         await require('./options_init').initNotSyncedOptions('', syncServerHost); |         await require('./options_init').initNotSyncedOptions(false, '', syncServerHost); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     log.info("Schema and not synced options generated."); |     log.info("Schema and not synced options generated."); | ||||||
| @@ -110,6 +124,7 @@ async function isDbUpToDate() { | |||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     dbReady, |     dbReady, | ||||||
|  |     schemaExists, | ||||||
|     isDbInitialized, |     isDbInitialized, | ||||||
|     initDbConnection, |     initDbConnection, | ||||||
|     isDbUpToDate, |     isDbUpToDate, | ||||||
|   | |||||||
| @@ -103,6 +103,7 @@ | |||||||
|     const glob = { |     const glob = { | ||||||
|         sourceId: '' |         sourceId: '' | ||||||
|     }; |     }; | ||||||
|  |     const syncInProgress = <%= syncInProgress ? 'true' : 'false' %>; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <!-- Required for correct loading of scripts in Electron --> | <!-- Required for correct loading of scripts in Electron --> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user