dceapi_rs/services/
news.rs

1//! News service for article and announcement APIs.
2
3use std::collections::HashSet;
4use std::sync::LazyLock;
5
6use crate::error::{Error, Result};
7use crate::http::{BaseClient, RequestOptions};
8use crate::models::{ArticleDetail, GetArticleByPageRequest, GetArticleByPageResponse};
9
10/// API endpoint for paginated article list.
11const PATH_GET_ARTICLE_BY_PAGE: &str = "/dceapi/cms/info/articleByPage";
12
13/// API endpoint for article detail.
14const PATH_GET_ARTICLE_DETAIL: &str = "/dceapi/cms/info/articleDetail";
15
16/// Valid column IDs for articles.
17static VALID_COLUMN_IDS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
18    let mut set = HashSet::new();
19    set.insert("244");  // 交易所公告
20    set.insert("245");  // 交易所通知
21    set.insert("246");  // 交割信息
22    set.insert("248");  // 会员服务系统公告
23    set.insert("1076"); // 期权公告
24    set.insert("242");  // 新闻
25    set
26});
27
28/// Check if a column ID is valid.
29pub fn is_valid_column_id(column_id: &str) -> bool {
30    VALID_COLUMN_IDS.contains(column_id)
31}
32
33/// News service for accessing articles and announcements.
34#[derive(Debug, Clone)]
35pub struct NewsService {
36    client: BaseClient,
37}
38
39impl NewsService {
40    /// Create a new news service.
41    pub fn new(client: BaseClient) -> Self {
42        NewsService { client }
43    }
44
45    /// Get paginated article list.
46    ///
47    /// # Arguments
48    /// * `req` - Request parameters including column_id, page_no, page_size
49    /// * `opts` - Optional request options
50    ///
51    /// # Valid Column IDs
52    /// * `244` - Exchange announcements (交易所公告)
53    /// * `245` - Exchange notices (交易所通知)
54    /// * `246` - Delivery information (交割信息)
55    /// * `248` - Member service announcements (会员服务系统公告)
56    /// * `1076` - Options announcements (期权公告)
57    /// * `242` - News (新闻)
58    pub async fn get_article_by_page(
59        &self,
60        mut req: GetArticleByPageRequest,
61        opts: Option<RequestOptions>,
62    ) -> Result<GetArticleByPageResponse> {
63        // Validate column_id
64        if !is_valid_column_id(&req.column_id) {
65            return Err(Error::validation(
66                "column_id",
67                "invalid column_id, must be one of: 244, 245, 246, 248, 1076, 242",
68            ));
69        }
70
71        // Apply default site_id if not set
72        if req.site_id == 0 {
73            req.site_id = 5;
74        }
75
76        self.client
77            .do_post(PATH_GET_ARTICLE_BY_PAGE, &req, opts)
78            .await
79    }
80
81    /// Get article detail by ID.
82    ///
83    /// # Arguments
84    /// * `article_id` - The article ID to fetch
85    /// * `opts` - Optional request options
86    pub async fn get_article_detail(
87        &self,
88        article_id: &str,
89        opts: Option<RequestOptions>,
90    ) -> Result<ArticleDetail> {
91        if article_id.is_empty() {
92            return Err(Error::validation("article_id", "article_id is required"));
93        }
94
95        #[derive(serde::Serialize)]
96        #[serde(rename_all = "camelCase")]
97        struct Request<'a> {
98            article_id: &'a str,
99        }
100
101        let req = Request { article_id };
102        self.client.do_post(PATH_GET_ARTICLE_DETAIL, &req, opts).await
103    }
104}