Skip to main content

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 = "crate::error::BuilderError")
64)]
65#[non_exhaustive]
66pub struct StartEditChapterSession {
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(skip_serializing)]
75    pub chapter_id: Uuid,
76
77    pub version: u32,
78}
79
80endpoint! {
81    POST ("/upload/begin/{}", chapter_id),
82    #[body auth] StartEditChapterSession,
83    #[rate_limited] UploadSessionData,
84    StartEditChapterSessionBuilder
85}
86
87#[cfg(test)]
88mod tests {
89    use serde_json::json;
90    use time::OffsetDateTime;
91    use url::Url;
92    use uuid::Uuid;
93    use wiremock::matchers::{body_json, header, method, path_regex};
94    use wiremock::{Mock, MockServer, ResponseTemplate};
95
96    use crate::v5::AuthTokens;
97    use crate::{HttpClient, MangaDexClient};
98    use mangadex_api_types::{MangaDexDateTime, RelationshipType};
99
100    #[tokio::test]
101    async fn start_edit_chapter_session_fires_a_request_to_base_url() -> anyhow::Result<()> {
102        let mock_server = MockServer::start().await;
103        let http_client: HttpClient = HttpClient::builder()
104            .base_url(Url::parse(&mock_server.uri())?)
105            .auth_tokens(non_exhaustive::non_exhaustive!(AuthTokens {
106                session: "sessiontoken".to_string(),
107                refresh: "refreshtoken".to_string(),
108            }))
109            .build()?;
110        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
111
112        let chapter_id = Uuid::new_v4();
113        let session_id = Uuid::new_v4();
114
115        let datetime = MangaDexDateTime::new(&OffsetDateTime::now_utc());
116
117        let expected_body = json!({
118            "version": 2,
119        });
120        let response_body = json!({
121            "result": "ok",
122            "response": "entity",
123            "data" : {
124                "id": session_id,
125                "type": "upload_session",
126                "attributes": {
127                    "isCommitted": false,
128                    "isProcessed": false,
129                    "isDeleted": false,
130                    "version": 2,
131                    "createdAt": datetime.to_string(),
132                    "updatedAt": datetime.to_string(),
133                },
134                "relationships": []
135            }
136        });
137
138        Mock::given(method("POST"))
139            .and(path_regex("/upload/begin/[0-9a-fA-F-]+"))
140            .and(header("Authorization", "Bearer sessiontoken"))
141            .and(header("Content-Type", "application/json"))
142            .and(body_json(expected_body))
143            .respond_with(
144                ResponseTemplate::new(200)
145                    .insert_header("x-ratelimit-retry-after", "1698723860")
146                    .insert_header("x-ratelimit-limit", "40")
147                    .insert_header("x-ratelimit-remaining", "39")
148                    .set_body_json(response_body),
149            )
150            .expect(1)
151            .mount(&mock_server)
152            .await;
153
154        let res = mangadex_client
155            .upload()
156            .begin()
157            .chapter_id(chapter_id)
158            .post()
159            .version(2_u32)
160            .send()
161            .await?;
162
163        let res = &res.data;
164
165        assert_eq!(res.id, session_id);
166        assert_eq!(res.type_, RelationshipType::UploadSession);
167        assert!(!res.attributes.is_committed);
168        assert!(!res.attributes.is_processed);
169        assert!(!res.attributes.is_deleted);
170        assert_eq!(res.attributes.version, 2);
171        assert_eq!(res.attributes.created_at.to_string(), datetime.to_string());
172        assert_eq!(res.attributes.updated_at.to_string(), datetime.to_string());
173
174        Ok(())
175    }
176}