//! Platform admin handlers. use axum::{ extract::{Path, Query}, http::StatusCode, response::{IntoResponse, Redirect, Response}, Form, }; use tower_sessions::Session; use crate::auth::PlatformAdmin; use crate::csrf; use crate::templates::*; use crate::AppState; use mt_core::types::ModAction; use super::{log_mod_action, parse_uuid, AdminSearchQuery, SuspendForm}; #[tracing::instrument(skip_all)] pub(super) async fn admin_dashboard( axum::extract::State(state): axum::extract::State, session: Session, PlatformAdmin(admin): PlatformAdmin, Query(query): Query, ) -> Result { let csrf_token = Some(csrf::get_or_create_token(&session).await); let communities = mt_db::queries::list_all_communities(&state.db) .await .map_err(|e| { tracing::error!(error = ?e, "db error listing communities"); StatusCode::INTERNAL_SERVER_ERROR.into_response() })? .into_iter() .map(|c| AdminCommunityViewRow { id: c.id.to_string(), name: c.name, slug: c.slug, is_suspended: c.suspended_at.is_some(), suspension_reason: c.suspension_reason, }) .collect(); let search_query = query.q.unwrap_or_default(); let users = if !search_query.is_empty() { mt_db::queries::search_users(&state.db, &search_query) .await .map_err(|e| { tracing::error!(error = ?e, "db error searching users"); StatusCode::INTERNAL_SERVER_ERROR.into_response() })? .into_iter() .map(|u| AdminUserViewRow { id: u.id.to_string(), username: u.username, display_name: u.display_name, is_suspended: u.suspended_at.is_some(), suspension_reason: u.suspension_reason, }) .collect() } else { vec![] }; Ok(AdminDashboardTemplate { csrf_token, session_user: Some(TemplateSessionUser { is_platform_admin: true, username: admin.username, }), mnw_base_url: state.config.mnw_base_url.clone(), communities, users, search_query, }) } #[tracing::instrument(skip_all)] pub(super) async fn suspend_community_handler( axum::extract::State(state): axum::extract::State, PlatformAdmin(admin): PlatformAdmin, Path(id): Path, Form(form): Form, ) -> Result { let community_id = parse_uuid(&id)?; let reason = form.reason.as_deref().filter(|r| !r.trim().is_empty()); mt_db::mutations::suspend_community(&state.db, community_id, reason) .await .map_err(|e| { tracing::error!(error = ?e, "db error suspending community"); StatusCode::INTERNAL_SERVER_ERROR.into_response() })?; log_mod_action( &state.db, None, admin.user_id, ModAction::SuspendCommunity, None, Some(community_id), reason, ).await; Ok(Redirect::to("/_admin?toast=Community+suspended")) } #[tracing::instrument(skip_all)] pub(super) async fn unsuspend_community_handler( axum::extract::State(state): axum::extract::State, PlatformAdmin(admin): PlatformAdmin, Path(id): Path, ) -> Result { let community_id = parse_uuid(&id)?; mt_db::mutations::unsuspend_community(&state.db, community_id) .await .map_err(|e| { tracing::error!(error = ?e, "db error unsuspending community"); StatusCode::INTERNAL_SERVER_ERROR.into_response() })?; log_mod_action( &state.db, None, admin.user_id, ModAction::UnsuspendCommunity, None, Some(community_id), None, ).await; Ok(Redirect::to("/_admin?toast=Community+unsuspended")) } #[tracing::instrument(skip_all)] pub(super) async fn suspend_user_handler( axum::extract::State(state): axum::extract::State, PlatformAdmin(admin): PlatformAdmin, Path(id): Path, Form(form): Form, ) -> Result { let user_id = parse_uuid(&id)?; let reason = form.reason.as_deref().filter(|r| !r.trim().is_empty()); mt_db::mutations::suspend_user(&state.db, user_id, reason) .await .map_err(|e| { tracing::error!(error = ?e, "db error suspending user"); StatusCode::INTERNAL_SERVER_ERROR.into_response() })?; log_mod_action( &state.db, None, admin.user_id, ModAction::SuspendUser, Some(user_id), None, reason, ).await; Ok(Redirect::to("/_admin?toast=User+suspended")) } #[tracing::instrument(skip_all)] pub(super) async fn unsuspend_user_handler( axum::extract::State(state): axum::extract::State, PlatformAdmin(admin): PlatformAdmin, Path(id): Path, ) -> Result { let user_id = parse_uuid(&id)?; mt_db::mutations::unsuspend_user(&state.db, user_id) .await .map_err(|e| { tracing::error!(error = ?e, "db error unsuspending user"); StatusCode::INTERNAL_SERVER_ERROR.into_response() })?; log_mod_action( &state.db, None, admin.user_id, ModAction::UnsuspendUser, Some(user_id), None, None, ).await; Ok(Redirect::to("/_admin?toast=User+unsuspended")) }