Skip to main content

yggdrasil/api/
admin_stats.rs

1//! 后台统计接口:侧栏导航项右侧的数量。
2//!
3//! 文章数读文章统计缓存,待审评论数读待审计数缓存;素材与评论总数是两次
4//! 计数查询,侧栏每次换页刷新一次。Leptos server function,注册在 `/api` 路径下。
5
6// 与 settings 等模块一致:Leptos `#[server]` 宏触发 deprecated/unit 提示,按项目惯例放行。
7#![allow(clippy::unused_unit, deprecated)]
8
9use crate::api::error::ApiError;
10use leptos::prelude::*;
11use serde::{Deserialize, Serialize};
12
13/// 侧栏数量。
14#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
15pub struct AdminNavCounts {
16    /// 未删除的文章(含草稿)。
17    pub posts: i64,
18    /// 已登记的素材。
19    pub assets: i64,
20    /// 待审与已通过的评论,不含垃圾与回收站。
21    pub comments: i64,
22    /// 待审评论。
23    pub pending_comments: i64,
24}
25
26/// 获取侧栏数量。需要 admin 权限。
27#[server(GetAdminNavCounts, endpoint = "get_admin_nav_counts", input = leptos::server_fn::codec::Json)]
28pub async fn get_admin_nav_counts() -> Result<AdminNavCounts, ApiError> {
29    #[cfg(feature = "server")]
30    {
31        use crate::api::error::AppError;
32        use crate::db::pool::get_conn;
33
34        crate::api::auth::get_current_admin_user().await?;
35        let stats = crate::api::posts::load_post_stats().await?;
36
37        let client = get_conn().await.map_err(AppError::db_conn)?;
38        let row = client
39            .query_one(
40                "SELECT
41                    (SELECT COUNT(*) FROM assets) AS assets,
42                    (SELECT COUNT(*) FROM comments
43                      WHERE deleted_at IS NULL AND status IN ('pending', 'approved')) AS comments",
44                &[],
45            )
46            .await
47            .map_err(AppError::query)?;
48
49        let pending_comments = match crate::cache::get_pending_count().await {
50            Some(count) => count,
51            None => {
52                let count: i64 = client
53                    .query_one(
54                        "SELECT COUNT(*) FROM comments WHERE status = 'pending' AND deleted_at IS NULL",
55                        &[],
56                    )
57                    .await
58                    .map_err(AppError::query)?
59                    .get(0);
60                crate::cache::set_pending_count(count).await;
61                count
62            }
63        };
64
65        Ok(AdminNavCounts {
66            posts: stats.total,
67            assets: row.get("assets"),
68            comments: row.get("comments"),
69            pending_comments,
70        })
71    }
72    #[cfg(not(feature = "server"))]
73    unreachable!()
74}