mangadex_api/v5/upload/begin/chapter_id/
post.rs

1//! Builder for starting an edit chapter session.
2//!
3//! <https://api.mangadex.org/docs/swagger.html#/Upload/begin-edit-session>
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 chapter_id = Uuid::new_v4();
29//! let res = client
30//!     .upload()
31//!     .begin()
32//!     .chapter_id(chapter_id)
33//!     .post()
34//!     .version(2_u32)
35//!     .send()
36//!     .await?;
37//!
38//! println!("edit chapter session start: {:?}", res);
39//! # Ok(())
40//! # }
41//! ```
42
43use derive_builder::Builder;
44use mangadex_api_schema::v5::UploadSessionData;
45use serde::Serialize;
46use uuid::Uuid;
47
48use crate::HttpClientRef;
49
50/// Start an edit chapter session.
51///
52/// This requires authentication.
53///
54/// Makes a request to `POST /upload/begin/{id}`.
55#[cfg_attr(
56    feature = "deserializable-endpoint",
57    derive(serde::Deserialize, getset::Getters, getset::Setters)
58)]
59#[derive(Debug, Builder, Serialize, Clone)]
60#[serde(rename_all = "camelCase")]
61#[builder(
62    setter(into, strip_option),
63    build_fn(error = "mangadex_api_types::error::BuilderError")
64)]
65pub struct StartEditChapterSession {
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 chapter_id: Uuid,
75
76    pub version: u32,
77}
78
79endpoint! {
80    POST ("/upload/begin/{}", chapter_id),
81    #[body auth] StartEditChapterSession,
82    #[rate_limited] UploadSessionData,
83    StartEditChapterSessionBuilder
84}
85
86#[cfg(test)]
87mod tests {
88    use serde_json::json;
89    use time::OffsetDateTime;
90    use url::Url;
91    use uuid::Uuid;
92    use wiremock::matchers::{body_json, header, method, path_regex};
93    use wiremock::{Mock, MockServer, ResponseTemplate};
94
95    use crate::v5::AuthTokens;
96    use crate::{HttpClient, MangaDexClient};
97    use mangadex_api_types::{MangaDexDateTime, RelationshipType};
98
99    #[tokio::test]
100    async fn start_edit_chapter_session_fires_a_request_to_base_url() -> anyhow::Result<()> {
101        let mock_server = MockServer::start().await;
102        let http_client: HttpClient = HttpClient::builder()
103            .base_url(Url::parse(&mock_server.uri())?)
104            .auth_tokens(AuthTokens {
105                session: "sessiontoken".to_string(),
106                refresh: "refreshtoken".to_string(),
107            })
108            .build()?;
109        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
110
111        let chapter_id = Uuid::new_v4();
112        let session_id = Uuid::new_v4();
113
114        let datetime = MangaDexDateTime::new(&OffsetDateTime::now_utc());
115
116        let expected_body = json!({
117            "version": 2,
118        });
119        let response_body = json!({
120            "result": "ok",
121            "response": "entity",
122            "data" : {
123                "id": session_id,
124                "type": "upload_session",
125                "attributes": {
126                    "isCommitted": false,
127                    "isProcessed": false,
128                    "isDeleted": false,
129                    "version": 2,
130                    "createdAt": datetime.to_string(),
131                    "updatedAt": datetime.to_string(),
132                },
133                "relationships": []
134            }
135        });
136
137        Mock::given(method("POST"))
138            .and(path_regex("/upload/begin/[0-9a-fA-F-]+"))
139            .and(header("Authorization", "Bearer sessiontoken"))
140            .and(header("Content-Type", "application/json"))
141            .and(body_json(expected_body))
142            .respond_with(
143                ResponseTemplate::new(200)
144                    .insert_header("x-ratelimit-retry-after", "1698723860")
145                    .insert_header("x-ratelimit-limit", "40")
146                    .insert_header("x-ratelimit-remaining", "39")
147                    .set_body_json(response_body),
148            )
149            .expect(1)
150            .mount(&mock_server)
151            .await;
152
153        let res = mangadex_client
154            .upload()
155            .begin()
156            .chapter_id(chapter_id)
157            .post()
158            .version(2_u32)
159            .send()
160            .await?;
161
162        let res = &res.data;
163
164        assert_eq!(res.id, session_id);
165        assert_eq!(res.type_, RelationshipType::UploadSession);
166        assert!(!res.attributes.is_committed);
167        assert!(!res.attributes.is_processed);
168        assert!(!res.attributes.is_deleted);
169        assert_eq!(res.attributes.version, 2);
170        assert_eq!(res.attributes.created_at.to_string(), datetime.to_string());
171        assert_eq!(res.attributes.updated_at.to_string(), datetime.to_string());
172
173        Ok(())
174    }
175}