use crate::models::{ _entities::{audio_albums, audio_tracks, audit_logs, blog_articles, users}, users as users_model, }; use loco_rs::prelude::*; use sea_orm::{EntityTrait, PaginatorTrait}; use serde::Serialize; #[derive(Debug, Serialize)] struct DashboardResponse { users: u64, blog_articles: u64, audio_albums: u64, audio_tracks: u64, audit_logs: u64, } pub(crate) fn admin_email(ctx: &AppContext) -> Option<&str> { ctx.config .settings .as_ref() .and_then(|settings| settings.get("admin_email")) .and_then(|email| email.as_str()) } pub(crate) fn is_admin(ctx: &AppContext, user: &users::Model) -> bool { admin_email(ctx).is_some_and(|email| user.email.eq_ignore_ascii_case(email)) } pub(crate) async fn current_admin(auth: auth::JWT, ctx: &AppContext) -> Result { let user = users_model::Model::find_by_pid(&ctx.db, &auth.claims.pid).await?; if !is_admin(ctx, &user) { return unauthorized("admin only"); } Ok(user) } #[debug_handler] async fn dashboard(auth: auth::JWT, State(ctx): State) -> Result { current_admin(auth, &ctx).await?; format::json(DashboardResponse { users: users::Entity::find().count(&ctx.db).await?, blog_articles: blog_articles::Entity::find().count(&ctx.db).await?, audio_albums: audio_albums::Entity::find().count(&ctx.db).await?, audio_tracks: audio_tracks::Entity::find().count(&ctx.db).await?, audit_logs: audit_logs::Entity::find().count(&ctx.db).await?, }) } pub fn routes() -> Routes { Routes::new() .prefix("/api/admin") .add("/dashboard", get(dashboard)) }