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
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"
|
||||
},
|
||||
"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": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@ impl Settings {
|
|||
.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(
|
||||
conn: impl SqliteExecutor<'_>,
|
||||
value: Option<&str>,
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ impl AdminMenu {
|
|||
label: "Security",
|
||||
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),
|
||||
AdminSettingsBranding(AdminSettingsBranding),
|
||||
AdminSettingsSecurity(AdminSettingsSecurity),
|
||||
AdminSettingsMaintenance(AdminSettingsMaintenance),
|
||||
AdminAppsList(AdminAppsList),
|
||||
AdminAppsNew(AdminAppsNew),
|
||||
AdminAppsView(AdminAppsView),
|
||||
|
|
@ -45,6 +46,7 @@ impl Page {
|
|||
Page::AdminDashboard(_) => "pages/admin/dashboard",
|
||||
Page::AdminSettingsBranding(_) => "pages/admin/settings/branding",
|
||||
Page::AdminSettingsSecurity(_) => "pages/admin/settings/security",
|
||||
Page::AdminSettingsMaintenance(_) => "pages/admin/settings/maintenance",
|
||||
Page::AdminAppsList(_) => "pages/admin/apps/list",
|
||||
Page::AdminAppsNew(_) => "pages/admin/apps/new",
|
||||
Page::AdminAppsView(_) => "pages/admin/apps/view",
|
||||
|
|
@ -72,6 +74,7 @@ impl Page {
|
|||
Page::AdminDashboard(_) => "Admin dashboard",
|
||||
Page::AdminSettingsBranding(_) => "Server branding",
|
||||
Page::AdminSettingsSecurity(_) => "Server security",
|
||||
Page::AdminSettingsMaintenance(_) => "Server maintenance",
|
||||
Page::AdminAppsList(_) => "Applications",
|
||||
Page::AdminAppsNew(_) => "New application",
|
||||
Page::AdminAppsView(_) => "Application info",
|
||||
|
|
@ -101,6 +104,7 @@ impl Page {
|
|||
Page::AdminDashboard(_) => Some(AdminMenu::Dashboard.into()),
|
||||
Page::AdminSettingsBranding(_) => Some(AdminMenu::Settings.into()),
|
||||
Page::AdminSettingsSecurity(_) => Some(AdminMenu::Settings.into()),
|
||||
Page::AdminSettingsMaintenance(_) => Some(AdminMenu::Settings.into()),
|
||||
Page::AdminAppsList(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::AdminAppsNew(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::AdminAppsView(_) => Some(AdminMenu::Apps.into()),
|
||||
|
|
@ -128,6 +132,7 @@ impl Page {
|
|||
Page::AdminDashboard(dashboard) => Box::new(dashboard),
|
||||
Page::AdminSettingsBranding(branding) => Box::new(branding),
|
||||
Page::AdminSettingsSecurity(security) => Box::new(security),
|
||||
Page::AdminSettingsMaintenance(maintenance) => Box::new(maintenance),
|
||||
Page::AdminAppsList(list) => Box::new(list),
|
||||
Page::AdminAppsNew(new) => Box::new(new),
|
||||
Page::AdminAppsView(view) => Box::new(view),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ pub fn routes() -> Vec<Route> {
|
|||
settings_update_branding,
|
||||
settings_security,
|
||||
settings_security_form,
|
||||
settings_maintenance,
|
||||
admin_apps_list,
|
||||
admin_apps_new,
|
||||
admin_apps_new_form,
|
||||
|
|
@ -65,6 +66,14 @@ pub mod content {
|
|||
pub user: JwtClaims,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[derive(Clone)]
|
||||
pub struct AdminSettingsMaintenance {
|
||||
pub user: JwtClaims,
|
||||
pub database_size: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[derive(Clone)]
|
||||
|
|
|
|||
|
|
@ -185,3 +185,27 @@ pub async fn settings_security_form(
|
|||
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>
|
||||
<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">Maintenance</a>
|
||||
</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>
|
||||
<a href="./security"
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@ id = { path = "../id" }
|
|||
thiserror = { workspace = true }
|
||||
chrono = { 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 database::sqlx::SqliteExecutor;
|
||||
use database::Settings as DatabaseSettings;
|
||||
use human_bytes::human_bytes;
|
||||
use id::UserID;
|
||||
use url::Url;
|
||||
|
||||
|
|
@ -34,6 +35,12 @@ impl Settings {
|
|||
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(
|
||||
conn: impl SqliteExecutor<'_>,
|
||||
business_name: &str,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue