wechat_mp_sdk/api/
analytics.rs1use std::collections::HashMap;
4use std::sync::Arc;
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9use super::{WechatApi, WechatContext};
10use crate::error::WechatError;
11
12#[non_exhaustive]
13#[derive(Debug, Clone, Serialize)]
14pub struct AnalyticsDateRangeRequest {
15 pub begin_date: String,
16 pub end_date: String,
17}
18
19impl AnalyticsDateRangeRequest {
20 pub fn new(begin_date: impl Into<String>, end_date: impl Into<String>) -> Self {
21 Self {
22 begin_date: begin_date.into(),
23 end_date: end_date.into(),
24 }
25 }
26}
27
28#[non_exhaustive]
29#[derive(Debug, Clone, Serialize)]
30pub struct PerformanceDataRequest {
31 pub cost_time_type: i32,
32 pub default_start_time: i64,
33 pub default_end_time: i64,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub device: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub networktype: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub scene: Option<i32>,
40}
41
42#[non_exhaustive]
43#[derive(Debug, Clone, Deserialize, Serialize)]
44pub struct AnalyticsResponse {
45 #[serde(default)]
46 pub(crate) errcode: i32,
47 #[serde(default)]
48 pub(crate) errmsg: String,
49 #[serde(flatten)]
50 pub extra: HashMap<String, Value>,
51}
52
53pub struct AnalyticsApi {
54 context: Arc<WechatContext>,
55}
56
57impl AnalyticsApi {
58 pub fn new(context: Arc<WechatContext>) -> Self {
59 Self { context }
60 }
61
62 pub async fn get_daily_summary(
63 &self,
64 request: &AnalyticsDateRangeRequest,
65 ) -> Result<AnalyticsResponse, WechatError> {
66 self.post_datacube("/datacube/getweanalysisappiddailysummarytrend", request)
67 .await
68 }
69
70 pub async fn get_daily_visit_trend(
71 &self,
72 request: &AnalyticsDateRangeRequest,
73 ) -> Result<AnalyticsResponse, WechatError> {
74 self.post_datacube("/datacube/getweanalysisappiddailyvisittrend", request)
75 .await
76 }
77
78 pub async fn get_weekly_visit_trend(
79 &self,
80 request: &AnalyticsDateRangeRequest,
81 ) -> Result<AnalyticsResponse, WechatError> {
82 self.post_datacube("/datacube/getweanalysisappidweeklyvisittrend", request)
83 .await
84 }
85
86 pub async fn get_monthly_visit_trend(
87 &self,
88 request: &AnalyticsDateRangeRequest,
89 ) -> Result<AnalyticsResponse, WechatError> {
90 self.post_datacube("/datacube/getweanalysisappidmonthlyvisittrend", request)
91 .await
92 }
93
94 pub async fn get_daily_retain(
95 &self,
96 request: &AnalyticsDateRangeRequest,
97 ) -> Result<AnalyticsResponse, WechatError> {
98 self.post_datacube("/datacube/getweanalysisappiddailyretaininfo", request)
99 .await
100 }
101
102 pub async fn get_weekly_retain(
103 &self,
104 request: &AnalyticsDateRangeRequest,
105 ) -> Result<AnalyticsResponse, WechatError> {
106 self.post_datacube("/datacube/getweanalysisappidweeklyretaininfo", request)
107 .await
108 }
109
110 pub async fn get_monthly_retain(
111 &self,
112 request: &AnalyticsDateRangeRequest,
113 ) -> Result<AnalyticsResponse, WechatError> {
114 self.post_datacube("/datacube/getweanalysisappidmonthlyretaininfo", request)
115 .await
116 }
117
118 pub async fn get_visit_page(
119 &self,
120 request: &AnalyticsDateRangeRequest,
121 ) -> Result<AnalyticsResponse, WechatError> {
122 self.post_datacube("/datacube/getweanalysisappidvisitpage", request)
123 .await
124 }
125
126 pub async fn get_visit_distribution(
127 &self,
128 request: &AnalyticsDateRangeRequest,
129 ) -> Result<AnalyticsResponse, WechatError> {
130 self.post_datacube("/datacube/getweanalysisappidvisitdistribution", request)
131 .await
132 }
133
134 pub async fn get_user_portrait(
135 &self,
136 request: &AnalyticsDateRangeRequest,
137 ) -> Result<AnalyticsResponse, WechatError> {
138 self.post_datacube("/datacube/getweanalysisappiduserportrait", request)
139 .await
140 }
141
142 pub async fn get_performance_data(
143 &self,
144 request: &PerformanceDataRequest,
145 ) -> Result<AnalyticsResponse, WechatError> {
146 self.post_datacube("/wxaapi/log/get_performance", request)
147 .await
148 }
149
150 async fn post_datacube<B: Serialize>(
151 &self,
152 endpoint: &str,
153 body: &B,
154 ) -> Result<AnalyticsResponse, WechatError> {
155 let response: AnalyticsResponse = self.context.authed_post(endpoint, body).await?;
156 WechatError::check_api(response.errcode, &response.errmsg)?;
157 Ok(response)
158 }
159}
160
161impl WechatApi for AnalyticsApi {
162 fn context(&self) -> &WechatContext {
163 &self.context
164 }
165
166 fn api_name(&self) -> &'static str {
167 "analytics"
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn analytics_response_deserializes() {
177 let json = r#"{"errcode":0,"errmsg":"ok","list":[{"k":"v"}]}"#;
178 let response: AnalyticsResponse = serde_json::from_str(json).unwrap();
179 assert_eq!(response.errcode, 0);
180 assert!(response.extra.contains_key("list"));
181 }
182
183 #[test]
184 fn analytics_date_range_request_serializes() {
185 let request = AnalyticsDateRangeRequest::new("20240101", "20240102");
186 let value = serde_json::to_value(request).unwrap();
187 assert_eq!(value["begin_date"], "20240101");
188 assert_eq!(value["end_date"], "20240102");
189 }
190}