1use crate::dto::user::*;
6use crate::{Error, PickcatAccound};
7
8pub trait UserProfileBehavior {
14 fn get_user_information(
16 &self,
17 user_id: &str,
18 ) -> impl std::future::Future<Output = Result<GetUserInformationDTO, Error>> + Send;
19
20 fn update_user_profile(
23 &self,
24 user_id: &str,
25 bio: Option<&str>,
26 ) -> impl std::future::Future<Output = Result<GetUserInformationDTO, Error>> + Send;
27
28 fn get_user_email(
31 &self,
32 user_id: &str,
33 ) -> impl std::future::Future<Output = Result<GetUserEmailDTO, Error>> + Send;
34
35 fn get_user_following(
37 &self,
38 user_id: &str,
39 limit: Option<u32>,
40 cursor: Option<&str>,
41 ) -> impl std::future::Future<Output = Result<CursorListDTO<GetUserInformationDTO>, Error>> + Send;
42
43 fn get_user_followers(
45 &self,
46 user_id: &str,
47 limit: Option<u32>,
48 cursor: Option<&str>,
49 ) -> impl std::future::Future<Output = Result<CursorListDTO<GetUserInformationDTO>, Error>> + Send;
50
51 fn get_user_topics(
53 &self,
54 user_id: &str,
55 limit: Option<u32>,
56 ) -> impl std::future::Future<Output = Result<UserSubjectsDTO, Error>> + Send;
57
58 fn get_user_posts(
60 &self,
61 user_id: &str,
62 role: Option<&str>,
63 limit: Option<u32>,
64 ) -> impl std::future::Future<Output = Result<UserRepliesDTO, Error>> + Send;
65
66 fn get_user_featured_topics(
68 &self,
69 user_id: &str,
70 ) -> impl std::future::Future<Output = Result<UserFeaturedTopicsDTO, Error>> + Send;
71
72 fn get_user_topic_collections(
76 &self,
77 user_id: &str,
78 limit: Option<u32>,
79 ) -> impl std::future::Future<Output = Result<CursorListDTO<serde_json::Value>, Error>> + Send;
80
81 fn get_user_badges(
83 &self,
84 user_id: &str,
85 ) -> impl std::future::Future<Output = Result<UserBadgesDTO, Error>> + Send;
86
87 fn get_user_badge_display(
89 &self,
90 user_id: &str,
91 ) -> impl std::future::Future<Output = Result<BadgeDisplayDTO, Error>> + Send;
92
93 fn get_user_badge_displays(
95 &self,
96 user_ids: &[String],
97 ) -> impl std::future::Future<Output = Result<UserBadgeDisplaysDTO, Error>> + Send;
98
99 fn get_user_profile_activities(
101 &self,
102 user_id: &str,
103 year: Option<u32>,
104 limit: Option<u32>,
105 ) -> impl std::future::Future<Output = Result<CursorListDTO<ProfileActivityDTO>, Error>> + Send;
106
107 fn get_my_profile_activities(
109 &self,
110 year: Option<u32>,
111 limit: Option<u32>,
112 ) -> impl std::future::Future<Output = Result<CursorListDTO<ProfileActivityDTO>, Error>> + Send;
113
114 fn get_user_level_contributions(
116 &self,
117 user_id: &str,
118 year: u32,
119 ) -> impl std::future::Future<Output = Result<LevelContributionsDTO, Error>> + Send;
120
121 fn get_my_level_contributions(
123 &self,
124 year: u32,
125 ) -> impl std::future::Future<Output = Result<LevelContributionsDTO, Error>> + Send;
126
127 fn get_level_progress(
129 &self,
130 ) -> impl std::future::Future<Output = Result<LevelProgressDTO, Error>> + Send;
131
132 fn get_content_length_limit(
134 &self,
135 ) -> impl std::future::Future<Output = Result<ContentLengthLimitDTO, Error>> + Send;
136
137 fn get_topic_collection_usage(
139 &self,
140 ) -> impl std::future::Future<Output = Result<TopicCollectionUsageDTO, Error>> + Send;
141
142 fn get_file_storage(
144 &self,
145 ) -> impl std::future::Future<Output = Result<FileStorageDTO, Error>> + Send;
146
147 fn get_bookmarks(
151 &self,
152 limit: Option<u32>,
153 ) -> impl std::future::Future<Output = Result<CursorListDTO<serde_json::Value>, Error>> + Send;
154
155 fn get_avatar_presets(
157 &self,
158 ) -> impl std::future::Future<Output = Result<AvatarPresetsDTO, Error>> + Send;
159}
160
161fn push_query(params: &mut Vec<(&str, String)>, key: &'static str, value: Option<String>) {
163 if let Some(value) = value {
164 params.push((key, value));
165 }
166}
167
168impl UserProfileBehavior for PickcatAccound {
169 async fn get_user_information(&self, user_id: &str) -> Result<GetUserInformationDTO, Error> {
170 Ok(self
171 .client
172 .get(format!("{}/api/v1/users/{}", self.base_url, user_id))
173 .send()
174 .await?
175 .json::<GetUserInformationDTO>()
176 .await?)
177 }
178
179 async fn update_user_profile(
180 &self,
181 user_id: &str,
182 bio: Option<&str>,
183 ) -> Result<GetUserInformationDTO, Error> {
184 let dto = UpdateUserProfileDTO {
185 bio: bio.map(str::to_string),
186 };
187 Ok(self
188 .client
189 .patch(format!("{}/api/v1/users/{}", self.base_url, user_id))
190 .json(&dto)
191 .send()
192 .await?
193 .json::<GetUserInformationDTO>()
194 .await?)
195 }
196
197 async fn get_user_email(&self, user_id: &str) -> Result<GetUserEmailDTO, Error> {
198 Ok(self
199 .client
200 .get(format!("{}/api/v1/users/{}/email", self.base_url, user_id))
201 .send()
202 .await?
203 .json::<GetUserEmailDTO>()
204 .await?)
205 }
206
207 async fn get_user_following(
208 &self,
209 user_id: &str,
210 limit: Option<u32>,
211 cursor: Option<&str>,
212 ) -> Result<CursorListDTO<GetUserInformationDTO>, Error> {
213 let mut params: Vec<(&str, String)> = Vec::new();
214 push_query(&mut params, "limit", limit.map(|v| v.to_string()));
215 push_query(&mut params, "cursor", cursor.map(str::to_string));
216
217 let mut request = self.client.get(format!(
218 "{}/api/v1/users/{}/following",
219 self.base_url, user_id
220 ));
221 if !params.is_empty() {
222 request = request.query(¶ms);
223 }
224 Ok(request
225 .send()
226 .await?
227 .json::<CursorListDTO<GetUserInformationDTO>>()
228 .await?)
229 }
230
231 async fn get_user_followers(
232 &self,
233 user_id: &str,
234 limit: Option<u32>,
235 cursor: Option<&str>,
236 ) -> Result<CursorListDTO<GetUserInformationDTO>, Error> {
237 let mut params: Vec<(&str, String)> = Vec::new();
238 push_query(&mut params, "limit", limit.map(|v| v.to_string()));
239 push_query(&mut params, "cursor", cursor.map(str::to_string));
240
241 let mut request = self.client.get(format!(
242 "{}/api/v1/users/{}/followers",
243 self.base_url, user_id
244 ));
245 if !params.is_empty() {
246 request = request.query(¶ms);
247 }
248 Ok(request
249 .send()
250 .await?
251 .json::<CursorListDTO<GetUserInformationDTO>>()
252 .await?)
253 }
254
255 async fn get_user_topics(
256 &self,
257 user_id: &str,
258 limit: Option<u32>,
259 ) -> Result<UserSubjectsDTO, Error> {
260 let mut request = self
261 .client
262 .get(format!("{}/api/v1/users/{}/topics", self.base_url, user_id));
263 if let Some(limit) = limit {
264 request = request.query(&[("limit", limit)]);
265 }
266 Ok(request.send().await?.json::<UserSubjectsDTO>().await?)
267 }
268
269 async fn get_user_posts(
270 &self,
271 user_id: &str,
272 role: Option<&str>,
273 limit: Option<u32>,
274 ) -> Result<UserRepliesDTO, Error> {
275 let mut params: Vec<(&str, String)> = Vec::new();
276 push_query(&mut params, "role", role.map(str::to_string));
277 push_query(&mut params, "limit", limit.map(|v| v.to_string()));
278
279 let mut request = self
280 .client
281 .get(format!("{}/api/v1/users/{}/posts", self.base_url, user_id));
282 if !params.is_empty() {
283 request = request.query(¶ms);
284 }
285 Ok(request.send().await?.json::<UserRepliesDTO>().await?)
286 }
287
288 async fn get_user_featured_topics(
289 &self,
290 user_id: &str,
291 ) -> Result<UserFeaturedTopicsDTO, Error> {
292 Ok(self
293 .client
294 .get(format!(
295 "{}/api/v1/users/{}/featured-topics",
296 self.base_url, user_id
297 ))
298 .send()
299 .await?
300 .json::<UserFeaturedTopicsDTO>()
301 .await?)
302 }
303
304 async fn get_user_topic_collections(
305 &self,
306 user_id: &str,
307 limit: Option<u32>,
308 ) -> Result<CursorListDTO<serde_json::Value>, Error> {
309 let mut request = self.client.get(format!(
310 "{}/api/v1/users/{}/topic-collections",
311 self.base_url, user_id
312 ));
313 if let Some(limit) = limit {
314 request = request.query(&[("limit", limit)]);
315 }
316 Ok(request
317 .send()
318 .await?
319 .json::<CursorListDTO<serde_json::Value>>()
320 .await?)
321 }
322
323 async fn get_user_badges(&self, user_id: &str) -> Result<UserBadgesDTO, Error> {
324 Ok(self
325 .client
326 .get(format!("{}/api/v1/users/{}/badges", self.base_url, user_id))
327 .send()
328 .await?
329 .json::<UserBadgesDTO>()
330 .await?)
331 }
332
333 async fn get_user_badge_display(&self, user_id: &str) -> Result<BadgeDisplayDTO, Error> {
334 Ok(self
335 .client
336 .get(format!(
337 "{}/api/v1/users/{}/badge-display",
338 self.base_url, user_id
339 ))
340 .send()
341 .await?
342 .json::<BadgeDisplayDTO>()
343 .await?)
344 }
345
346 async fn get_user_badge_displays(
347 &self,
348 user_ids: &[String],
349 ) -> Result<UserBadgeDisplaysDTO, Error> {
350 Ok(self
351 .client
352 .get(format!("{}/api/v1/user-badge-displays", self.base_url))
353 .query(&[("userIds", user_ids.join(","))])
354 .send()
355 .await?
356 .json::<UserBadgeDisplaysDTO>()
357 .await?)
358 }
359
360 async fn get_user_profile_activities(
361 &self,
362 user_id: &str,
363 year: Option<u32>,
364 limit: Option<u32>,
365 ) -> Result<CursorListDTO<ProfileActivityDTO>, Error> {
366 let mut params: Vec<(&str, String)> = Vec::new();
367 push_query(&mut params, "year", year.map(|v| v.to_string()));
368 push_query(&mut params, "limit", limit.map(|v| v.to_string()));
369
370 let mut request = self.client.get(format!(
371 "{}/api/v1/users/{}/profile-activities",
372 self.base_url, user_id
373 ));
374 if !params.is_empty() {
375 request = request.query(¶ms);
376 }
377 Ok(request
378 .send()
379 .await?
380 .json::<CursorListDTO<ProfileActivityDTO>>()
381 .await?)
382 }
383
384 async fn get_my_profile_activities(
385 &self,
386 year: Option<u32>,
387 limit: Option<u32>,
388 ) -> Result<CursorListDTO<ProfileActivityDTO>, Error> {
389 let mut params: Vec<(&str, String)> = Vec::new();
390 push_query(&mut params, "year", year.map(|v| v.to_string()));
391 push_query(&mut params, "limit", limit.map(|v| v.to_string()));
392
393 let mut request = self
394 .client
395 .get(format!("{}/api/v1/profile-activities", self.base_url));
396 if !params.is_empty() {
397 request = request.query(¶ms);
398 }
399 Ok(request
400 .send()
401 .await?
402 .json::<CursorListDTO<ProfileActivityDTO>>()
403 .await?)
404 }
405
406 async fn get_user_level_contributions(
407 &self,
408 user_id: &str,
409 year: u32,
410 ) -> Result<LevelContributionsDTO, Error> {
411 Ok(self
412 .client
413 .get(format!(
414 "{}/api/v1/users/{}/level-contributions/{}",
415 self.base_url, user_id, year
416 ))
417 .send()
418 .await?
419 .json::<LevelContributionsDTO>()
420 .await?)
421 }
422
423 async fn get_my_level_contributions(&self, year: u32) -> Result<LevelContributionsDTO, Error> {
424 Ok(self
425 .client
426 .get(format!(
427 "{}/api/v1/level-contributions/{}",
428 self.base_url, year
429 ))
430 .send()
431 .await?
432 .json::<LevelContributionsDTO>()
433 .await?)
434 }
435
436 async fn get_level_progress(&self) -> Result<LevelProgressDTO, Error> {
437 Ok(self
438 .client
439 .get(format!("{}/api/v1/level-progress", self.base_url))
440 .send()
441 .await?
442 .json::<LevelProgressDTO>()
443 .await?)
444 }
445
446 async fn get_content_length_limit(&self) -> Result<ContentLengthLimitDTO, Error> {
447 Ok(self
448 .client
449 .get(format!("{}/api/v1/content-length-limit", self.base_url))
450 .send()
451 .await?
452 .json::<ContentLengthLimitDTO>()
453 .await?)
454 }
455
456 async fn get_topic_collection_usage(&self) -> Result<TopicCollectionUsageDTO, Error> {
457 Ok(self
458 .client
459 .get(format!("{}/api/v1/topic-collection-usage", self.base_url))
460 .send()
461 .await?
462 .json::<TopicCollectionUsageDTO>()
463 .await?)
464 }
465
466 async fn get_file_storage(&self) -> Result<FileStorageDTO, Error> {
467 Ok(self
468 .client
469 .get(format!("{}/api/v1/file-storage", self.base_url))
470 .send()
471 .await?
472 .json::<FileStorageDTO>()
473 .await?)
474 }
475
476 async fn get_bookmarks(
477 &self,
478 limit: Option<u32>,
479 ) -> Result<CursorListDTO<serde_json::Value>, Error> {
480 let mut request = self
481 .client
482 .get(format!("{}/api/v1/bookmarks", self.base_url));
483 if let Some(limit) = limit {
484 request = request.query(&[("limit", limit)]);
485 }
486 Ok(request
487 .send()
488 .await?
489 .json::<CursorListDTO<serde_json::Value>>()
490 .await?)
491 }
492
493 async fn get_avatar_presets(&self) -> Result<AvatarPresetsDTO, Error> {
494 Ok(self
495 .client
496 .get(format!("{}/api/v1/avatar-presets", self.base_url))
497 .send()
498 .await?
499 .json::<AvatarPresetsDTO>()
500 .await?)
501 }
502}