Skip to main content

mangadex_api/v5/custom_list/
create.rs

1//! Builder for the CustomList creation endpoint.
2//!
3//! <https://api.mangadex.org/swagger.html#/CustomList/post-list>
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//! let _login_res = client
17//!     .auth()
18//!     .login()
19//!     .username(Username::parse("myusername")?)
20//!     .password(Password::parse("hunter23")?)
21//!     .build()?
22//!     .send()
23//!     .await?;
24//!
25//! let manga_id = Uuid::new_v4();
26//! let res = client
27//!     .custom_list()
28//!     .create()
29//!     .name("My Custom List")
30//!     .add_manga_id(manga_id)
31//!     .version(1_u32)
32//!     .build()?
33//!     .send()
34//!     .await?;
35//!
36//! println!("custom list create: {:?}", res);
37//! # Ok(())
38//! # }
39//! ```
40
41use derive_builder::Builder;
42use serde::Serialize;
43use uuid::Uuid;
44
45use crate::HttpClientRef;
46use mangadex_api_schema::v5::CustomListResponse;
47use mangadex_api_types::CustomListVisibility;
48
49#[derive(Debug, Serialize, Clone, Builder)]
50#[serde(rename_all = "camelCase")]
51#[builder(setter(into, strip_option), pattern = "owned")]
52#[non_exhaustive]
53pub struct CreateCustomList<'a> {
54    /// This should never be set manually as this is only for internal use.
55    #[doc(hidden)]
56    #[serde(skip)]
57    #[builder(pattern = "immutable")]
58    pub(crate) http_client: HttpClientRef,
59
60    pub name: &'a str,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    #[builder(default)]
63    pub visibility: Option<CustomListVisibility>,
64    #[serde(skip_serializing_if = "Vec::is_empty")]
65    #[builder(setter(each = "add_manga_id"), default)]
66    pub manga: Vec<Uuid>,
67    #[serde(skip_serializing_if = "Option::is_none")]
68    #[builder(default)]
69    pub version: Option<u32>,
70}
71
72endpoint! {
73    POST ("/list"),
74    #[body auth] CreateCustomList<'_>,
75    #[flatten_result] CustomListResponse
76}
77
78#[cfg(test)]
79mod tests {
80    use fake::faker::name::en::Name;
81    use fake::Fake;
82    use serde_json::json;
83    use url::Url;
84    use uuid::Uuid;
85    use wiremock::matchers::{header, method, path};
86    use wiremock::{Mock, MockServer, ResponseTemplate};
87
88    use crate::v5::AuthTokens;
89    use crate::{HttpClient, MangaDexClient};
90
91    #[tokio::test]
92    async fn create_custom_list_fires_a_request_to_base_url() -> 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 custom_list_id = Uuid::new_v4();
104        let custom_list_name: String = Name().fake();
105        let _expected_body = json!({
106            "name": custom_list_name,
107            "version": 1
108        });
109        let response_body = json!({
110            "result": "ok",
111            "response": "entity",
112            "data": {
113                "id": custom_list_id,
114                "type": "custom_list",
115                "attributes": {
116                    "name": custom_list_name,
117                    "visibility": "private",
118                    "version": 1
119                },
120                "relationships": []
121            }
122        });
123
124        Mock::given(method("POST"))
125            .and(path(r"/list"))
126            .and(header("Authorization", "Bearer sessiontoken"))
127            .and(header("Content-Type", "application/json"))
128            // TODO: Make the request body check work.
129            // .and(body_json(expected_body))
130            .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
131            .expect(1)
132            .mount(&mock_server)
133            .await;
134
135        let _ = mangadex_client
136            .custom_list()
137            .create()
138            .name(custom_list_name.as_str())
139            .version(1u32)
140            .build()?
141            .send()
142            .await?;
143
144        Ok(())
145    }
146}