mangadex_api/v5/upload/upload_session_id/batch/
delete.rs

1//! Builder for deleting a set of uploaded images from an upload session.
2//!
3//! <https://api.mangadex.org/docs/swagger.html#/Upload/delete-uploaded-session-files>
4//!
5//! # Examples
6//!
7//! ```rust
8//! use uuid::Uuid;
9//!
10//! use mangadex_api::v5::MangaDexClient;
11//! // use mangadex_api_types::{Password, Username};
12//!
13//! # async fn run() -> anyhow::Result<()> {
14//! let client = MangaDexClient::default();
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 session_id = Uuid::new_v4();
29//! let session_file_id = Uuid::new_v4();
30//!
31//! let res = client
32//!     .upload()
33//!     .upload_session_id(session_id)
34//!     .batch()
35//!     .delete()
36//!     .add_session_file_id(session_file_id)
37//!     .send()
38//!     .await?;
39//!
40//! println!("delete images: {:?}", res);
41//! # Ok(())
42//! # }
43//! ```
44
45use std::borrow::Cow;
46
47use derive_builder::Builder;
48use mangadex_api_schema::{Endpoint, Limited, NoData};
49use serde::Serialize;
50use uuid::Uuid;
51
52use crate::HttpClientRef;
53use mangadex_api_types::error::Result;
54
55#[cfg_attr(
56    feature = "deserializable-endpoint",
57    derive(serde::Deserialize, getset::Getters, getset::Setters)
58)]
59#[derive(Debug, Serialize, Clone, Builder)]
60#[serde(rename_all = "camelCase")]
61#[builder(
62    setter(into, strip_option),
63    build_fn(error = "mangadex_api_types::error::BuilderError")
64)]
65pub struct DeleteImages {
66    /// This should never be set manually as this is only for internal use.
67    #[doc(hidden)]
68    #[serde(skip)]
69    #[builder(pattern = "immutable")]
70    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
71    pub http_client: HttpClientRef,
72
73    #[serde(skip_serializing)]
74    pub session_id: Uuid,
75    #[builder(setter(each = "add_session_file_id"))]
76    pub session_file_ids: Vec<Uuid>,
77}
78
79// MangaDex takes an array for the request body rather than a traditional JSON body for this endpoint.
80impl Endpoint for DeleteImages {
81    type Query = ();
82    type Body = Vec<Uuid>;
83    type Response = NoData;
84
85    fn path(&self) -> Cow<str> {
86        Cow::Owned(format!("/upload/{}/batch", self.session_id))
87    }
88
89    fn method(&self) -> reqwest::Method {
90        reqwest::Method::DELETE
91    }
92
93    fn require_auth(&self) -> bool {
94        true
95    }
96
97    fn body(&self) -> Option<&Vec<Uuid>> {
98        Some(&self.session_file_ids)
99    }
100}
101
102impl DeleteImages {
103    pub async fn send(&self) -> Result<Limited<NoData>> {
104        #[cfg(all(
105            not(feature = "multi-thread"),
106            not(feature = "tokio-multi-thread"),
107            not(feature = "rw-multi-thread")
108        ))]
109        {
110            self.http_client
111                .try_borrow()?
112                .send_request_with_rate_limit(self)
113                .await
114        }
115        #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
116        {
117            self.http_client
118                .lock()
119                .await
120                .send_request_with_rate_limit(self)
121                .await
122        }
123        #[cfg(feature = "rw-multi-thread")]
124        {
125            self.http_client
126                .read()
127                .await
128                .send_request_with_rate_limit(self)
129                .await
130        }
131    }
132}
133
134builder_send! {
135    #[builder] DeleteImagesBuilder,
136    #[rate_limited] NoData
137}
138
139#[cfg(test)]
140mod tests {
141    use serde_json::json;
142    use url::Url;
143    use uuid::Uuid;
144    use wiremock::matchers::{body_json, header, method, path_regex};
145    use wiremock::{Mock, MockServer, ResponseTemplate};
146
147    use crate::v5::AuthTokens;
148    use crate::{HttpClient, MangaDexClient};
149
150    #[tokio::test]
151    async fn delete_images_fires_a_request_to_base_url() -> anyhow::Result<()> {
152        let mock_server = MockServer::start().await;
153        let http_client = HttpClient::builder()
154            .base_url(Url::parse(&mock_server.uri())?)
155            .auth_tokens(AuthTokens {
156                session: "sessiontoken".to_string(),
157                refresh: "refreshtoken".to_string(),
158            })
159            .build()?;
160        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
161
162        let session_id = Uuid::new_v4();
163        let session_file_id = Uuid::new_v4();
164        let expected_body = json!([session_file_id]);
165        let response_body = json!({
166            "result": "ok",
167        });
168
169        Mock::given(method("DELETE"))
170            .and(path_regex(r"/upload/[0-9a-fA-F-]+/batch"))
171            .and(header("Authorization", "Bearer sessiontoken"))
172            .and(body_json(expected_body))
173            .respond_with(
174                ResponseTemplate::new(200)
175                    .insert_header("x-ratelimit-retry-after", "1698723860")
176                    .insert_header("x-ratelimit-limit", "40")
177                    .insert_header("x-ratelimit-remaining", "39")
178                    .set_body_json(response_body),
179            )
180            .expect(1)
181            .mount(&mock_server)
182            .await;
183
184        let _ = mangadex_client
185            .upload()
186            .upload_session_id(session_id)
187            .batch()
188            .delete()
189            .add_session_file_id(session_file_id)
190            .send()
191            .await?;
192
193        Ok(())
194    }
195}