mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
show existing backups and anonymized DBs, #4321
This commit is contained in:
parent
2132cf3bdc
commit
148bff9f77
14
package-lock.json
generated
14
package-lock.json
generated
@ -79,7 +79,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3",
|
||||
"electron": "25.9.1",
|
||||
"electron": "25.9.2",
|
||||
"electron-builder": "24.6.4",
|
||||
"electron-packager": "17.1.2",
|
||||
"electron-rebuild": "3.2.9",
|
||||
@ -4276,9 +4276,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "25.9.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz",
|
||||
"integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==",
|
||||
"version": "25.9.2",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.2.tgz",
|
||||
"integrity": "sha512-hVBN5rsrL99BKNHvzMeYy2PkAmewuIobu4U3o3EzVz4MDoLmMfW4yTH5GZ4RbJrpokoEky5IzGtRR/ggPzL6Fw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@electron/get": "^2.0.0",
|
||||
@ -16633,9 +16633,9 @@
|
||||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "25.9.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz",
|
||||
"integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==",
|
||||
"version": "25.9.2",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.2.tgz",
|
||||
"integrity": "sha512-hVBN5rsrL99BKNHvzMeYy2PkAmewuIobu4U3o3EzVz4MDoLmMfW4yTH5GZ4RbJrpokoEky5IzGtRR/ggPzL6Fw==",
|
||||
"requires": {
|
||||
"@electron/get": "^2.0.0",
|
||||
"@types/node": "^18.11.18",
|
||||
|
@ -97,7 +97,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3",
|
||||
"electron": "25.9.1",
|
||||
"electron": "25.9.2",
|
||||
"electron-builder": "24.6.4",
|
||||
"electron-packager": "17.1.2",
|
||||
"electron-rebuild": "3.2.9",
|
||||
|
@ -20,6 +20,10 @@ const TPL = `
|
||||
<p>You can decide yourself if you want to provide a fully or lightly anonymized database. Even fully anonymized DB is very useful, however in some cases lightly anonymized database can speed up the process of bug identification and fixing.</p>
|
||||
|
||||
<button class="anonymize-light-button btn">Save lightly anonymized database</button>
|
||||
|
||||
<h5>Existing anonymized databases</h5>
|
||||
|
||||
<ul class="existing-anonymized-databases"></ul>
|
||||
</div>`;
|
||||
|
||||
export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
||||
@ -38,6 +42,8 @@ export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
||||
else {
|
||||
toastService.showMessage(`Created fully anonymized database in ${resp.anonymizedFilePath}`, 10000);
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
});
|
||||
|
||||
this.$anonymizeLightButton.on('click', async () => {
|
||||
@ -51,6 +57,24 @@ export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
||||
else {
|
||||
toastService.showMessage(`Created lightly anonymized database in ${resp.anonymizedFilePath}`, 10000);
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
});
|
||||
|
||||
this.$existingAnonymizedDatabases = this.$widget.find(".existing-anonymized-databases");
|
||||
}
|
||||
|
||||
optionsLoaded(options) {
|
||||
server.get("database/anonymized-databases").then(anonymizedDatabases => {
|
||||
this.$existingAnonymizedDatabases.empty();
|
||||
|
||||
if (!anonymizedDatabases.length) {
|
||||
anonymizedDatabases = [{filePath: "no anonymized database yet"}];
|
||||
}
|
||||
|
||||
for (const {filePath} of anonymizedDatabases) {
|
||||
this.$existingAnonymizedDatabases.append($("<li>").text(filePath));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,12 @@ const TPL = `
|
||||
|
||||
<button class="backup-database-button btn">Backup database now</button>
|
||||
</div>
|
||||
|
||||
<div class="options-section">
|
||||
<h4>Existing backups</h4>
|
||||
|
||||
<ul class="existing-backup-list"></ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
export default class BackupOptions extends OptionsWidget {
|
||||
@ -49,6 +55,8 @@ export default class BackupOptions extends OptionsWidget {
|
||||
const {backupFile} = await server.post('database/backup-database');
|
||||
|
||||
toastService.showMessage(`Database has been backed up to ${backupFile}`, 10000);
|
||||
|
||||
this.refresh();
|
||||
});
|
||||
|
||||
this.$dailyBackupEnabled = this.$widget.find(".daily-backup-enabled");
|
||||
@ -63,11 +71,25 @@ export default class BackupOptions extends OptionsWidget {
|
||||
|
||||
this.$monthlyBackupEnabled.on('change', () =>
|
||||
this.updateCheckboxOption('monthlyBackupEnabled', this.$monthlyBackupEnabled));
|
||||
|
||||
this.$existingBackupList = this.$widget.find(".existing-backup-list");
|
||||
}
|
||||
|
||||
optionsLoaded(options) {
|
||||
this.setCheckboxState(this.$dailyBackupEnabled, options.dailyBackupEnabled);
|
||||
this.setCheckboxState(this.$weeklyBackupEnabled, options.weeklyBackupEnabled);
|
||||
this.setCheckboxState(this.$monthlyBackupEnabled, options.monthlyBackupEnabled);
|
||||
|
||||
server.get("database/backups").then(backupFiles => {
|
||||
this.$existingBackupList.empty();
|
||||
|
||||
if (!backupFiles.length) {
|
||||
backupFiles = [{filePath: "no backup yet"}];
|
||||
}
|
||||
|
||||
for (const {filePath} of backupFiles) {
|
||||
this.$existingBackupList.append($("<li>").text(filePath));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ const backupService = require('../../services/backup');
|
||||
const anonymizationService = require('../../services/anonymization');
|
||||
const consistencyChecksService = require('../../services/consistency_checks');
|
||||
|
||||
async function anonymize(req) {
|
||||
return await anonymizationService.createAnonymizedCopy(req.params.type);
|
||||
function getExistingBackups() {
|
||||
return backupService.getExistingBackups();
|
||||
}
|
||||
|
||||
async function backupDatabase() {
|
||||
@ -22,6 +22,18 @@ function vacuumDatabase() {
|
||||
log.info("Database has been vacuumed.");
|
||||
}
|
||||
|
||||
function findAndFixConsistencyIssues() {
|
||||
consistencyChecksService.runOnDemandChecks(true);
|
||||
}
|
||||
|
||||
function getExistingAnonymizedDatabases() {
|
||||
return anonymizationService.getExistingAnonymizedDatabases();
|
||||
}
|
||||
|
||||
async function anonymize(req) {
|
||||
return await anonymizationService.createAnonymizedCopy(req.params.type);
|
||||
}
|
||||
|
||||
function checkIntegrity() {
|
||||
const results = sql.getRows("PRAGMA integrity_check");
|
||||
|
||||
@ -32,14 +44,12 @@ function checkIntegrity() {
|
||||
};
|
||||
}
|
||||
|
||||
function findAndFixConsistencyIssues() {
|
||||
consistencyChecksService.runOnDemandChecks(true);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getExistingBackups,
|
||||
backupDatabase,
|
||||
vacuumDatabase,
|
||||
findAndFixConsistencyIssues,
|
||||
getExistingAnonymizedDatabases,
|
||||
anonymize,
|
||||
checkIntegrity
|
||||
};
|
||||
|
@ -289,9 +289,11 @@ function register(app) {
|
||||
apiRoute(GET, '/api/sql/schema', sqlRoute.getSchema);
|
||||
apiRoute(PST, '/api/sql/execute/:noteId', sqlRoute.execute);
|
||||
route(PST, '/api/database/anonymize/:type', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.anonymize, apiResultHandler, false);
|
||||
apiRoute(GET, '/api/database/anonymized-databases', databaseRoute.getExistingAnonymizedDatabases);
|
||||
|
||||
// backup requires execution outside of transaction
|
||||
route(PST, '/api/database/backup-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.backupDatabase, apiResultHandler, false);
|
||||
apiRoute(GET, '/api/database/backups', databaseRoute.getExistingBackups);
|
||||
|
||||
// VACUUM requires execution outside of transaction
|
||||
route(PST, '/api/database/vacuum-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.vacuumDatabase, apiResultHandler, false);
|
||||
|
@ -4,6 +4,7 @@ const dataDir = require("./data_dir");
|
||||
const dateUtils = require("./date_utils");
|
||||
const Database = require("better-sqlite3");
|
||||
const sql = require("./sql");
|
||||
const path = require("path");
|
||||
|
||||
function getFullAnonymizationScript() {
|
||||
// we want to delete all non-builtin attributes because they can contain sensitive names and values
|
||||
@ -70,7 +71,21 @@ async function createAnonymizedCopy(type) {
|
||||
};
|
||||
}
|
||||
|
||||
function getExistingAnonymizedDatabases() {
|
||||
if (!fs.existsSync(dataDir.ANONYMIZED_DB_DIR)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fs.readdirSync(dataDir.ANONYMIZED_DB_DIR)
|
||||
.filter(fileName => fileName.includes("anonymized"))
|
||||
.map(fileName => ({
|
||||
fileName: fileName,
|
||||
filePath: path.resolve(dataDir.ANONYMIZED_DB_DIR, fileName)
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFullAnonymizationScript,
|
||||
createAnonymizedCopy
|
||||
createAnonymizedCopy,
|
||||
getExistingAnonymizedDatabases
|
||||
}
|
||||
|
@ -8,6 +8,20 @@ const log = require('./log');
|
||||
const syncMutexService = require('./sync_mutex');
|
||||
const cls = require('./cls');
|
||||
const sql = require('./sql');
|
||||
const path = require('path');
|
||||
|
||||
function getExistingBackups() {
|
||||
if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fs.readdirSync(dataDir.BACKUP_DIR)
|
||||
.filter(fileName => fileName.includes("backup"))
|
||||
.map(fileName => ({
|
||||
fileName: fileName,
|
||||
filePath: path.resolve(dataDir.BACKUP_DIR, fileName)
|
||||
}));
|
||||
}
|
||||
|
||||
function regularBackup() {
|
||||
cls.init(() => {
|
||||
@ -58,6 +72,7 @@ if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getExistingBackups,
|
||||
backupNow,
|
||||
regularBackup
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user