sponsor_block/client/user/
user_stats.rs1use std::{collections::HashMap, result::Result as StdResult};
3
4use serde::{Deserialize, Deserializer};
5use serde_json::from_str as from_json_str;
6
7use crate::{
8 api::{convert_to_action_type, convert_to_segment_kind},
9 error::Result,
10 util::{de::map_hashmap_key_from_str, get_response_text},
11 Action,
12 ActionableSegmentKind,
13 Client,
14 LocalUserIdSlice,
15 PublicUserId,
16 PublicUserIdSlice,
17};
18
19#[derive(Deserialize, Debug, Default)]
21#[serde(default, rename_all = "camelCase")]
22pub struct UserStats {
23 #[serde(rename = "userID")]
25 pub user_id: PublicUserId,
26 pub user_name: Option<String>,
28 pub overall_stats: OverallStats,
30 #[serde(deserialize_with = "map_category_kinds")]
32 pub category_count: HashMap<ActionableSegmentKind, u32>,
33 #[serde(deserialize_with = "map_action_types")]
35 pub action_type_count: HashMap<Action, u32>,
36}
37
38fn map_category_kinds<'de, D: Deserializer<'de>, O: Deserialize<'de>>(
39 deserializer: D,
40) -> StdResult<HashMap<ActionableSegmentKind, O>, D::Error> {
41 map_hashmap_key_from_str(deserializer, convert_to_segment_kind)
42}
43
44fn map_action_types<'de, D: Deserializer<'de>, O: Deserialize<'de>>(
45 deserializer: D,
46) -> StdResult<HashMap<Action, O>, D::Error> {
47 map_hashmap_key_from_str(deserializer, convert_to_action_type)
48}
49
50#[derive(Deserialize, Debug, Default)]
56#[serde(default, rename_all = "camelCase")]
57pub struct OverallStats {
58 pub minutes_saved: f32,
60 pub segment_count: u32,
63}
64
65const API_ENDPOINT: &str = "/userStats";
67
68impl Client {
70 pub async fn fetch_user_stats_public(
79 &self,
80 public_user_id: &PublicUserIdSlice,
81 ) -> Result<UserStats> {
82 let request = self
84 .http
85 .get(format!("{}{}", &self.base_url, API_ENDPOINT))
86 .query(&[("publicUserID", public_user_id)])
87 .query(&[("fetchCategoryStats", true), ("fetchActionTypeStats", true)]);
88
89 let response = get_response_text(request.send().await?).await?;
91
92 let mut result = from_json_str::<UserStats>(response.as_str())?;
94 if result
97 .user_name
98 .as_ref()
99 .expect("userName field was not set")
100 .eq(&result.user_id)
101 {
102 result.user_name = None;
103 }
104 Ok(result)
105 }
106
107 pub async fn fetch_user_stats_local(
116 &self,
117 local_user_id: &LocalUserIdSlice,
118 ) -> Result<UserStats> {
119 let request = self
121 .http
122 .get(format!("{}{}", &self.base_url, API_ENDPOINT))
123 .query(&[("userID", local_user_id)])
124 .query(&[("fetchCategoryStats", true), ("fetchActionTypeStats", true)]);
125
126 let response = get_response_text(request.send().await?).await?;
128
129 let mut result = from_json_str::<UserStats>(response.as_str())?;
131 if result
134 .user_name
135 .as_ref()
136 .expect("userName field was not set")
137 .eq(&result.user_id)
138 {
139 result.user_name = None;
140 }
141 Ok(result)
142 }
143}