1use super::model::*;
2use super::Error;
3use super::{delete, get, handle_response, patch, API_URL};
4use crate::auth::OAuth;
5use serde::Serialize;
6
7#[derive(Clone, Debug, Serialize)]
8pub struct UpdateUserMangaStatus {
9 #[serde(skip_serializing_if = "Option::is_none")]
10 pub status: Option<UserReadStatus>,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub is_rereading: Option<bool>,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub score: Option<u8>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub num_volumes_read: Option<u64>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub num_chapters_read: Option<u64>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub priority: Option<u8>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub num_times_reread: Option<u8>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub reread_value: Option<u8>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub tags: Option<String>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub comments: Option<String>,
29}
30
31pub async fn update_manga_list_status(
32 manga_id: u64,
33 update: &UpdateUserMangaStatus,
34 auth: &OAuth,
35) -> Result<UserMangaListStatus, Error> {
36 let response = patch(
37 &format!("{}/manga/{}/my_list_status", API_URL, manga_id),
38 auth,
39 update,
40 )
41 .await?;
42 handle_response(&response)
43}
44
45pub async fn delete_manga_from_list(manga_id: u64, auth: &OAuth) -> Result<(), Error> {
46 let response = delete(
47 &format!("{}/manga/{}/my_list_status", API_URL, manga_id),
48 auth,
49 )
50 .await?;
51 if response.status.is_success() {
52 Ok(())
53 } else {
54 Err(Error::HttpError(response.status))
55 }
56}
57
58#[derive(Clone, Debug, Serialize)]
59pub struct GetUserMangaListQuery {
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub fields: Option<String>,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub status: Option<UserReadStatus>,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub sort: Option<SortStyle>,
66 pub limit: u64,
67 pub offset: u64,
68 pub nsfw: bool,
69}
70
71pub async fn get_user_manga_list<U: ToString>(
72 user: U,
73 query: &GetUserMangaListQuery,
74 auth: &OAuth,
75) -> Result<Page<Manga>, Error> {
76 let response = get(
77 &format!(
78 "{}/users/{}/mangalist?{}",
79 API_URL,
80 user.to_string(),
81 serde_urlencoded::to_string(query)?
82 ),
83 auth,
84 )
85 .await?;
86 handle_response(&response)
87}
88
89#[cfg(test)]
90mod test {
91 use super::*;
92 use crate::api::manga::tests::*;
93
94 #[tokio::test]
95 async fn test_delete_manga_from_list() {
96 let auth = crate::auth::tests::get_auth();
97 let manga = get_manga("Grand Blue", &auth).await.unwrap();
98 delete_manga_from_list(manga.id, &auth).await.unwrap();
99 }
100
101 #[tokio::test]
102 async fn test_update_manga_list() {
103 let auth = crate::auth::tests::get_auth();
104 let query = UpdateUserMangaStatus {
105 status: Some(UserReadStatus::Reading),
106 is_rereading: None,
107 score: Some(9),
108 num_volumes_read: None,
109 num_chapters_read: Some(62),
110 priority: None,
111 num_times_reread: None,
112 reread_value: None,
113 tags: None,
114 comments: None,
115 };
116 let manga = get_manga("Grand Blue", &auth).await.unwrap();
117 let result = update_manga_list_status(manga.id, &query, &auth)
118 .await
119 .unwrap();
120 println!("{:#?}", result);
121 assert_eq!(result.num_chapters_read, 62);
122 }
123
124 #[tokio::test]
125 async fn test_get_user_manga_list() {
126 let auth = crate::auth::tests::get_auth();
127 let query = GetUserMangaListQuery {
128 fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
129 status: None,
130 sort: None,
131 limit: 100,
132 offset: 0,
133 nsfw: true,
134 };
135 let result = get_user_manga_list("@me", &query, &auth).await.unwrap();
136
137 print!("{:#?}", result);
138
139 assert!(!result.data.is_empty());
140 }
141}