From ce5effc0bf3ce92a581be7f566eb1b0787e2f027 Mon Sep 17 00:00:00 2001 From: Per Stark Date: Thu, 23 Jan 2025 14:35:13 +0100 Subject: [PATCH] feat: admin panel --- src/server/routes/html/admin_panel.rs | 13 ++++++-- src/storage/types/analytics.rs | 31 ++++++++++++++++++- templates/auth/account_settings.html | 6 ++-- templates/auth/admin_panel.html | 43 ++++++++++++++++++++++----- templates/auth/signup_form.html | 2 +- templates/body_base.html | 2 ++ 6 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/server/routes/html/admin_panel.rs b/src/server/routes/html/admin_panel.rs index e4a4475..b4a91e4 100644 --- a/src/server/routes/html/admin_panel.rs +++ b/src/server/routes/html/admin_panel.rs @@ -18,7 +18,8 @@ use crate::{ page_data!(AdminPanelData, "auth/admin_panel.html", { user: User, settings: SystemSettings, - analytics: Analytics + analytics: Analytics, + users: i64, }); pub async fn show_admin_panel( @@ -27,23 +28,29 @@ pub async fn show_admin_panel( ) -> Result { // Early return if the user is not authenticated let user = match auth.current_user { - Some(user) => user, - None => return Ok(Redirect::to("/").into_response()), + Some(user) if user.admin => user, + _ => return Ok(Redirect::to("/").into_response()), }; let settings = SystemSettings::get_current(&state.surreal_db_client) .await .map_err(|e| HtmlError::new(e, state.templates.clone()))?; + let analytics = Analytics::get_current(&state.surreal_db_client) .await .map_err(|e| HtmlError::new(e, state.templates.clone()))?; + let users_count = Analytics::get_users_amount(&state.surreal_db_client) + .await + .map_err(|e| HtmlError::new(e, state.templates.clone()))?; + let output = render_template( AdminPanelData::template_name(), AdminPanelData { user, settings, analytics, + users: users_count, }, state.templates.clone(), )?; diff --git a/src/storage/types/analytics.rs b/src/storage/types/analytics.rs index 0c0c4f5..5ee97e4 100644 --- a/src/storage/types/analytics.rs +++ b/src/storage/types/analytics.rs @@ -1,5 +1,6 @@ -use crate::storage::types::file_info::deserialize_flexible_id; +use crate::storage::types::{file_info::deserialize_flexible_id, user::User, StoredObject}; use serde::{Deserialize, Serialize}; +use tracing::info; use crate::{error::AppError, storage::db::SurrealDbClient}; @@ -7,6 +8,7 @@ use crate::{error::AppError, storage::db::SurrealDbClient}; pub struct Analytics { #[serde(deserialize_with = "deserialize_flexible_id")] pub id: String, + pub page_loads: i64, pub visitors: i64, } @@ -20,6 +22,7 @@ impl Analytics { .content(Analytics { id: "current".to_string(), visitors: 0, + page_loads: 0, }) .await?; @@ -47,4 +50,30 @@ impl Analytics { updated.ok_or(AppError::Validation("Failed to update analytics".into())) } + + pub async fn increment_page_loads(db: &SurrealDbClient) -> Result { + let updated: Option = db + .client + .query("UPDATE type::thing('analytics', 'current') SET page_loads += 1 RETURN AFTER") + .await? + .take(0)?; + + updated.ok_or(AppError::Validation("Failed to update analytics".into())) + } + + pub async fn get_users_amount(db: &SurrealDbClient) -> Result { + #[derive(Debug, Deserialize)] + struct CountResult { + count: i64, + } + + let result: Option = db + .client + .query("SELECT count() as count FROM type::table($table) GROUP ALL") + .bind(("table", User::table_name())) + .await? + .take(0)?; + + Ok(result.map(|r| r.count).unwrap_or(0)) + } } diff --git a/templates/auth/account_settings.html b/templates/auth/account_settings.html index e2a2b43..efe1700 100644 --- a/templates/auth/account_settings.html +++ b/templates/auth/account_settings.html @@ -11,7 +11,7 @@ - -
+