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)]
9pub struct UpdateUserAnimeListStatusQuery {
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub status: Option<UserWatchStatus>,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub is_rewatching: Option<bool>,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub score: Option<u8>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub num_watched_episodes: Option<u64>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub priority: Option<u8>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub num_times_rewatched: Option<u64>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub rewatch_value: Option<u8>,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub tags: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub comments: Option<String>,
28}
29
30pub async fn update_anime_list_status(
31 anime_id: u64,
32 update: &UpdateUserAnimeListStatusQuery,
33 auth: &OAuth,
34) -> Result<UserAnimeListStatus, Error> {
35 let response = patch(
36 &format!("{}/anime/{}/my_list_status", API_URL, anime_id,),
37 auth,
38 update,
39 )
40 .await?;
41 handle_response(&response)
42}
43
44pub async fn delete_anime_from_list(anime_id: u64, auth: &OAuth) -> Result<(), Error> {
45 let response = delete(
46 &format!("{}/anime/{}/my_list_status", API_URL, anime_id),
47 auth,
48 )
49 .await?;
50 if response.status.is_success() {
51 Ok(())
52 } else {
53 Err(Error::HttpError(response.status))
54 }
55}
56
57#[derive(Clone, Debug, Serialize)]
58pub struct GetUserAnimeListQuery {
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub fields: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub status: Option<UserWatchStatus>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub sort: Option<SortStyle>,
65 pub limit: u64,
66 pub offset: u64,
67 pub nsfw: bool,
68}
69
70pub async fn get_user_anime_list<U: ToString>(
71 user: U,
72 query: &GetUserAnimeListQuery,
73 auth: &OAuth,
74) -> Result<Page<Anime>, Error> {
75 let response = get(
76 &format!(
77 "{}/users/{}/animelist?{}",
78 API_URL,
79 user.to_string(),
80 serde_urlencoded::to_string(query)?
81 ),
82 auth,
83 )
84 .await?;
85 handle_response(&response)
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::api::anime::tests::*;
92
93 #[tokio::test]
94 #[ignore]
95 async fn test_delete_anime_from_list() {
96 let auth = crate::auth::tests::get_auth();
97 let anime = get_anime("God of High School", &auth).await.unwrap();
98 delete_anime_from_list(anime.id, &auth).await.unwrap();
99 }
100
101 #[tokio::test]
102 async fn test_update_anime_list() {
103 let auth = crate::auth::tests::get_auth();
104 let query = UpdateUserAnimeListStatusQuery {
105 status: Some(UserWatchStatus::Completed),
106 is_rewatching: None,
107 score: Some(8),
108 num_watched_episodes: Some(13),
109 priority: None,
110 num_times_rewatched: None,
111 rewatch_value: None,
112 tags: None,
113 comments: None,
114 };
115
116 let anime = get_anime(
117 "Yahari Ore no Seishun Love Comedy wa Machigatteiru. Kan",
118 &auth,
119 )
120 .await
121 .unwrap();
122
123 let result = update_anime_list_status(anime.id, &query, &auth)
124 .await
125 .unwrap();
126 println!("{:#?}", result);
127 assert_eq!(result.num_episodes_watched, 5);
128 }
129
130 #[tokio::test]
131 async fn test_get_user_anime_list() {
132 let auth = crate::auth::tests::get_auth();
133 let query = GetUserAnimeListQuery {
134 fields: Some(ALL_ANIME_AND_MANGA_FIELDS.to_string()),
135 status: None,
136 sort: Some(SortStyle::ListScore),
137 limit: 2,
138 offset: 0,
139 nsfw: true,
140 };
141 let result = get_user_anime_list("@me", &query, &auth).await.unwrap();
142
143 print!("{:#?}", result);
144
145 assert!(!result.data.is_empty());
146 }
147}