database backup
parent
5eb61df31d
commit
94af5ba3fe
|
|
@ -6,6 +6,9 @@ cypress/downloads/
|
|||
cypress/screenshots/
|
||||
cypress/videos/
|
||||
|
||||
data/backups/*
|
||||
!data/backups/README.md
|
||||
|
||||
data/sessions/
|
||||
|
||||
node_modules/
|
||||
|
|
|
|||
|
|
@ -1,17 +1,27 @@
|
|||
import { testAdmin } from '../../../test/_globals.js';
|
||||
import { logout, login, ajaxDelayMillis } from '../../support/index.js';
|
||||
describe('Admin - Cleanup Database', () => {
|
||||
describe('Admin - Database Maintenance', () => {
|
||||
beforeEach('Loads page', () => {
|
||||
logout();
|
||||
login(testAdmin);
|
||||
cy.visit('/admin/cleanup');
|
||||
cy.location('pathname').should('equal', '/admin/cleanup');
|
||||
cy.visit('/admin/database');
|
||||
cy.location('pathname').should('equal', '/admin/database');
|
||||
});
|
||||
afterEach(logout);
|
||||
it('Has no detectable accessibility issues', () => {
|
||||
cy.injectAxe();
|
||||
cy.checkA11y();
|
||||
});
|
||||
it('Backs up the database', () => {
|
||||
cy.get("button[data-cy='backup']").click();
|
||||
cy.get('.modal').should('be.visible').should('contain.text', 'Backup');
|
||||
cy.get(".modal button[data-cy='ok']").click();
|
||||
cy.wait(ajaxDelayMillis);
|
||||
cy.get('.modal')
|
||||
.should('contain.text', 'Backed Up')
|
||||
.should('contain.text', 'Success');
|
||||
cy.get(".modal button[data-cy='ok']").click();
|
||||
});
|
||||
it('Cleans up the database', () => {
|
||||
cy.get("button[data-cy='cleanup']").click();
|
||||
cy.get('.modal').should('be.visible').should('contain.text', 'Cleanup');
|
||||
|
|
@ -4,12 +4,12 @@ import { testAdmin } from '../../../test/_globals.js'
|
|||
|
||||
import { logout, login, ajaxDelayMillis } from '../../support/index.js'
|
||||
|
||||
describe('Admin - Cleanup Database', () => {
|
||||
describe('Admin - Database Maintenance', () => {
|
||||
beforeEach('Loads page', () => {
|
||||
logout()
|
||||
login(testAdmin)
|
||||
cy.visit('/admin/cleanup')
|
||||
cy.location('pathname').should('equal', '/admin/cleanup')
|
||||
cy.visit('/admin/database')
|
||||
cy.location('pathname').should('equal', '/admin/database')
|
||||
})
|
||||
|
||||
afterEach(logout)
|
||||
|
|
@ -19,6 +19,22 @@ describe('Admin - Cleanup Database', () => {
|
|||
cy.checkA11y()
|
||||
})
|
||||
|
||||
it('Backs up the database', () => {
|
||||
cy.get("button[data-cy='backup']").click()
|
||||
|
||||
cy.get('.modal').should('be.visible').should('contain.text', 'Backup')
|
||||
|
||||
cy.get(".modal button[data-cy='ok']").click()
|
||||
|
||||
cy.wait(ajaxDelayMillis)
|
||||
|
||||
cy.get('.modal')
|
||||
.should('contain.text', 'Backed Up')
|
||||
.should('contain.text', 'Success')
|
||||
|
||||
cy.get(".modal button[data-cy='ok']").click()
|
||||
})
|
||||
|
||||
it('Cleans up the database', () => {
|
||||
cy.get("button[data-cy='cleanup']").click()
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ describe('Update User', () => {
|
|||
cy.get("a[href*='/admin']").should('not.exist');
|
||||
});
|
||||
it('Redirects to Dashboard when attempting to access admin area', () => {
|
||||
cy.visit('/admin/cleanup');
|
||||
cy.visit('/admin/tables');
|
||||
cy.wait(200);
|
||||
cy.location('pathname').should('equal', '/dashboard/');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ describe('Update User', () => {
|
|||
})
|
||||
|
||||
it('Redirects to Dashboard when attempting to access admin area', () => {
|
||||
cy.visit('/admin/cleanup')
|
||||
cy.visit('/admin/tables')
|
||||
cy.wait(200)
|
||||
cy.location('pathname').should('equal', '/dashboard/')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -25,4 +25,9 @@ describe('Login Page', () => {
|
|||
matchCase: false
|
||||
});
|
||||
});
|
||||
it('Redirects to login when attempting to access dashboard', () => {
|
||||
cy.visit('/dashboard');
|
||||
cy.wait(200);
|
||||
cy.location('pathname').should('contain', '/login');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -32,4 +32,10 @@ describe('Login Page', () => {
|
|||
matchCase: false
|
||||
})
|
||||
})
|
||||
|
||||
it('Redirects to login when attempting to access dashboard', () => {
|
||||
cy.visit('/dashboard')
|
||||
cy.wait(200)
|
||||
cy.location('pathname').should('contain', '/login')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# Placeholder
|
||||
|
||||
This is a placeholder file to assist with the creation of this folder.
|
||||
|
|
@ -2,3 +2,4 @@ export declare const useTestDatabases: boolean;
|
|||
export declare const lotOccupancyDBLive = "data/lotOccupancy.db";
|
||||
export declare const lotOccupancyDBTesting = "data/lotOccupancy-testing.db";
|
||||
export declare const lotOccupancyDB: string;
|
||||
export declare const backupFolder = "data/backups";
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ export const lotOccupancyDBTesting = 'data/lotOccupancy-testing.db';
|
|||
export const lotOccupancyDB = useTestDatabases
|
||||
? lotOccupancyDBTesting
|
||||
: lotOccupancyDBLive;
|
||||
export const backupFolder = 'data/backups';
|
||||
|
|
|
|||
|
|
@ -19,3 +19,5 @@ export const lotOccupancyDBTesting = 'data/lotOccupancy-testing.db'
|
|||
export const lotOccupancyDB = useTestDatabases
|
||||
? lotOccupancyDBTesting
|
||||
: lotOccupancyDBLive
|
||||
|
||||
export const backupFolder = 'data/backups'
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
export function handler(_request, response) {
|
||||
response.render('admin-cleanup', {
|
||||
headTitle: 'Database Cleanup'
|
||||
});
|
||||
}
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export function handler(_request, response) {
|
||||
response.render('admin-database', {
|
||||
headTitle: 'Database Maintenance'
|
||||
});
|
||||
}
|
||||
export default handler;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import type { Request, Response } from 'express'
|
||||
|
||||
export function handler(_request: Request, response: Response): void {
|
||||
response.render('admin-cleanup', {
|
||||
headTitle: 'Database Cleanup'
|
||||
response.render('admin-database', {
|
||||
headTitle: 'Database Maintenance'
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import type { Request, Response } from 'express';
|
||||
export declare function handler(_request: Request, response: Response): Promise<void>;
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { backupDatabase } from '../../helpers/functions.database.js';
|
||||
export async function handler(_request, response) {
|
||||
const backupDatabasePath = await backupDatabase();
|
||||
if (typeof backupDatabasePath === 'string') {
|
||||
const backupDatabasePathSplit = backupDatabasePath.split(/[/\\]/g);
|
||||
const fileName = backupDatabasePathSplit[backupDatabasePathSplit.length - 1];
|
||||
response.json({
|
||||
success: true,
|
||||
fileName
|
||||
});
|
||||
}
|
||||
else {
|
||||
response.json({
|
||||
success: false,
|
||||
errorMessage: 'Unable to write backup file.'
|
||||
});
|
||||
}
|
||||
}
|
||||
export default handler;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import type { Request, Response } from 'express'
|
||||
|
||||
import { backupDatabase } from '../../helpers/functions.database.js'
|
||||
|
||||
export async function handler(
|
||||
_request: Request,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
const backupDatabasePath = await backupDatabase()
|
||||
|
||||
if (typeof backupDatabasePath === 'string') {
|
||||
const backupDatabasePathSplit = backupDatabasePath.split(/[/\\]/g)
|
||||
|
||||
const fileName = backupDatabasePathSplit[backupDatabasePathSplit.length - 1]
|
||||
|
||||
response.json({
|
||||
success: true,
|
||||
fileName
|
||||
})
|
||||
} else {
|
||||
response.json({
|
||||
success: false,
|
||||
errorMessage: 'Unable to write backup file.'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
|
@ -0,0 +1 @@
|
|||
export declare const backupDatabase: () => Promise<string | false>;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import fs from 'node:fs/promises';
|
||||
import { lotOccupancyDB as databasePath, backupFolder } from '../data/databasePaths.js';
|
||||
export const backupDatabase = async () => {
|
||||
const databasePathSplit = databasePath.split(/[/\\]/g);
|
||||
const backupDatabasePath = backupFolder +
|
||||
'/' +
|
||||
databasePathSplit[databasePathSplit.length - 1] +
|
||||
'.' +
|
||||
Date.now().toString();
|
||||
try {
|
||||
await fs.copyFile(databasePath, backupDatabasePath);
|
||||
return backupDatabasePath;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import fs from 'node:fs/promises'
|
||||
import {
|
||||
lotOccupancyDB as databasePath,
|
||||
backupFolder
|
||||
} from '../data/databasePaths.js'
|
||||
|
||||
export const backupDatabase = async (): Promise<string | false> => {
|
||||
const databasePathSplit = databasePath.split(/[/\\]/g)
|
||||
|
||||
const backupDatabasePath =
|
||||
backupFolder +
|
||||
'/' +
|
||||
databasePathSplit[databasePathSplit.length - 1] +
|
||||
'.' +
|
||||
Date.now().toString()
|
||||
|
||||
try {
|
||||
await fs.copyFile(databasePath, backupDatabasePath)
|
||||
return backupDatabasePath
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
"use strict";
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion, unicorn/prefer-module */
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
(() => {
|
||||
const los = exports.los;
|
||||
function doCleanup() {
|
||||
cityssm.postJSON(los.urlPrefix + '/admin/doCleanupDatabase', {}, (responseJSON) => {
|
||||
var _a;
|
||||
if (responseJSON.success) {
|
||||
bulmaJS.alert({
|
||||
title: 'Database Cleaned Up Successfully',
|
||||
message: `${responseJSON.inactivedRecordCount} records inactivated,
|
||||
${responseJSON.purgedRecordCount} permanently deleted.`,
|
||||
contextualColorName: 'success'
|
||||
});
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: 'Error Cleaning Database',
|
||||
message: (_a = responseJSON.errorMessage) !== null && _a !== void 0 ? _a : '',
|
||||
contextualColorName: 'danger'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
document
|
||||
.querySelector('#button--cleanupDatabase')
|
||||
.addEventListener('click', () => {
|
||||
bulmaJS.confirm({
|
||||
title: 'Cleanup Database',
|
||||
message: 'Are you sure you want to cleanup up the database?',
|
||||
okButton: {
|
||||
text: 'Yes, Cleanup Database',
|
||||
callbackFunction: doCleanup
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
"use strict";
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion, unicorn/prefer-module */
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
(() => {
|
||||
var _a, _b;
|
||||
const los = exports.los;
|
||||
function doBackup() {
|
||||
cityssm.postJSON(los.urlPrefix + '/admin/doBackupDatabase', {}, (responseJSON) => {
|
||||
var _a;
|
||||
if (responseJSON.success) {
|
||||
bulmaJS.alert({
|
||||
title: 'Database Backed Up Successfully',
|
||||
message: `Backed up to ${responseJSON.fileName}`,
|
||||
contextualColorName: 'success'
|
||||
});
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: 'Error Backing Up Database',
|
||||
message: (_a = responseJSON.errorMessage) !== null && _a !== void 0 ? _a : '',
|
||||
contextualColorName: 'danger'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function doCleanup() {
|
||||
cityssm.postJSON(los.urlPrefix + '/admin/doCleanupDatabase', {}, (responseJSON) => {
|
||||
var _a;
|
||||
if (responseJSON.success) {
|
||||
bulmaJS.alert({
|
||||
title: 'Database Cleaned Up Successfully',
|
||||
message: `${responseJSON.inactivedRecordCount} records inactivated,
|
||||
${responseJSON.purgedRecordCount} permanently deleted.`,
|
||||
contextualColorName: 'success'
|
||||
});
|
||||
}
|
||||
else {
|
||||
bulmaJS.alert({
|
||||
title: 'Error Cleaning Database',
|
||||
message: (_a = responseJSON.errorMessage) !== null && _a !== void 0 ? _a : '',
|
||||
contextualColorName: 'danger'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
(_a = document
|
||||
.querySelector('#button--cleanupDatabase')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => {
|
||||
bulmaJS.confirm({
|
||||
title: 'Cleanup Database',
|
||||
message: 'Are you sure you want to cleanup up the database?',
|
||||
okButton: {
|
||||
text: 'Yes, Cleanup Database',
|
||||
callbackFunction: doCleanup
|
||||
}
|
||||
});
|
||||
});
|
||||
(_b = document
|
||||
.querySelector('#button--backupDatabase')) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {
|
||||
bulmaJS.confirm({
|
||||
title: 'Backup Database',
|
||||
message: 'Are you sure you want to backup up the database?',
|
||||
okButton: {
|
||||
text: 'Yes, Backup Database',
|
||||
callbackFunction: doBackup
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
@ -11,6 +11,32 @@ declare const bulmaJS: BulmaJS
|
|||
;(() => {
|
||||
const los = exports.los as globalTypes.LOS
|
||||
|
||||
function doBackup(): void {
|
||||
cityssm.postJSON(
|
||||
los.urlPrefix + '/admin/doBackupDatabase',
|
||||
{},
|
||||
(responseJSON: {
|
||||
success: boolean
|
||||
errorMessage?: string
|
||||
fileName?: string
|
||||
}) => {
|
||||
if (responseJSON.success) {
|
||||
bulmaJS.alert({
|
||||
title: 'Database Backed Up Successfully',
|
||||
message: `Backed up to ${responseJSON.fileName!}`,
|
||||
contextualColorName: 'success'
|
||||
})
|
||||
} else {
|
||||
bulmaJS.alert({
|
||||
title: 'Error Backing Up Database',
|
||||
message: responseJSON.errorMessage ?? '',
|
||||
contextualColorName: 'danger'
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function doCleanup(): void {
|
||||
cityssm.postJSON(
|
||||
los.urlPrefix + '/admin/doCleanupDatabase',
|
||||
|
|
@ -40,8 +66,8 @@ declare const bulmaJS: BulmaJS
|
|||
}
|
||||
|
||||
document
|
||||
.querySelector('#button--cleanupDatabase')!
|
||||
.addEventListener('click', () => {
|
||||
.querySelector('#button--cleanupDatabase')
|
||||
?.addEventListener('click', () => {
|
||||
bulmaJS.confirm({
|
||||
title: 'Cleanup Database',
|
||||
message: 'Are you sure you want to cleanup up the database?',
|
||||
|
|
@ -51,4 +77,17 @@ declare const bulmaJS: BulmaJS
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
document
|
||||
.querySelector('#button--backupDatabase')
|
||||
?.addEventListener('click', () => {
|
||||
bulmaJS.confirm({
|
||||
title: 'Backup Database',
|
||||
message: 'Are you sure you want to backup up the database?',
|
||||
okButton: {
|
||||
text: 'Yes, Backup Database',
|
||||
callbackFunction: doBackup
|
||||
}
|
||||
})
|
||||
})
|
||||
})()
|
||||
|
|
@ -1 +0,0 @@
|
|||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los;function a(){cityssm.postJSON(e.urlPrefix+"/admin/doCleanupDatabase",{},e=>{var a;e.success?bulmaJS.alert({title:"Database Cleaned Up Successfully",message:`${e.inactivedRecordCount} records inactivated,\n ${e.purgedRecordCount} permanently deleted.`,contextualColorName:"success"}):bulmaJS.alert({title:"Error Cleaning Database",message:null!==(a=e.errorMessage)&&void 0!==a?a:"",contextualColorName:"danger"})})}document.querySelector("#button--cleanupDatabase").addEventListener("click",()=>{bulmaJS.confirm({title:"Cleanup Database",message:"Are you sure you want to cleanup up the database?",okButton:{text:"Yes, Cleanup Database",callbackFunction:a}})})})();
|
||||
|
|
@ -0,0 +1 @@
|
|||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{var e,a;const t=exports.los;function s(){cityssm.postJSON(t.urlPrefix+"/admin/doBackupDatabase",{},e=>{var a;e.success?bulmaJS.alert({title:"Database Backed Up Successfully",message:`Backed up to ${e.fileName}`,contextualColorName:"success"}):bulmaJS.alert({title:"Error Backing Up Database",message:null!==(a=e.errorMessage)&&void 0!==a?a:"",contextualColorName:"danger"})})}function u(){cityssm.postJSON(t.urlPrefix+"/admin/doCleanupDatabase",{},e=>{var a;e.success?bulmaJS.alert({title:"Database Cleaned Up Successfully",message:`${e.inactivedRecordCount} records inactivated,\n ${e.purgedRecordCount} permanently deleted.`,contextualColorName:"success"}):bulmaJS.alert({title:"Error Cleaning Database",message:null!==(a=e.errorMessage)&&void 0!==a?a:"",contextualColorName:"danger"})})}null===(e=document.querySelector("#button--cleanupDatabase"))||void 0===e||e.addEventListener("click",()=>{bulmaJS.confirm({title:"Cleanup Database",message:"Are you sure you want to cleanup up the database?",okButton:{text:"Yes, Cleanup Database",callbackFunction:u}})}),null===(a=document.querySelector("#button--backupDatabase"))||void 0===a||a.addEventListener("click",()=>{bulmaJS.confirm({title:"Backup Database",message:"Are you sure you want to backup up the database?",okButton:{text:"Yes, Backup Database",callbackFunction:s}})})})();
|
||||
|
|
@ -57,7 +57,8 @@ import handler_doUpdateLotOccupantType from '../handlers/admin-post/doUpdateLotO
|
|||
import handler_doMoveLotOccupantTypeUp from '../handlers/admin-post/doMoveLotOccupantTypeUp.js';
|
||||
import handler_doMoveLotOccupantTypeDown from '../handlers/admin-post/doMoveLotOccupantTypeDown.js';
|
||||
import handler_doDeleteLotOccupantType from '../handlers/admin-post/doDeleteLotOccupantType.js';
|
||||
import handler_cleanup from '../handlers/admin-get/cleanup.js';
|
||||
import handler_database from '../handlers/admin-get/database.js';
|
||||
import handler_doBackupDatabase from '../handlers/admin-post/doBackupDatabase.js';
|
||||
import handler_doCleanupDatabase from '../handlers/admin-post/doCleanupDatabase.js';
|
||||
import handler_ntfyStartup from '../handlers/admin-get/ntfyStartup.js';
|
||||
export const router = Router();
|
||||
|
|
@ -119,7 +120,8 @@ router.post('/doUpdateLotOccupantType', handler_doUpdateLotOccupantType);
|
|||
router.post('/doMoveLotOccupantTypeUp', handler_doMoveLotOccupantTypeUp);
|
||||
router.post('/doMoveLotOccupantTypeDown', handler_doMoveLotOccupantTypeDown);
|
||||
router.post('/doDeleteLotOccupantType', handler_doDeleteLotOccupantType);
|
||||
router.get('/cleanup', handler_cleanup);
|
||||
router.get('/database', handler_database);
|
||||
router.post('/doBackupDatabase', handler_doBackupDatabase);
|
||||
router.post('/doCleanupDatabase', handler_doCleanupDatabase);
|
||||
router.get('/ntfyStartup', handler_ntfyStartup);
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Router, RequestHandler } from 'express'
|
||||
import { Router, type RequestHandler } from 'express'
|
||||
|
||||
// Fee Management
|
||||
|
||||
|
|
@ -81,9 +81,10 @@ import handler_doMoveLotOccupantTypeUp from '../handlers/admin-post/doMoveLotOcc
|
|||
import handler_doMoveLotOccupantTypeDown from '../handlers/admin-post/doMoveLotOccupantTypeDown.js'
|
||||
import handler_doDeleteLotOccupantType from '../handlers/admin-post/doDeleteLotOccupantType.js'
|
||||
|
||||
// Cleanup
|
||||
// Database Maintenance
|
||||
|
||||
import handler_cleanup from '../handlers/admin-get/cleanup.js'
|
||||
import handler_database from '../handlers/admin-get/database.js'
|
||||
import handler_doBackupDatabase from '../handlers/admin-post/doBackupDatabase.js'
|
||||
import handler_doCleanupDatabase from '../handlers/admin-post/doCleanupDatabase.js'
|
||||
|
||||
// Ntfy Startup
|
||||
|
|
@ -346,9 +347,11 @@ router.post(
|
|||
handler_doDeleteLotOccupantType as RequestHandler
|
||||
)
|
||||
|
||||
// Cleanup
|
||||
// Database Maintenance
|
||||
|
||||
router.get('/cleanup', handler_cleanup)
|
||||
router.get('/database', handler_database)
|
||||
|
||||
router.post('/doBackupDatabase', handler_doBackupDatabase as RequestHandler)
|
||||
|
||||
router.post('/doCleanupDatabase', handler_doCleanupDatabase as RequestHandler)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"strictNullChecks": true
|
||||
},
|
||||
"files": [
|
||||
"public-typescript/adminCleanup.ts",
|
||||
"public-typescript/adminDatabase.ts",
|
||||
"public-typescript/adminFees.ts",
|
||||
"public-typescript/adminLotTypes.ts",
|
||||
"public-typescript/adminOccupancyTypes.ts",
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="<%= (headTitle === "Database Cleanup" ? "is-active" : "") %>" href="<%= urlPrefix %>/admin/cleanup">
|
||||
<span class="icon"><i class="fas fa-fw fa-broom" aria-hidden="true"></i></span>
|
||||
<span>Database Cleanup</span>
|
||||
<a class="<%= (headTitle === "Database Maintenance" ? "is-active" : "") %>" href="<%= urlPrefix %>/admin/database">
|
||||
<span class="icon"><i class="fas fa-fw fa-database" aria-hidden="true"></i></span>
|
||||
<span>Database Maintenance</span>
|
||||
</a>
|
||||
</li>
|
||||
<% if (configFunctions.getProperty("application.ntfyStartup")) { %>
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
<%- include('_header'); -%>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column is-3 is-hidden-mobile">
|
||||
<%- include('_menu-admin'); -%>
|
||||
</div>
|
||||
<div class="column">
|
||||
<nav class="breadcrumb">
|
||||
<ul>
|
||||
<li><a href="<%= urlPrefix %>/dashboard">Home</a></li>
|
||||
<li>
|
||||
<a href="#">
|
||||
|
||||
<span class="icon is-small"><i class="fas fa-cog" aria-hidden="true"></i></span>
|
||||
<span>Administrator Tools</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="is-active">
|
||||
<a href="#" aria-current="page">
|
||||
Database Cleanup
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<h1 class="title is-1">
|
||||
Database Cleanup
|
||||
</h1>
|
||||
|
||||
<div class="message is-warning">
|
||||
<div class="message-header">
|
||||
Important Note
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<p>
|
||||
When records are deleted in this application, they are not removed entirely.
|
||||
This gives systems administrators the ability to recover deleted records.
|
||||
This also can leave a small amount of garbage behind in the database.
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
This process permanently deletes records that have already been deleted over <%= configFunctions.getProperty("settings.adminCleanup.recordDeleteAgeDays") %> days ago.
|
||||
Note that no active records will be affected by the cleanup process.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="has-text-right">
|
||||
<button class="button is-success" id="button--cleanupDatabase" data-cy="cleanup" type="button">
|
||||
<span class="icon"><i class="fas fa-broom" aria-hidden="true"></i></span>
|
||||
<span>Cleanup Database</span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include('_footerA'); -%>
|
||||
|
||||
<script src="<%= urlPrefix %>/javascripts/adminCleanup.min.js"></script>
|
||||
|
||||
<%- include('_footerB'); -%>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<%- include('_header'); -%>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column is-3 is-hidden-mobile">
|
||||
<%- include('_menu-admin'); -%>
|
||||
</div>
|
||||
<div class="column">
|
||||
<nav class="breadcrumb">
|
||||
<ul>
|
||||
<li><a href="<%= urlPrefix %>/dashboard">Home</a></li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<span class="icon is-small"><i class="fas fa-cog" aria-hidden="true"></i></span>
|
||||
<span>Administrator Tools</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="is-active">
|
||||
<a href="#" aria-current="page">
|
||||
Database Maintenance
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<h1 class="title is-1">
|
||||
Database Maintenance
|
||||
</h1>
|
||||
|
||||
<h2 class="title is-3">
|
||||
Database Backup
|
||||
</h2>
|
||||
|
||||
<div class="message is-info">
|
||||
<div class="message-body">
|
||||
<p>
|
||||
Before making significant changes to the records in the database,
|
||||
it is a good idea to back up first!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="has-text-right">
|
||||
<button class="button is-success" id="button--backupDatabase" data-cy="backup" type="button">
|
||||
<span class="icon"><i class="fas fa-save" aria-hidden="true"></i></span>
|
||||
<span>Backup Database</span>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<h2 class="title is-3">
|
||||
Database Cleanup
|
||||
</h2>
|
||||
|
||||
<div class="message is-warning">
|
||||
<div class="message-header">
|
||||
Important Note about Cleanup
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<p>
|
||||
When records are deleted in this application, they are not removed entirely.
|
||||
This gives systems administrators the ability to recover deleted records.
|
||||
This also can leave a small amount of garbage behind in the database.
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
This process permanently deletes records that have already been deleted over
|
||||
<%= configFunctions.getProperty("settings.adminCleanup.recordDeleteAgeDays") %> days ago.
|
||||
Note that no active records will be affected by the cleanup process.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="has-text-right">
|
||||
<button class="button is-success" id="button--cleanupDatabase" data-cy="cleanup" type="button">
|
||||
<span class="icon"><i class="fas fa-broom" aria-hidden="true"></i></span>
|
||||
<span>Cleanup Database</span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include('_footerA'); -%>
|
||||
|
||||
<script src="<%= urlPrefix %>/javascripts/adminDatabase.min.js"></script>
|
||||
|
||||
<%- include('_footerB'); -%>
|
||||
|
|
@ -365,13 +365,14 @@
|
|||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<i class="fas fa-3x fa-fw fa-broom" aria-hidden="true"></i>
|
||||
<i class="fas fa-3x fa-fw fa-database" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="media-content has-text-black">
|
||||
<h2 class="title is-4 is-marginless">
|
||||
<a href="<%= urlPrefix %>/admin/cleanup">Database Cleanup</a>
|
||||
<a href="<%= urlPrefix %>/admin/database">Database Maintenance</a>
|
||||
</h2>
|
||||
<p>
|
||||
Backup the database before making significant updates.
|
||||
Permanently delete records that have been previously deleted from the database.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue