1use std::collections::HashMap;
2
3use crate::client::Client;
4use crate::constants;
5use crate::error;
6use crate::types::{
7 PostsOptions, PostsResponse, PublicUser, RecentSearch, RepliesResponse, User, UserId,
8};
9use crate::validation;
10
11impl Client {
12 pub async fn get_user(&self, user_id: &UserId) -> crate::Result<User> {
14 if !user_id.is_valid() {
15 return Err(error::new_validation_error(
16 0,
17 constants::ERR_EMPTY_USER_ID,
18 "",
19 "user_id",
20 ));
21 }
22
23 let token = self.access_token().await;
24 let mut params = HashMap::new();
25 params.insert("fields".into(), constants::USER_PROFILE_FIELDS.into());
26
27 let path = format!("/{}", user_id);
28 let resp = self.http_client.get(&path, params, &token).await?;
29 resp.json()
30 }
31
32 pub async fn get_me(&self) -> crate::Result<User> {
34 let uid = self.user_id().await;
35 if uid.is_empty() {
36 return Err(error::new_authentication_error(
37 401,
38 constants::ERR_EMPTY_USER_ID,
39 "No user ID available from token",
40 ));
41 }
42 let user_id = UserId::from(uid);
43 self.get_user(&user_id).await
44 }
45
46 pub async fn lookup_public_profile(&self, username: &str) -> crate::Result<PublicUser> {
48 if username.is_empty() {
49 return Err(error::new_validation_error(
50 0,
51 "Username is required",
52 "",
53 "username",
54 ));
55 }
56
57 let token = self.access_token().await;
58 let mut params = HashMap::new();
59 params.insert("username".into(), username.to_owned());
60 params.insert("fields".into(), constants::PUBLIC_USER_FIELDS.into());
61
62 let resp = self
63 .http_client
64 .get("/profile_lookup", params, &token)
65 .await?;
66 resp.json()
67 }
68
69 pub async fn get_user_with_fields(
71 &self,
72 user_id: &UserId,
73 fields: &[&str],
74 ) -> crate::Result<User> {
75 if !user_id.is_valid() {
76 return Err(error::new_validation_error(
77 0,
78 constants::ERR_EMPTY_USER_ID,
79 "",
80 "user_id",
81 ));
82 }
83
84 let token = self.access_token().await;
85 let mut params = HashMap::new();
86
87 let fields_str = if fields.is_empty() {
88 constants::USER_PROFILE_FIELDS.to_owned()
89 } else {
90 fields.join(",")
91 };
92 params.insert("fields".into(), fields_str);
93
94 let path = format!("/{}", user_id);
95 let resp = self.http_client.get(&path, params, &token).await?;
96 resp.json()
97 }
98
99 pub async fn get_public_profile_posts(
101 &self,
102 username: &str,
103 opts: Option<&PostsOptions>,
104 ) -> crate::Result<PostsResponse> {
105 if username.is_empty() {
106 return Err(error::new_validation_error(
107 0,
108 "Username is required",
109 "",
110 "username",
111 ));
112 }
113
114 if let Some(opts) = opts {
115 validation::validate_posts_options(opts)?;
116 }
117
118 let token = self.access_token().await;
119 let mut params = HashMap::new();
120 params.insert("username".into(), username.to_owned());
121 params.insert("fields".into(), constants::POST_EXTENDED_FIELDS.into());
122
123 if let Some(opts) = opts {
124 if let Some(limit) = opts.limit {
125 params.insert("limit".into(), limit.to_string());
126 }
127 if let Some(ref before) = opts.before {
128 params.insert("before".into(), before.clone());
129 }
130 if let Some(ref after) = opts.after {
131 params.insert("after".into(), after.clone());
132 }
133 if let Some(since) = opts.since {
134 params.insert("since".into(), since.to_string());
135 }
136 if let Some(until) = opts.until {
137 params.insert("until".into(), until.to_string());
138 }
139 }
140
141 let resp = self
142 .http_client
143 .get("/profile_posts", params, &token)
144 .await?;
145 resp.json()
146 }
147
148 pub async fn get_user_replies(
150 &self,
151 user_id: &UserId,
152 opts: Option<&PostsOptions>,
153 ) -> crate::Result<RepliesResponse> {
154 if !user_id.is_valid() {
155 return Err(error::new_validation_error(
156 0,
157 constants::ERR_EMPTY_USER_ID,
158 "",
159 "user_id",
160 ));
161 }
162
163 if let Some(opts) = opts {
164 validation::validate_posts_options(opts)?;
165 }
166
167 let token = self.access_token().await;
168 let mut params = HashMap::new();
169 params.insert("fields".into(), constants::REPLY_FIELDS.into());
170
171 if let Some(opts) = opts {
172 if let Some(limit) = opts.limit {
173 params.insert("limit".into(), limit.to_string());
174 }
175 if let Some(ref before) = opts.before {
176 params.insert("before".into(), before.clone());
177 }
178 if let Some(ref after) = opts.after {
179 params.insert("after".into(), after.clone());
180 }
181 if let Some(since) = opts.since {
182 params.insert("since".into(), since.to_string());
183 }
184 if let Some(until) = opts.until {
185 params.insert("until".into(), until.to_string());
186 }
187 }
188
189 let path = format!("/{}/replies", user_id);
190 let resp = self.http_client.get(&path, params, &token).await?;
191 resp.json()
192 }
193
194 pub async fn get_my_posts(&self, opts: Option<&PostsOptions>) -> crate::Result<PostsResponse> {
198 let uid = self.user_id().await;
199 if uid.is_empty() {
200 return Err(error::new_authentication_error(
201 401,
202 constants::ERR_EMPTY_USER_ID,
203 "No user ID available from token",
204 ));
205 }
206 let user_id = UserId::from(uid);
207 self.get_user_posts(&user_id, opts).await
208 }
209
210 pub async fn get_my_replies(
212 &self,
213 opts: Option<&PostsOptions>,
214 ) -> crate::Result<RepliesResponse> {
215 let uid = self.user_id().await;
216 if uid.is_empty() {
217 return Err(error::new_authentication_error(
218 401,
219 constants::ERR_EMPTY_USER_ID,
220 "No user ID available from token",
221 ));
222 }
223 let user_id = UserId::from(uid);
224 self.get_user_replies(&user_id, opts).await
225 }
226
227 pub async fn get_my_mentions(
229 &self,
230 opts: Option<&PostsOptions>,
231 ) -> crate::Result<PostsResponse> {
232 let uid = self.user_id().await;
233 if uid.is_empty() {
234 return Err(error::new_authentication_error(
235 401,
236 constants::ERR_EMPTY_USER_ID,
237 "No user ID available from token",
238 ));
239 }
240 let user_id = UserId::from(uid);
241 self.get_user_mentions(&user_id, opts).await
242 }
243
244 pub async fn get_my_ghost_posts(
246 &self,
247 opts: Option<&PostsOptions>,
248 ) -> crate::Result<PostsResponse> {
249 let uid = self.user_id().await;
250 if uid.is_empty() {
251 return Err(error::new_authentication_error(
252 401,
253 constants::ERR_EMPTY_USER_ID,
254 "No user ID available from token",
255 ));
256 }
257 let user_id = UserId::from(uid);
258 self.get_user_ghost_posts(&user_id, opts).await
259 }
260
261 pub async fn get_recently_searched_keywords(&self) -> crate::Result<Vec<RecentSearch>> {
263 let uid = self.user_id().await;
264 if uid.is_empty() {
265 return Err(error::new_authentication_error(
266 401,
267 constants::ERR_EMPTY_USER_ID,
268 "No user ID available from token",
269 ));
270 }
271 let user_id = UserId::from(uid);
272 let user = self
273 .get_user_with_fields(&user_id, &["recently_searched_keywords"])
274 .await?;
275 Ok(user.recently_searched_keywords.unwrap_or_default())
276 }
277}