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": {
|
"devDependencies": {
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"electron": "25.9.1",
|
"electron": "25.9.2",
|
||||||
"electron-builder": "24.6.4",
|
"electron-builder": "24.6.4",
|
||||||
"electron-packager": "17.1.2",
|
"electron-packager": "17.1.2",
|
||||||
"electron-rebuild": "3.2.9",
|
"electron-rebuild": "3.2.9",
|
||||||
@ -4276,9 +4276,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron": {
|
"node_modules/electron": {
|
||||||
"version": "25.9.1",
|
"version": "25.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.2.tgz",
|
||||||
"integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==",
|
"integrity": "sha512-hVBN5rsrL99BKNHvzMeYy2PkAmewuIobu4U3o3EzVz4MDoLmMfW4yTH5GZ4RbJrpokoEky5IzGtRR/ggPzL6Fw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/get": "^2.0.0",
|
"@electron/get": "^2.0.0",
|
||||||
@ -16633,9 +16633,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron": {
|
"electron": {
|
||||||
"version": "25.9.1",
|
"version": "25.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/electron/-/electron-25.9.2.tgz",
|
||||||
"integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==",
|
"integrity": "sha512-hVBN5rsrL99BKNHvzMeYy2PkAmewuIobu4U3o3EzVz4MDoLmMfW4yTH5GZ4RbJrpokoEky5IzGtRR/ggPzL6Fw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@electron/get": "^2.0.0",
|
"@electron/get": "^2.0.0",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"electron": "25.9.1",
|
"electron": "25.9.2",
|
||||||
"electron-builder": "24.6.4",
|
"electron-builder": "24.6.4",
|
||||||
"electron-packager": "17.1.2",
|
"electron-packager": "17.1.2",
|
||||||
"electron-rebuild": "3.2.9",
|
"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>
|
<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>
|
<button class="anonymize-light-button btn">Save lightly anonymized database</button>
|
||||||
|
|
||||||
|
<h5>Existing anonymized databases</h5>
|
||||||
|
|
||||||
|
<ul class="existing-anonymized-databases"></ul>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
||||||
@ -38,6 +42,8 @@ export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
|||||||
else {
|
else {
|
||||||
toastService.showMessage(`Created fully anonymized database in ${resp.anonymizedFilePath}`, 10000);
|
toastService.showMessage(`Created fully anonymized database in ${resp.anonymizedFilePath}`, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$anonymizeLightButton.on('click', async () => {
|
this.$anonymizeLightButton.on('click', async () => {
|
||||||
@ -51,6 +57,24 @@ export default class DatabaseAnonymizationOptions extends OptionsWidget {
|
|||||||
else {
|
else {
|
||||||
toastService.showMessage(`Created lightly anonymized database in ${resp.anonymizedFilePath}`, 10000);
|
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>
|
<button class="backup-database-button btn">Backup database now</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="options-section">
|
||||||
|
<h4>Existing backups</h4>
|
||||||
|
|
||||||
|
<ul class="existing-backup-list"></ul>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default class BackupOptions extends OptionsWidget {
|
export default class BackupOptions extends OptionsWidget {
|
||||||
@ -49,6 +55,8 @@ export default class BackupOptions extends OptionsWidget {
|
|||||||
const {backupFile} = await server.post('database/backup-database');
|
const {backupFile} = await server.post('database/backup-database');
|
||||||
|
|
||||||
toastService.showMessage(`Database has been backed up to ${backupFile}`, 10000);
|
toastService.showMessage(`Database has been backed up to ${backupFile}`, 10000);
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$dailyBackupEnabled = this.$widget.find(".daily-backup-enabled");
|
this.$dailyBackupEnabled = this.$widget.find(".daily-backup-enabled");
|
||||||
@ -63,11 +71,25 @@ export default class BackupOptions extends OptionsWidget {
|
|||||||
|
|
||||||
this.$monthlyBackupEnabled.on('change', () =>
|
this.$monthlyBackupEnabled.on('change', () =>
|
||||||
this.updateCheckboxOption('monthlyBackupEnabled', this.$monthlyBackupEnabled));
|
this.updateCheckboxOption('monthlyBackupEnabled', this.$monthlyBackupEnabled));
|
||||||
|
|
||||||
|
this.$existingBackupList = this.$widget.find(".existing-backup-list");
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsLoaded(options) {
|
optionsLoaded(options) {
|
||||||
this.setCheckboxState(this.$dailyBackupEnabled, options.dailyBackupEnabled);
|
this.setCheckboxState(this.$dailyBackupEnabled, options.dailyBackupEnabled);
|
||||||
this.setCheckboxState(this.$weeklyBackupEnabled, options.weeklyBackupEnabled);
|
this.setCheckboxState(this.$weeklyBackupEnabled, options.weeklyBackupEnabled);
|
||||||
this.setCheckboxState(this.$monthlyBackupEnabled, options.monthlyBackupEnabled);
|
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 anonymizationService = require('../../services/anonymization');
|
||||||
const consistencyChecksService = require('../../services/consistency_checks');
|
const consistencyChecksService = require('../../services/consistency_checks');
|
||||||
|
|
||||||
async function anonymize(req) {
|
function getExistingBackups() {
|
||||||
return await anonymizationService.createAnonymizedCopy(req.params.type);
|
return backupService.getExistingBackups();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function backupDatabase() {
|
async function backupDatabase() {
|
||||||
@ -22,6 +22,18 @@ function vacuumDatabase() {
|
|||||||
log.info("Database has been vacuumed.");
|
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() {
|
function checkIntegrity() {
|
||||||
const results = sql.getRows("PRAGMA integrity_check");
|
const results = sql.getRows("PRAGMA integrity_check");
|
||||||
|
|
||||||
@ -32,14 +44,12 @@ function checkIntegrity() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function findAndFixConsistencyIssues() {
|
|
||||||
consistencyChecksService.runOnDemandChecks(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
getExistingBackups,
|
||||||
backupDatabase,
|
backupDatabase,
|
||||||
vacuumDatabase,
|
vacuumDatabase,
|
||||||
findAndFixConsistencyIssues,
|
findAndFixConsistencyIssues,
|
||||||
|
getExistingAnonymizedDatabases,
|
||||||
anonymize,
|
anonymize,
|
||||||
checkIntegrity
|
checkIntegrity
|
||||||
};
|
};
|
||||||
|
@ -289,9 +289,11 @@ function register(app) {
|
|||||||
apiRoute(GET, '/api/sql/schema', sqlRoute.getSchema);
|
apiRoute(GET, '/api/sql/schema', sqlRoute.getSchema);
|
||||||
apiRoute(PST, '/api/sql/execute/:noteId', sqlRoute.execute);
|
apiRoute(PST, '/api/sql/execute/:noteId', sqlRoute.execute);
|
||||||
route(PST, '/api/database/anonymize/:type', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.anonymize, apiResultHandler, false);
|
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
|
// backup requires execution outside of transaction
|
||||||
route(PST, '/api/database/backup-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.backupDatabase, apiResultHandler, false);
|
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
|
// VACUUM requires execution outside of transaction
|
||||||
route(PST, '/api/database/vacuum-database', [auth.checkApiAuthOrElectron, csrfMiddleware], databaseRoute.vacuumDatabase, apiResultHandler, false);
|
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 dateUtils = require("./date_utils");
|
||||||
const Database = require("better-sqlite3");
|
const Database = require("better-sqlite3");
|
||||||
const sql = require("./sql");
|
const sql = require("./sql");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
function getFullAnonymizationScript() {
|
function getFullAnonymizationScript() {
|
||||||
// we want to delete all non-builtin attributes because they can contain sensitive names and values
|
// 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 = {
|
module.exports = {
|
||||||
getFullAnonymizationScript,
|
getFullAnonymizationScript,
|
||||||
createAnonymizedCopy
|
createAnonymizedCopy,
|
||||||
|
getExistingAnonymizedDatabases
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,20 @@ const log = require('./log');
|
|||||||
const syncMutexService = require('./sync_mutex');
|
const syncMutexService = require('./sync_mutex');
|
||||||
const cls = require('./cls');
|
const cls = require('./cls');
|
||||||
const sql = require('./sql');
|
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() {
|
function regularBackup() {
|
||||||
cls.init(() => {
|
cls.init(() => {
|
||||||
@ -58,6 +72,7 @@ if (!fs.existsSync(dataDir.BACKUP_DIR)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
getExistingBackups,
|
||||||
backupNow,
|
backupNow,
|
||||||
regularBackup
|
regularBackup
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user