//! The admin user list and its counts. //! //! `get_all_users` and `count_users` are two `match` ladders over the same //! filter set, and a filter added to one and not the other silently mispages //! the list. Their agreement is enforced by sitting next to each other, which //! sixty lines apart in a 1330-line file was not. use sqlx::PgPool; use crate::db::models::DbUser; use crate::error::Result; /// Admin query: all users, optionally filtered by suspension status, with pagination. #[tracing::instrument(skip_all)] pub async fn get_all_users( pool: &PgPool, filter: Option<&str>, limit: i64, offset: i64, ) -> Result> { let limit = limit.min(200); let users = match filter { Some("suspended") => { sqlx::query_as::<_, DbUser>( "SELECT * FROM users WHERE suspended_at IS NOT NULL ORDER BY suspended_at DESC LIMIT $1 OFFSET $2", ) .bind(limit) .bind(offset) .fetch_all(pool) .await? } Some("active") => { sqlx::query_as::<_, DbUser>( "SELECT * FROM users WHERE suspended_at IS NULL ORDER BY created_at DESC LIMIT $1 OFFSET $2", ) .bind(limit) .bind(offset) .fetch_all(pool) .await? } // Creators with a custom page; most recently changed first, so // "recently changed" surfaces naturally at the top. Some("custom_pages") => { sqlx::query_as::<_, DbUser>( "SELECT * FROM users WHERE custom_html <> '' OR custom_css <> '' \ ORDER BY custom_pages_updated_at DESC NULLS LAST, created_at DESC LIMIT $1 OFFSET $2", ) .bind(limit) .bind(offset) .fetch_all(pool) .await? } Some("pages_locked") => { sqlx::query_as::<_, DbUser>( "SELECT * FROM users WHERE custom_pages_locked = true ORDER BY created_at DESC LIMIT $1 OFFSET $2", ) .bind(limit) .bind(offset) .fetch_all(pool) .await? } _ => { sqlx::query_as::<_, DbUser>( "SELECT * FROM users ORDER BY created_at DESC LIMIT $1 OFFSET $2", ) .bind(limit) .bind(offset) .fetch_all(pool) .await? } }; Ok(users) } /// Count users matching a filter (for pagination totals). #[tracing::instrument(skip_all)] pub async fn count_users(pool: &PgPool, filter: Option<&str>) -> Result { let count = match filter { Some("suspended") => { sqlx::query_scalar::<_, i64>( "SELECT COUNT(*) FROM users WHERE suspended_at IS NOT NULL", ) .fetch_one(pool) .await? } Some("active") => { sqlx::query_scalar::<_, i64>("SELECT COUNT(*) FROM users WHERE suspended_at IS NULL") .fetch_one(pool) .await? } Some("custom_pages") => { sqlx::query_scalar::<_, i64>( "SELECT COUNT(*) FROM users WHERE custom_html <> '' OR custom_css <> ''", ) .fetch_one(pool) .await? } Some("pages_locked") => { sqlx::query_scalar::<_, i64>( "SELECT COUNT(*) FROM users WHERE custom_pages_locked = true", ) .fetch_one(pool) .await? } _ => { sqlx::query_scalar::<_, i64>("SELECT COUNT(*) FROM users") .fetch_one(pool) .await? } }; Ok(count) } /// Count total and suspended users in a single query. #[tracing::instrument(skip_all)] pub async fn count_users_summary(pool: &PgPool) -> Result<(i64, i64)> { let (total, suspended): (i64, i64) = sqlx::query_as( r" SELECT COUNT(*), COUNT(*) FILTER (WHERE suspended_at IS NOT NULL) FROM users ", ) .fetch_one(pool) .await?; Ok((total, suspended)) }