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