diff --git a/src/api/admin.rs b/src/api/admin.rs index 680c8804..165387bf 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -9,7 +9,7 @@ use rocket_contrib::json::Json; use crate::api::{ApiResult, EmptyResult, JsonResult}; use crate::auth::{decode_admin, encode_jwt, generate_admin_claims, ClientIp}; use crate::config::ConfigBuilder; -use crate::db::{models::*, DbConn}; +use crate::db::{models::*, DbConn, backup_database}; use crate::error::Error; use crate::mail; use crate::CONFIG; @@ -30,6 +30,7 @@ pub fn routes() -> Vec { update_revision_users, post_config, delete_config, + backup_db, ] } @@ -204,6 +205,11 @@ fn delete_config(_token: AdminToken) -> EmptyResult { CONFIG.delete_user_config() } +#[post("/config/backup_db")] +fn backup_db(_token: AdminToken) -> EmptyResult { + backup_database() +} + pub struct AdminToken {} impl<'a, 'r> FromRequest<'a, 'r> for AdminToken { diff --git a/src/db/mod.rs b/src/db/mod.rs index 54ecfb19..38bd7567 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -9,6 +9,11 @@ use rocket::http::Status; use rocket::request::{self, FromRequest}; use rocket::{Outcome, Request, State}; +use std::process::Command; +use chrono::prelude::*; +use crate::error::Error; + + use crate::CONFIG; /// An alias to the database connection used @@ -34,6 +39,21 @@ pub fn get_connection() -> Result { Connection::establish(&CONFIG.database_url()) } +/// Creates a back-up of the database using sqlite3 +pub fn backup_database() -> Result<(), Error> { + let now: DateTime = Utc::now(); + let file_date = String::from(now.format("%Y%m%d").to_string()); + let backup_command: String = format!("{}{}{}", ".backup 'db_", file_date, ".sqlite3'"); + + Command::new("sqlite3") + .current_dir("./data") + .args(&["db.sqlite3", &backup_command]) + .output() + .expect("Can't open database, sqlite3 is not available, make sure it's installed and available on the PATH"); + + Ok(()) +} + /// Attempts to retrieve a single connection from the managed database pool. If /// no pool is currently managed, fails with an `InternalServerError` status. If /// no connections are available, fails with a `ServiceUnavailable` status. diff --git a/src/static/templates/admin/page.hbs b/src/static/templates/admin/page.hbs index d558ee2b..1cab7634 100644 --- a/src/static/templates/admin/page.hbs +++ b/src/static/templates/admin/page.hbs @@ -154,6 +154,17 @@ {{/unless}} {{/each}} {{/each}} + + + +
+
+
+
+ NOTE: A local installation of sqlite3 is required for this section to work. +
+
@@ -268,6 +279,12 @@ return false; } + function backupDatabase() { + _post("/admin/config/backup_db", + "Backup created successfully", + "Error creating backup"); + return false; + } function masterCheck(check_id, inputs_query) { function toggleEnabled(check_id, inputs_query, enabled) { $(inputs_query).prop("disabled", !enabled)