mangadex_api/v5/upload/check_approval_required/
post.rs

1//! Builder for checking if a given manga / locale for a User needs moderation approval.
2//!
3//! <https://api.mangadex.org/docs/swagger.html#/Upload/upload-check-approval-required>
4//!
5//! ```rust
6//! use uuid::Uuid;
7//!
8//! use mangadex_api::MangaDexClient;
9//! // use mangadex_api_types::{Password, Username};
10//! use mangadex_api_types::Language;
11//!
12//! # async fn run() -> anyhow::Result<()> {
13//! let client = MangaDexClient::default();
14//!
15//! /*
16//!
17//!     let _login_res = client
18//!         .auth()
19//!         .login()
20//!         .post()
21//!         .username(Username::parse("myusername")?)
22//!         .password(Password::parse("hunter23")?)
23//!         .send()
24//!         .await?;
25//!
26//!  */
27//!
28//! let manga_id = Uuid::new_v4();
29//! let res = client
30//!     .upload()
31//!     .check_approval_required()
32//!     .post()
33//!     .manga_id(manga_id)
34//!     .locale(Language::English)
35//!     .send()
36//!     .await?;
37//!
38//! println!("session start: {:?}", res);
39//! # Ok(())
40//! # }
41//! ```
42
43use derive_builder::Builder;
44use mangadex_api_schema::v5::upload_required_approval::UploadRequiredApproval;
45use mangadex_api_types::Language;
46use serde::Serialize;
47use uuid::Uuid;
48
49use crate::HttpClientRef;
50
51/// Check if a given manga / locale for a User needs moderation approval.
52///
53/// This requires authentication.
54///
55/// Makes a request to `POST /upload/check-approval-required`.
56#[cfg_attr(
57    feature = "deserializable-endpoint",
58    derive(serde::Deserialize, getset::Getters, getset::Setters)
59)]
60#[derive(Debug, Builder, Serialize, Clone)]
61#[serde(rename_all = "camelCase")]
62#[builder(
63    setter(into, strip_option),
64    build_fn(error = "mangadex_api_types::error::BuilderError")
65)]
66pub struct CheckApprovalRequired {
67    /// This should never be set manually as this is only for internal use.
68    #[doc(hidden)]
69    #[serde(skip)]
70    #[builder(pattern = "immutable")]
71    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
72    pub http_client: HttpClientRef,
73
74    #[serde(rename = "manga")]
75    pub manga_id: Uuid,
76    pub locale: Language,
77}
78
79endpoint! {
80    POST "/upload/check-approval-required",
81    #[body auth] CheckApprovalRequired,
82    #[rate_limited] UploadRequiredApproval,
83    CheckApprovalRequiredBuilder
84}
85
86#[cfg(test)]
87mod tests {
88    use serde_json::json;
89    use url::Url;
90    use uuid::Uuid;
91    use wiremock::matchers::{body_json, header, method, path_regex};
92    use wiremock::{Mock, MockServer, ResponseTemplate};
93
94    use crate::v5::AuthTokens;
95    use crate::{HttpClient, MangaDexClient};
96    use mangadex_api_types::Language;
97
98    use serde::Serialize;
99
100    #[derive(Clone, Serialize, Debug)]
101    #[serde(rename_all = "camelCase")]
102    struct ExceptedBody {
103        manga: Uuid,
104        locale: Language,
105    }
106
107    #[tokio::test]
108    async fn check_approval_required_fires_a_request_to_base_url() -> anyhow::Result<()> {
109        let mock_server = MockServer::start().await;
110        let http_client = HttpClient::builder()
111            .base_url(Url::parse(&mock_server.uri())?)
112            .auth_tokens(AuthTokens {
113                session: "sessiontoken".to_string(),
114                refresh: "refreshtoken".to_string(),
115            })
116            .build()?;
117        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
118
119        let manga = Uuid::new_v4();
120        let locale = Language::English;
121
122        let expected_body = ExceptedBody { manga, locale };
123
124        let response_body = json!({
125            "result": "ok",
126            "requiresApproval": false
127        });
128        Mock::given(method("POST"))
129            .and(path_regex(r"/upload/check-approval-required"))
130            .and(header("authorization", "Bearer sessiontoken"))
131            .and(header("content-type", "application/json"))
132            .and(body_json(expected_body))
133            .respond_with(
134                ResponseTemplate::new(200)
135                    .insert_header("x-ratelimit-retry-after", "1698723860")
136                    .insert_header("x-ratelimit-limit", "40")
137                    .insert_header("x-ratelimit-remaining", "39")
138                    .set_body_json(response_body),
139            )
140            .expect(1)
141            .mount(&mock_server)
142            .await;
143
144        let res = mangadex_client
145            .upload()
146            .check_approval_required()
147            .post()
148            .locale(locale)
149            .manga_id(manga)
150            .send()
151            .await?;
152
153        let res = res.body;
154
155        assert!(!res.requires_approval.unwrap());
156
157        Ok(())
158    }
159    #[tokio::test]
160    async fn check_approval_required_parses_404_not_found() -> anyhow::Result<()> {
161        let mock_server = MockServer::start().await;
162        let http_client = HttpClient::builder()
163            .base_url(Url::parse(&mock_server.uri())?)
164            .auth_tokens(AuthTokens {
165                session: "sessiontoken".to_string(),
166                refresh: "refreshtoken".to_string(),
167            })
168            .build()?;
169        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
170
171        let manga = Uuid::new_v4();
172        let locale = Language::English;
173
174        let expected_body = ExceptedBody { manga, locale };
175
176        let response_body = json!({
177            "result": "ok"
178        });
179        Mock::given(method("POST"))
180            .and(path_regex(r"/upload/check-approval-required"))
181            .and(header("authorization", "Bearer sessiontoken"))
182            .and(header("content-type", "application/json"))
183            .and(body_json(expected_body))
184            .respond_with(
185                ResponseTemplate::new(404)
186                    .insert_header("x-ratelimit-retry-after", "1698723860")
187                    .insert_header("x-ratelimit-limit", "40")
188                    .insert_header("x-ratelimit-remaining", "39")
189                    .set_body_json(response_body),
190            )
191            .expect(1)
192            .mount(&mock_server)
193            .await;
194
195        let res = mangadex_client
196            .upload()
197            .check_approval_required()
198            .post()
199            .locale(locale)
200            .manga_id(manga)
201            .send()
202            .await?;
203
204        let res = res.body;
205
206        assert!(res.is_manga_not_found());
207
208        Ok(())
209    }
210}