mangadex_api/v5/forums/thread/
post.rs1use crate::HttpClientRef;
43use derive_builder::Builder;
44use mangadex_api_schema::v5::ForumThreadResponseData;
45use mangadex_api_types::ForumThreadType;
46use serde::Serialize;
47use uuid::Uuid;
48
49#[cfg_attr(
50 feature = "deserializable-endpoint",
51 derive(serde::Deserialize, getset::Getters, getset::Setters)
52)]
53#[derive(Debug, Serialize, Clone, Builder)]
54#[serde(rename_all = "camelCase")]
55#[builder(
56 setter(into, strip_option),
57 build_fn(error = "mangadex_api_types::error::BuilderError")
58)]
59#[cfg_attr(feature = "non_exhaustive", non_exhaustive)]
60pub struct CreateForumThread {
61 #[doc(hidden)]
63 #[serde(skip)]
64 #[builder(pattern = "immutable")]
65 #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
66 pub http_client: HttpClientRef,
67
68 pub type_: ForumThreadType,
69 pub id: Uuid,
70}
71
72endpoint! {
73 POST "/forums/thread",
74 #[body auth] CreateForumThread,
75 #[rate_limited] ForumThreadResponseData,
76 CreateForumThreadBuilder
77}
78
79#[cfg(test)]
80mod tests {
81 use serde_json::json;
82 use url::Url;
83 use uuid::Uuid;
84 use wiremock::matchers::{body_json, header, method, path_regex};
85 use wiremock::{Mock, MockServer, ResponseTemplate};
86
87 use crate::v5::AuthTokens;
88 use crate::{HttpClient, MangaDexClient};
89 use mangadex_api_types::ForumThreadType;
90
91 #[tokio::test]
92 async fn create_a_forums_thread_handle_ok() -> anyhow::Result<()> {
93 let mock_server = MockServer::start().await;
94 let http_client = HttpClient::builder()
95 .base_url(Url::parse(&mock_server.uri())?)
96 .auth_tokens(AuthTokens {
97 session: "sessiontoken".to_string(),
98 refresh: "refreshtoken".to_string(),
99 })
100 .build()?;
101 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
102
103 let body_id = Uuid::new_v4();
104 let response_body = json!({
105 "result": "ok",
106 "response": "entity",
107 "data": {
108 "type": "thread",
109 "id": 0,
110 "attributes": {
111 "repliesCount": 0
112 }
113 }
114 });
115
116 Mock::given(method("POST"))
117 .and(path_regex("/forums/thread"))
118 .and(header("Authorization", "Bearer sessiontoken"))
119 .and(header("Content-Type", "application/json"))
120 .and(body_json(json!({
121 "type": "manga",
122 "id": body_id
123 })))
124 .respond_with(
125 ResponseTemplate::new(200)
126 .insert_header("x-ratelimit-retry-after", "1698723860")
127 .insert_header("x-ratelimit-limit", "40")
128 .insert_header("x-ratelimit-remaining", "39")
129 .set_body_json(response_body),
130 )
131 .expect(1)
132 .mount(&mock_server)
133 .await;
134
135 mangadex_client
136 .forums()
137 .thread()
138 .post()
139 .id(body_id)
140 .type_(ForumThreadType::Manga)
141 .send()
142 .await?;
143
144 Ok(())
145 }
146
147 #[tokio::test]
148 async fn create_a_forums_thread_handle_403_error() -> anyhow::Result<()> {
149 let mock_server = MockServer::start().await;
150 let http_client = HttpClient::builder()
151 .base_url(Url::parse(&mock_server.uri())?)
152 .auth_tokens(AuthTokens {
153 session: "sessiontoken".to_string(),
154 refresh: "refreshtoken".to_string(),
155 })
156 .build()?;
157 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
158
159 let body_id = Uuid::new_v4();
160 let response_body = json!({
161 "result": "error",
162 "errors": [
163 {
164 "id": "string",
165 "status": 0,
166 "title": "string",
167 "detail": "string"
168 }
169 ]
170 });
171
172 Mock::given(method("POST"))
173 .and(path_regex("/forums/thread"))
174 .and(header("Authorization", "Bearer sessiontoken"))
175 .and(header("Content-Type", "application/json"))
176 .and(body_json(json!({
177 "type": "manga",
178 "id": body_id
179 })))
180 .respond_with(
181 ResponseTemplate::new(403)
182 .insert_header("x-ratelimit-retry-after", "1698723860")
183 .insert_header("x-ratelimit-limit", "40")
184 .insert_header("x-ratelimit-remaining", "39")
185 .set_body_json(response_body),
186 )
187 .expect(1)
188 .mount(&mock_server)
189 .await;
190
191 mangadex_client
192 .forums()
193 .thread()
194 .post()
195 .id(body_id)
196 .type_(ForumThreadType::Manga)
197 .send()
198 .await
199 .expect_err("an error should be received");
200
201 Ok(())
202 }
203
204 #[tokio::test]
205 async fn create_a_forums_thread_handle_404_error() -> anyhow::Result<()> {
206 let mock_server = MockServer::start().await;
207 let http_client = HttpClient::builder()
208 .base_url(Url::parse(&mock_server.uri())?)
209 .auth_tokens(AuthTokens {
210 session: "sessiontoken".to_string(),
211 refresh: "refreshtoken".to_string(),
212 })
213 .build()?;
214 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
215
216 let body_id = Uuid::new_v4();
217 let response_body = json!({
218 "result": "error",
219 "errors": [
220 {
221 "id": "string",
222 "status": 0,
223 "title": "string",
224 "detail": "string"
225 }
226 ]
227 });
228
229 Mock::given(method("POST"))
230 .and(path_regex("/forums/thread"))
231 .and(header("Authorization", "Bearer sessiontoken"))
232 .and(header("Content-Type", "application/json"))
233 .and(body_json(json!({
234 "type": "manga",
235 "id": body_id
236 })))
237 .respond_with(
238 ResponseTemplate::new(404)
239 .insert_header("x-ratelimit-retry-after", "1698723860")
240 .insert_header("x-ratelimit-limit", "40")
241 .insert_header("x-ratelimit-remaining", "39")
242 .set_body_json(response_body),
243 )
244 .expect(1)
245 .mount(&mock_server)
246 .await;
247
248 mangadex_client
249 .forums()
250 .thread()
251 .post()
252 .id(body_id)
253 .type_(ForumThreadType::Manga)
254 .send()
255 .await
256 .expect_err("an error should be received");
257
258 Ok(())
259 }
260}