admin/settings: maintenance page, show database size
This commit is contained in:
parent
3dfcd542bf
commit
ff6c910b2f
13 changed files with 203 additions and 0 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -1259,6 +1259,12 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "human_bytes"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27e2b089f28ad15597b48d8c0a8fe94eeb1c1cb26ca99b6f66ac9582ae10c5e6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humansize"
|
name = "humansize"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
|
|
@ -2959,6 +2965,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"database",
|
"database",
|
||||||
|
"human_bytes",
|
||||||
"id",
|
"id",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"url",
|
"url",
|
||||||
|
|
|
||||||
2
crates/database/queries/settings/database_size.sql
Normal file
2
crates/database/queries/settings/database_size.sql
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
select page_count * page_size
|
||||||
|
FROM pragma_page_count(), pragma_page_size();
|
||||||
|
|
@ -1598,6 +1598,24 @@
|
||||||
},
|
},
|
||||||
"query": "select id,\n created_at as \"created_at: DateTime<Utc>\",\n updated_at as \"updated_at: DateTime<Utc>\",\n label,\n redirect_uri,\n secret,\n is_confidential as \"is_confidential: bool\",\n is_archived as \"is_archived: bool\"\nfrom apps\n\nwhere id is (?)\n"
|
"query": "select id,\n created_at as \"created_at: DateTime<Utc>\",\n updated_at as \"updated_at: DateTime<Utc>\",\n label,\n redirect_uri,\n secret,\n is_confidential as \"is_confidential: bool\",\n is_archived as \"is_archived: bool\"\nfrom apps\n\nwhere id is (?)\n"
|
||||||
},
|
},
|
||||||
|
"e977ca16c7bd7ec4125725ff5e42d3c547634e2b608d6be91814bce657e07b65": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "page_count * page_size",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
null
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "select page_count * page_size\nFROM pragma_page_count(), pragma_page_size();"
|
||||||
|
},
|
||||||
"eaf0744f65a1de803fa8cc21b67bad4bdf22760d431265cf97b911e6456b2fd8": {
|
"eaf0744f65a1de803fa8cc21b67bad4bdf22760d431265cf97b911e6456b2fd8": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,13 @@ impl Settings {
|
||||||
.map_err(handle_error)
|
.map_err(handle_error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn database_size(conn: impl SqliteExecutor<'_>) -> Result<Option<i32>, Error> {
|
||||||
|
sqlx::query_file_scalar!("queries/settings/database_size.sql")
|
||||||
|
.fetch_one(conn)
|
||||||
|
.await
|
||||||
|
.map_err(handle_error)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_business_name(
|
pub async fn set_business_name(
|
||||||
conn: impl SqliteExecutor<'_>,
|
conn: impl SqliteExecutor<'_>,
|
||||||
value: Option<&str>,
|
value: Option<&str>,
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,10 @@ impl AdminMenu {
|
||||||
label: "Security",
|
label: "Security",
|
||||||
link: uri!(routes::admin::settings::settings_security).to_string(),
|
link: uri!(routes::admin::settings::settings_security).to_string(),
|
||||||
},
|
},
|
||||||
|
SubItem {
|
||||||
|
label: "Maintenance",
|
||||||
|
link: uri!(routes::admin::settings::settings_maintenance).to_string(),
|
||||||
|
},
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ pub enum Page {
|
||||||
AdminDashboard(AdminDashboard),
|
AdminDashboard(AdminDashboard),
|
||||||
AdminSettingsBranding(AdminSettingsBranding),
|
AdminSettingsBranding(AdminSettingsBranding),
|
||||||
AdminSettingsSecurity(AdminSettingsSecurity),
|
AdminSettingsSecurity(AdminSettingsSecurity),
|
||||||
|
AdminSettingsMaintenance(AdminSettingsMaintenance),
|
||||||
AdminAppsList(AdminAppsList),
|
AdminAppsList(AdminAppsList),
|
||||||
AdminAppsNew(AdminAppsNew),
|
AdminAppsNew(AdminAppsNew),
|
||||||
AdminAppsView(AdminAppsView),
|
AdminAppsView(AdminAppsView),
|
||||||
|
|
@ -45,6 +46,7 @@ impl Page {
|
||||||
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
||||||
Page::AdminSettingsBranding(_) => "pages/admin/settings/branding",
|
Page::AdminSettingsBranding(_) => "pages/admin/settings/branding",
|
||||||
Page::AdminSettingsSecurity(_) => "pages/admin/settings/security",
|
Page::AdminSettingsSecurity(_) => "pages/admin/settings/security",
|
||||||
|
Page::AdminSettingsMaintenance(_) => "pages/admin/settings/maintenance",
|
||||||
Page::AdminAppsList(_) => "pages/admin/apps/list",
|
Page::AdminAppsList(_) => "pages/admin/apps/list",
|
||||||
Page::AdminAppsNew(_) => "pages/admin/apps/new",
|
Page::AdminAppsNew(_) => "pages/admin/apps/new",
|
||||||
Page::AdminAppsView(_) => "pages/admin/apps/view",
|
Page::AdminAppsView(_) => "pages/admin/apps/view",
|
||||||
|
|
@ -72,6 +74,7 @@ impl Page {
|
||||||
Page::AdminDashboard(_) => "Admin dashboard",
|
Page::AdminDashboard(_) => "Admin dashboard",
|
||||||
Page::AdminSettingsBranding(_) => "Server branding",
|
Page::AdminSettingsBranding(_) => "Server branding",
|
||||||
Page::AdminSettingsSecurity(_) => "Server security",
|
Page::AdminSettingsSecurity(_) => "Server security",
|
||||||
|
Page::AdminSettingsMaintenance(_) => "Server maintenance",
|
||||||
Page::AdminAppsList(_) => "Applications",
|
Page::AdminAppsList(_) => "Applications",
|
||||||
Page::AdminAppsNew(_) => "New application",
|
Page::AdminAppsNew(_) => "New application",
|
||||||
Page::AdminAppsView(_) => "Application info",
|
Page::AdminAppsView(_) => "Application info",
|
||||||
|
|
@ -101,6 +104,7 @@ impl Page {
|
||||||
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
||||||
Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()),
|
Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()),
|
||||||
Page::AdminSettingsSecurity(_) => Some(AdminMenu::Settings.into()),
|
Page::AdminSettingsSecurity(_) => Some(AdminMenu::Settings.into()),
|
||||||
|
Page::AdminSettingsMaintenance(_) => Some(AdminMenu::Settings.into()),
|
||||||
Page::AdminAppsList(_) => Some(AdminMenu::Apps.into()),
|
Page::AdminAppsList(_) => Some(AdminMenu::Apps.into()),
|
||||||
Page::AdminAppsNew(_) => Some(AdminMenu::Apps.into()),
|
Page::AdminAppsNew(_) => Some(AdminMenu::Apps.into()),
|
||||||
Page::AdminAppsView(_) => Some(AdminMenu::Apps.into()),
|
Page::AdminAppsView(_) => Some(AdminMenu::Apps.into()),
|
||||||
|
|
@ -128,6 +132,7 @@ impl Page {
|
||||||
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
||||||
Page::AdminSettingsBranding(branding) => Box::new(branding),
|
Page::AdminSettingsBranding(branding) => Box::new(branding),
|
||||||
Page::AdminSettingsSecurity(security) => Box::new(security),
|
Page::AdminSettingsSecurity(security) => Box::new(security),
|
||||||
|
Page::AdminSettingsMaintenance(maintenance) => Box::new(maintenance),
|
||||||
Page::AdminAppsList(list) => Box::new(list),
|
Page::AdminAppsList(list) => Box::new(list),
|
||||||
Page::AdminAppsNew(new) => Box::new(new),
|
Page::AdminAppsNew(new) => Box::new(new),
|
||||||
Page::AdminAppsView(view) => Box::new(view),
|
Page::AdminAppsView(view) => Box::new(view),
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ pub fn routes() -> Vec<Route> {
|
||||||
settings_update_branding,
|
settings_update_branding,
|
||||||
settings_security,
|
settings_security,
|
||||||
settings_security_form,
|
settings_security_form,
|
||||||
|
settings_maintenance,
|
||||||
admin_apps_list,
|
admin_apps_list,
|
||||||
admin_apps_new,
|
admin_apps_new,
|
||||||
admin_apps_new_form,
|
admin_apps_new_form,
|
||||||
|
|
@ -65,6 +66,14 @@ pub mod content {
|
||||||
pub user: JwtClaims,
|
pub user: JwtClaims,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AdminSettingsMaintenance {
|
||||||
|
pub user: JwtClaims,
|
||||||
|
pub database_size: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
||||||
|
|
@ -185,3 +185,27 @@ pub async fn settings_security_form(
|
||||||
flash_message,
|
flash_message,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/admin/settings/maintenance")]
|
||||||
|
pub async fn settings_maintenance(
|
||||||
|
mut db: Connection<Database>,
|
||||||
|
admin: JwtAdmin,
|
||||||
|
flash: Option<FlashMessage<'_>>,
|
||||||
|
) -> Result<Template> {
|
||||||
|
let mut transaction = db.begin().await?;
|
||||||
|
|
||||||
|
let database_size = Settings::database_size(&mut transaction)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| Error::internal_server_error("Failed to get database size"))?;
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
|
let page = Page::AdminSettingsMaintenance(super::content::AdminSettingsMaintenance {
|
||||||
|
user: admin.0,
|
||||||
|
database_size,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(flash
|
||||||
|
.map(|flash| Page::with_flash(page.clone(), flash))
|
||||||
|
.unwrap_or_else(|| page.into()))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
class="list-group-item list-group-item-action d-flex align-items-center active">Branding</a>
|
class="list-group-item list-group-item-action d-flex align-items-center active">Branding</a>
|
||||||
<a href="./security"
|
<a href="./security"
|
||||||
class="list-group-item list-group-item-action d-flex align-items-center">Security</a>
|
class="list-group-item list-group-item-action d-flex align-items-center">Security</a>
|
||||||
|
<a href="./maintenance"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center">Maintenance</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
{% extends "shell" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<!-- Page header -->
|
||||||
|
<div class="page-header d-print-none">
|
||||||
|
<div class="container-xl">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col">
|
||||||
|
<h2 class="page-title">
|
||||||
|
Server settings
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Page body -->
|
||||||
|
<div class="page-body">
|
||||||
|
<div class="container-xl">
|
||||||
|
|
||||||
|
{% if flash %}
|
||||||
|
<div class="alert alert-{{flash.0}}" role="alert">
|
||||||
|
<h4 class="alert-title">{{ flash.1 | safe }}</h4>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="row g-0">
|
||||||
|
<div class="col-3 d-none d-md-block border-end">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="list-group list-group-transparent">
|
||||||
|
<a href="./branding"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center">Branding</a>
|
||||||
|
<a href="./security"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center">Security</a>
|
||||||
|
<a href="./maintenance"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center active">Maintenance</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col d-flex flex-column">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="mb-4">Maintenance</h2>
|
||||||
|
|
||||||
|
<h3 class="card-title">Database size</h3>
|
||||||
|
<p>{{ database_size }}</p>
|
||||||
|
|
||||||
|
<div class="row align-items-center mb-4">
|
||||||
|
|
||||||
|
<!-- Clean database -->
|
||||||
|
<div class="col-auto">
|
||||||
|
<a class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#modal-clean-database">
|
||||||
|
Clean database
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Clean database modal -->
|
||||||
|
<div class="modal modal-blur" tabindex="-1" id="modal-clean-database">
|
||||||
|
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
|
||||||
|
<div class="modal-status bg-danger"></div>
|
||||||
|
|
||||||
|
<div class="modal-body text-center py-4">
|
||||||
|
|
||||||
|
<div class="text-danger mb-2">
|
||||||
|
{% include "icons/alert-triangle-large" %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Do you want to clean the database?</h3>
|
||||||
|
<div class="mt-2">
|
||||||
|
This action will <strong>delete</strong> the following:
|
||||||
|
</div>
|
||||||
|
<ul class="list-inline mt-1">
|
||||||
|
<li>Authorization codes</li>
|
||||||
|
<li>Refresh tokens</li>
|
||||||
|
<li>TOTP requests</li>
|
||||||
|
</ul>
|
||||||
|
<div class="mt-2">
|
||||||
|
This action will be permanent.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<div class="w-100">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<a href="#" class="btn w-100" data-bs-dismiss="modal">Cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
<form action="" method="post">
|
||||||
|
<button type="submit" name="clean" value="true" class="btn btn-danger w-100">
|
||||||
|
Clean database
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -32,6 +32,8 @@
|
||||||
class="list-group-item list-group-item-action d-flex align-items-center">Branding</a>
|
class="list-group-item list-group-item-action d-flex align-items-center">Branding</a>
|
||||||
<a href="./security"
|
<a href="./security"
|
||||||
class="list-group-item list-group-item-action d-flex align-items-center active">Security</a>
|
class="list-group-item list-group-item-action d-flex align-items-center active">Security</a>
|
||||||
|
<a href="./maintenance"
|
||||||
|
class="list-group-item list-group-item-action d-flex align-items-center">Maintenance</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,4 @@ id = { path = "../id" }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
human_bytes = { version = "0.4.1", default-features = false }
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::error::Error;
|
||||||
use crate::Settings;
|
use crate::Settings;
|
||||||
use database::sqlx::SqliteExecutor;
|
use database::sqlx::SqliteExecutor;
|
||||||
use database::Settings as DatabaseSettings;
|
use database::Settings as DatabaseSettings;
|
||||||
|
use human_bytes::human_bytes;
|
||||||
use id::UserID;
|
use id::UserID;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
@ -34,6 +35,12 @@ impl Settings {
|
||||||
Ok(DatabaseSettings::get(conn).await.map(Self::from)?)
|
Ok(DatabaseSettings::get(conn).await.map(Self::from)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn database_size(conn: impl SqliteExecutor<'_>) -> Result<Option<String>, Error> {
|
||||||
|
Ok(DatabaseSettings::database_size(conn)
|
||||||
|
.await?
|
||||||
|
.map(human_bytes))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_business_name(
|
pub async fn set_business_name(
|
||||||
conn: impl SqliteExecutor<'_>,
|
conn: impl SqliteExecutor<'_>,
|
||||||
business_name: &str,
|
business_name: &str,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue