Skip to main content

yggdrasil/api/comments/
list.rs

1//! 评论列表查询接口:后台管理用的全部评论列表与待审核计数。
2//!
3//! 所有接口均需管理员身份,Dioxus server function 注册在 `/api` 路径下。
4//! 仅在 `feature = "server"` 启用的服务端构建中查询数据库。
5
6use crate::api::comments::types::*;
7use dioxus::prelude::*;
8
9/// 获取待审核评论总数。
10///
11/// 优先从缓存读取,未命中时查询数据库并写入缓存。
12#[server(GetPendingCount, "/api")]
13pub async fn get_pending_count() -> Result<PendingCountResponse, ServerFnError> {
14    #[cfg(feature = "server")]
15    {
16        use crate::api::auth::get_current_admin_user;
17        use crate::api::error::AppError;
18        use crate::cache;
19        use crate::db::pool::get_conn;
20
21        let _admin = get_current_admin_user().await?;
22
23        if let Some(cached) = cache::get_pending_count().await {
24            return Ok(PendingCountResponse { count: cached });
25        }
26
27        let client = get_conn().await.map_err(AppError::db_conn)?;
28
29        let count: i64 = client
30            .query_one(
31                "SELECT COUNT(*) FROM comments WHERE status = 'pending' AND deleted_at IS NULL",
32                &[],
33            )
34            .await
35            .map_err(AppError::query)?
36            .get(0);
37
38        cache::set_pending_count(count).await;
39
40        Ok(PendingCountResponse { count })
41    }
42    #[cfg(not(feature = "server"))]
43    unreachable!()
44}
45
46/// 获取全部评论分页列表。
47///
48/// 支持按状态筛选;未指定状态时返回所有未删除评论。
49#[server(GetAllComments, "/api")]
50pub async fn get_all_comments(
51    page: i32,
52    status: Option<String>,
53) -> Result<AllCommentsResponse, ServerFnError> {
54    #[cfg(feature = "server")]
55    {
56        use crate::api::auth::get_current_admin_user;
57        use crate::api::comments::helpers::row_to_admin_comment;
58        use crate::api::error::AppError;
59        use crate::db::pool::get_conn;
60
61        let _admin = get_current_admin_user().await?;
62
63        let page = page.max(1);
64        let per_page: i64 = 20;
65        let offset: i64 = (page as i64 - 1) * per_page;
66
67        let client = get_conn().await.map_err(AppError::db_conn)?;
68
69        // 根据是否传入状态参数,分别构造 SQL 与查询条件。
70        let (total, rows) = match status.as_deref() {
71            Some(s) if !s.is_empty() => {
72                let total: i64 = client
73                    .query_one(
74                        "SELECT COUNT(*) FROM comments WHERE status = $1 AND deleted_at IS NULL",
75                        &[&s],
76                    )
77                    .await
78                    .map_err(AppError::query)?
79                    .get(0);
80
81                let rows = client
82                    .query(
83                        "SELECT c.id, c.post_id, c.parent_id, c.depth, c.author_name, c.author_email, \
84                                c.author_url, c.content_md, c.status, c.created_at, \
85                                c.user_id, u.display_name AS user_display_name, u.avatar_url AS user_avatar, \
86                                p.title as post_title, p.slug as post_slug \
87                         FROM comments c JOIN posts p ON c.post_id = p.id \
88                         LEFT JOIN users u ON c.user_id = u.id \
89                         WHERE c.status = $1 AND c.deleted_at IS NULL \
90                         ORDER BY c.created_at DESC LIMIT $2 OFFSET $3",
91                        &[&s, &per_page, &offset],
92                    )
93                    .await
94                    .map_err(AppError::query)?;
95
96                (total, rows)
97            }
98            _ => {
99                let total: i64 = client
100                    .query_one(
101                        "SELECT COUNT(*) FROM comments WHERE deleted_at IS NULL",
102                        &[],
103                    )
104                    .await
105                    .map_err(AppError::query)?
106                    .get(0);
107
108                let rows = client
109                    .query(
110                        "SELECT c.id, c.post_id, c.parent_id, c.depth, c.author_name, c.author_email, \
111                                c.author_url, c.content_md, c.status, c.created_at, \
112                                c.user_id, u.display_name AS user_display_name, u.avatar_url AS user_avatar, \
113                                p.title as post_title, p.slug as post_slug \
114                         FROM comments c JOIN posts p ON c.post_id = p.id \
115                         LEFT JOIN users u ON c.user_id = u.id \
116                         WHERE c.deleted_at IS NULL \
117                         ORDER BY c.created_at DESC LIMIT $1 OFFSET $2",
118                        &[&per_page, &offset],
119                    )
120                    .await
121                    .map_err(AppError::query)?;
122
123                (total, rows)
124            }
125        };
126
127        let comments = rows.iter().map(row_to_admin_comment).collect();
128
129        Ok(AllCommentsResponse { comments, total })
130    }
131    #[cfg(not(feature = "server"))]
132    unreachable!()
133}