threads_rs/api/
posts_read.rs1use std::collections::HashMap;
2
3use crate::client::Client;
4use crate::constants;
5use crate::error;
6use crate::types::{Post, PostId, PostsOptions, PostsResponse, PublishingLimits, UserId};
7use crate::validation;
8
9impl Client {
10 pub async fn get_post(&self, post_id: &PostId) -> crate::Result<Post> {
12 if !post_id.is_valid() {
13 return Err(error::new_validation_error(
14 0,
15 constants::ERR_EMPTY_POST_ID,
16 "",
17 "post_id",
18 ));
19 }
20
21 let token = self.access_token().await;
22 let mut params = HashMap::new();
23 params.insert("fields".into(), constants::POST_EXTENDED_FIELDS.into());
24
25 let path = format!("/{}", post_id);
26 let resp = self.http_client.get(&path, params, &token).await?;
27 resp.json()
28 }
29
30 pub async fn get_user_posts(
32 &self,
33 user_id: &UserId,
34 opts: Option<&PostsOptions>,
35 ) -> crate::Result<PostsResponse> {
36 if !user_id.is_valid() {
37 return Err(error::new_validation_error(
38 0,
39 constants::ERR_EMPTY_USER_ID,
40 "",
41 "user_id",
42 ));
43 }
44
45 if let Some(opts) = opts {
46 validation::validate_posts_options(opts)?;
47 }
48
49 let token = self.access_token().await;
50 let mut params = HashMap::new();
51 params.insert("fields".into(), constants::POST_EXTENDED_FIELDS.into());
52
53 if let Some(opts) = opts {
54 if let Some(limit) = opts.limit {
55 params.insert("limit".into(), limit.to_string());
56 }
57 if let Some(ref before) = opts.before {
58 params.insert("before".into(), before.clone());
59 }
60 if let Some(ref after) = opts.after {
61 params.insert("after".into(), after.clone());
62 }
63 if let Some(since) = opts.since {
64 params.insert("since".into(), since.to_string());
65 }
66 if let Some(until) = opts.until {
67 params.insert("until".into(), until.to_string());
68 }
69 }
70
71 let path = format!("/{}/threads", user_id);
72 let resp = self.http_client.get(&path, params, &token).await?;
73 resp.json()
74 }
75
76 pub async fn get_user_mentions(
81 &self,
82 user_id: &UserId,
83 opts: Option<&PostsOptions>,
84 ) -> crate::Result<PostsResponse> {
85 if !user_id.is_valid() {
86 return Err(error::new_validation_error(
87 0,
88 constants::ERR_EMPTY_USER_ID,
89 "",
90 "user_id",
91 ));
92 }
93
94 if let Some(opts) = opts {
95 validation::validate_posts_options(opts)?;
96 }
97
98 let token = self.access_token().await;
99 let mut params = HashMap::new();
100 params.insert("fields".into(), constants::POST_EXTENDED_FIELDS.into());
101
102 if let Some(opts) = opts {
103 if let Some(limit) = opts.limit {
104 params.insert("limit".into(), limit.to_string());
105 }
106 if let Some(ref before) = opts.before {
107 params.insert("before".into(), before.clone());
108 }
109 if let Some(ref after) = opts.after {
110 params.insert("after".into(), after.clone());
111 }
112 if let Some(since) = opts.since {
113 params.insert("since".into(), since.to_string());
114 }
115 if let Some(until) = opts.until {
116 params.insert("until".into(), until.to_string());
117 }
118 }
119
120 let path = format!("/{}/mentions", user_id);
121 let resp = self.http_client.get(&path, params, &token).await?;
122 resp.json()
123 }
124
125 pub async fn get_user_ghost_posts(
130 &self,
131 user_id: &UserId,
132 opts: Option<&PostsOptions>,
133 ) -> crate::Result<PostsResponse> {
134 if !user_id.is_valid() {
135 return Err(error::new_validation_error(
136 0,
137 constants::ERR_EMPTY_USER_ID,
138 "",
139 "user_id",
140 ));
141 }
142
143 if let Some(opts) = opts {
144 validation::validate_posts_options(opts)?;
145 }
146
147 let token = self.access_token().await;
148 let mut params = HashMap::new();
149 params.insert("fields".into(), constants::GHOST_POST_FIELDS.into());
150
151 if let Some(opts) = opts {
152 if let Some(limit) = opts.limit {
153 params.insert("limit".into(), limit.to_string());
154 }
155 if let Some(ref before) = opts.before {
156 params.insert("before".into(), before.clone());
157 }
158 if let Some(ref after) = opts.after {
159 params.insert("after".into(), after.clone());
160 }
161 if let Some(since) = opts.since {
162 params.insert("since".into(), since.to_string());
163 }
164 if let Some(until) = opts.until {
165 params.insert("until".into(), until.to_string());
166 }
167 }
168
169 let path = format!("/{}/ghost_posts", user_id);
170 let resp = self.http_client.get(&path, params, &token).await?;
171 resp.json()
172 }
173
174 pub async fn get_publishing_limits(&self) -> crate::Result<PublishingLimits> {
176 let user_id = self.user_id().await;
177 if user_id.is_empty() {
178 return Err(error::new_authentication_error(
179 401,
180 constants::ERR_EMPTY_USER_ID,
181 "No user ID available from token",
182 ));
183 }
184
185 let token = self.access_token().await;
186 let mut params = HashMap::new();
187 params.insert("fields".into(), constants::PUBLISHING_LIMIT_FIELDS.into());
188
189 let path = format!("/{}/threads_publishing_limit", user_id);
190 let resp = self.http_client.get(&path, params, &token).await?;
191
192 #[derive(serde::Deserialize)]
194 struct Wrapper {
195 data: Vec<PublishingLimits>,
196 }
197
198 let wrapper: Wrapper = resp.json()?;
199 wrapper
200 .data
201 .into_iter()
202 .next()
203 .ok_or_else(|| error::new_api_error(0, "No publishing limits data returned", "", ""))
204 }
205}