Skip to content

Commit 4069d3e

Browse files
committed
Refactored /user/bookmarks/
1 parent 650d355 commit 4069d3e

File tree

27 files changed

+1502
-19
lines changed

27 files changed

+1502
-19
lines changed

.vscode/settings.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@
1010
"[x]",
1111
"FINISHED",
1212
"todo!"
13-
]
13+
],
14+
"[rust]": {
15+
"editor.defaultFormatter": "rust-lang.rust-analyzer",
16+
"editor.formatOnSave": true
17+
}
1418
}

mangadex-api/src/http_client.rs

+35-5
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ macro_rules! endpoint {
350350
}
351351
}
352352

353-
353+
354354
};
355355
// Don't return any data from the response.
356356
{ @send:discard_result, $typ:ty, $out:ty } => {
@@ -371,11 +371,11 @@ macro_rules! endpoint {
371371
{ @send:no_send, $typ:ty, $out:ty } => { };
372372

373373
}
374-
/// Helper macros for implementing the send function on the builder
375-
///
374+
/// Helper macros for implementing the send function on the builder
375+
///
376376
/// Introduced in v3.0.0-alpha.1
377-
///
378-
///
377+
///
378+
///
379379
macro_rules! builder_send {
380380
{
381381
#[$builder:ident] $typ:ty,
@@ -407,3 +407,33 @@ macro_rules! builder_send {
407407
}
408408
}
409409

410+
macro_rules! create_endpoint_node {
411+
{
412+
#[$name:ident] $sname:ident $tname:ident,
413+
#[$args:ident] {$($arg_name:ident: $arg_ty:ty,)+},
414+
#[$methods:ident] {$($func:ident($($farg_name:ident: $farg_ty:ty,)*) -> $output:ty;)*}
415+
} => {
416+
#[derive(Debug)]
417+
pub struct $sname {
418+
$( $arg_name: $arg_ty, )+
419+
}
420+
trait $tname {
421+
$(
422+
fn $func(&self, $( $farg_name: $farg_ty, )*) -> $output;
423+
)*
424+
}
425+
impl $sname {
426+
pub fn new($( $arg_name: $arg_ty, )+) -> Self {
427+
Self {
428+
$( $arg_name, )+
429+
}
430+
}
431+
$(
432+
pub fn $func(&self, $( $farg_name: $farg_ty, )*) -> $output {
433+
<Self as $tname>::$func(&self, $( $farg_name,)*)
434+
}
435+
)*
436+
}
437+
}
438+
439+
}

mangadex-api/src/v5/feed.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use uuid::Uuid;
66

77
use crate::v5::custom_list::id::feed::get::CustomListMangaFeedBuilder;
8-
use crate::v5::user::followed_manga_feed::GetFollowedMangaFeedBuilder;
8+
//use crate::v5::user::followed_manga_feed::GetFollowedMangaFeedBuilder;
99
use crate::HttpClientRef;
1010

1111
/// Feed endpoint handler builder.
@@ -54,9 +54,10 @@ impl FeedBuilder {
5454
/// # Ok(())
5555
/// # }
5656
/// ```
57-
pub fn followed_manga(&self) -> GetFollowedMangaFeedBuilder {
57+
/// TODO Re-add this later
58+
/*pub fn followed_manga(&self) -> GetFollowedMangaFeedBuilder {
5859
GetFollowedMangaFeedBuilder::default().http_client(self.http_client.clone())
59-
}
60+
}*/
6061

6162
/// Get the manga feed for a given custom list.
6263
///

mangadex-api/src/v5/user.rs

+18-8
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,26 @@ pub mod subscription;
1515

1616
use crate::HttpClientRef;
1717

18-
/// User endpoint handler builder.
19-
#[derive(Debug)]
20-
pub struct UserBuilder {
21-
http_client: HttpClientRef,
18+
use bookmarks::BookmarksEndpoint;
19+
use get::ListUserBuilder;
20+
21+
create_endpoint_node! {
22+
#[name] UserBuilder UserBuilderMethods,
23+
#[args] {
24+
http_client: HttpClientRef,
25+
},
26+
#[methods] {
27+
bookmarks() -> BookmarksEndpoint;
28+
get() -> ListUserBuilder;
29+
}
2230
}
2331

24-
impl UserBuilder {
25-
#[doc(hidden)]
26-
pub(crate) fn new(http_client: HttpClientRef) -> Self {
27-
Self { http_client }
32+
impl UserBuilderMethods for UserBuilder {
33+
fn bookmarks(&self) -> BookmarksEndpoint {
34+
BookmarksEndpoint::new(self.http_client.clone())
2835
}
2936

37+
fn get(&self) -> ListUserBuilder {
38+
ListUserBuilder::default().http_client(self.http_client.clone())
39+
}
3040
}

mangadex-api/src/v5/user/bookmarks.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
pub mod group;
2+
pub mod list;
3+
pub mod user;
4+
5+
use crate::HttpClientRef;
6+
use group::GroupEndpoint;
7+
use list::ListEndpoint;
8+
use user::UserEndpoint;
9+
10+
create_endpoint_node! {
11+
#[name] BookmarksEndpoint BookmarksEndpointMethods,
12+
#[args] {
13+
http_client: HttpClientRef,
14+
},
15+
#[methods] {
16+
group() -> GroupEndpoint;
17+
list() -> ListEndpoint;
18+
user() -> UserEndpoint;
19+
}
20+
}
21+
22+
impl BookmarksEndpointMethods for BookmarksEndpoint {
23+
fn group(&self) -> GroupEndpoint {
24+
GroupEndpoint::new(self.http_client.clone())
25+
}
26+
27+
fn list(&self) -> ListEndpoint {
28+
ListEndpoint::new(self.http_client.clone())
29+
}
30+
31+
fn user(&self) -> UserEndpoint {
32+
UserEndpoint::new(self.http_client.clone())
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
pub mod get;
2+
pub mod id;
3+
4+
use get::BookmarkedGroupsBuilder;
5+
use id::IdEndpoint;
6+
use uuid::Uuid;
7+
8+
use crate::HttpClientRef;
9+
10+
create_endpoint_node! {
11+
#[name] GroupEndpoint GroupEndpointMethods,
12+
#[args] {
13+
http_client: HttpClientRef,
14+
},
15+
#[methods] {
16+
get() -> BookmarkedGroupsBuilder;
17+
id(id: Uuid, ) -> IdEndpoint;
18+
}
19+
}
20+
21+
impl GroupEndpointMethods for GroupEndpoint {
22+
fn get(&self) -> BookmarkedGroupsBuilder {
23+
BookmarkedGroupsBuilder::default().http_client(self.http_client.clone())
24+
}
25+
26+
fn id(&self, id: Uuid) -> IdEndpoint {
27+
IdEndpoint::new(self.http_client.clone(), id)
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
//! Builder for the followed scanlation groups endpoint.
2+
//!
3+
//! <https://api.mangadex.org/swagger.html#/Follows/get-user-follows-group>
4+
//!
5+
//! # Examples
6+
//!
7+
//! ```rust
8+
//! use uuid::Uuid;
9+
//!
10+
//! use mangadex_api::v5::MangaDexClient;
11+
//! use mangadex_api_types::{Password, Username};
12+
//!
13+
//! # async fn run() -> anyhow::Result<()> {
14+
//! let client = MangaDexClient::default();
15+
//!
16+
//! let _login_res = client
17+
//! .auth()
18+
//! .login()
19+
//! .username(Username::parse("myusername")?)
20+
//! .password(Password::parse("hunter23")?)
21+
//! .build()?
22+
//! .send()
23+
//! .await?;
24+
//!
25+
//! let res = client
26+
//! .user()
27+
//! .followed_groups()
28+
//! .limit(1_u32)
29+
//! .build()?
30+
//! .send()
31+
//! .await?;
32+
//!
33+
//! println!("followed groups: {:?}", res);
34+
//! # Ok(())
35+
//! # }
36+
//! ```
37+
38+
use derive_builder::Builder;
39+
use serde::Serialize;
40+
41+
use crate::HttpClientRef;
42+
use mangadex_api_schema::v5::GroupListResponse;
43+
use mangadex_api_types::ReferenceExpansionResource;
44+
45+
#[cfg_attr(
46+
feature = "deserializable-endpoint",
47+
derive(serde::Deserialize, getset::Getters, getset::Setters)
48+
)]
49+
#[derive(Debug, Serialize, Clone, Builder, Default)]
50+
#[serde(rename_all = "camelCase")]
51+
#[builder(
52+
setter(into, strip_option),
53+
pattern = "owned",
54+
default,
55+
build_fn(error = "mangadex_api_types::error::BuilderError")
56+
)]
57+
pub struct BookmarkedGroups {
58+
/// This should never be set manually as this is only for internal use.
59+
#[doc(hidden)]
60+
#[serde(skip)]
61+
#[builder(pattern = "immutable")]
62+
#[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
63+
pub(crate) http_client: HttpClientRef,
64+
65+
#[serde(skip_serializing_if = "Option::is_none")]
66+
pub limit: Option<u32>,
67+
#[serde(skip_serializing_if = "Option::is_none")]
68+
pub offset: Option<u32>,
69+
#[builder(setter(each = "include"), default)]
70+
pub includes: Vec<ReferenceExpansionResource>,
71+
}
72+
73+
endpoint! {
74+
GET "/user/bookmarks/group",
75+
#[query auth] BookmarkedGroups,
76+
#[flatten_result] GroupListResponse
77+
}
78+
79+
#[cfg(test)]
80+
mod tests {
81+
use serde_json::json;
82+
use time::OffsetDateTime;
83+
use url::Url;
84+
use uuid::Uuid;
85+
use wiremock::matchers::{header, method, path_regex};
86+
use wiremock::{Mock, MockServer, ResponseTemplate};
87+
88+
use crate::v5::AuthTokens;
89+
use crate::{HttpClient, MangaDexClient};
90+
use mangadex_api_types::MangaDexDateTime;
91+
92+
#[tokio::test]
93+
async fn get_followed_groups_fires_a_request_to_base_url_ungrouped() -> anyhow::Result<()> {
94+
let mock_server = MockServer::start().await;
95+
let http_client = HttpClient::builder()
96+
.base_url(Url::parse(&mock_server.uri())?)
97+
.auth_tokens(AuthTokens {
98+
session: "sessiontoken".to_string(),
99+
refresh: "refreshtoken".to_string(),
100+
})
101+
.build()?;
102+
let mangadex_client = MangaDexClient::new_with_http_client(http_client);
103+
104+
let group_id = Uuid::new_v4();
105+
106+
let datetime = MangaDexDateTime::new(&OffsetDateTime::now_utc());
107+
108+
let response_body = json!({
109+
"result": "ok",
110+
"response": "collection",
111+
"data": [
112+
{
113+
"id": group_id,
114+
"type": "scanlation_group",
115+
"attributes": {
116+
"name": "Scanlation Group",
117+
"altNames": [],
118+
"website": "https://example.org",
119+
"ircServer": null,
120+
"ircChannel": null,
121+
"discord": null,
122+
"contactEmail": null,
123+
"description": null,
124+
"twitter": null,
125+
"focusedLanguages": ["en"],
126+
"locked": false,
127+
"official": false,
128+
"verified": false,
129+
"inactive": false,
130+
"publishDelay": "P6WT5M",
131+
"version": 1,
132+
"createdAt": datetime.to_string(),
133+
"updatedAt": datetime.to_string(),
134+
},
135+
"relationships": []
136+
}
137+
],
138+
"limit": 1,
139+
"offset": 0,
140+
"total": 1
141+
});
142+
143+
Mock::given(method("GET"))
144+
.and(path_regex(r"/user/bookmarks/group"))
145+
.and(header("Authorization", "Bearer sessiontoken"))
146+
.respond_with(ResponseTemplate::new(200).set_body_json(response_body))
147+
.expect(1)
148+
.mount(&mock_server)
149+
.await;
150+
151+
let _ = mangadex_client
152+
.user()
153+
.bookmarks()
154+
.group()
155+
.get()
156+
.limit(1_u32)
157+
.build()?
158+
.send()
159+
.await?;
160+
161+
Ok(())
162+
}
163+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
pub mod get;
2+
3+
use crate::HttpClientRef;
4+
5+
use uuid::Uuid;
6+
7+
use self::get::IsBookmarkingGroupBuilder;
8+
9+
create_endpoint_node! {
10+
#[name] IdEndpoint IdEndpointMethods,
11+
#[args] {
12+
http_client: HttpClientRef,
13+
id: Uuid,
14+
},
15+
#[methods] {
16+
get() -> IsBookmarkingGroupBuilder;
17+
}
18+
}
19+
20+
impl IdEndpointMethods for IdEndpoint {
21+
fn get(&self) -> IsBookmarkingGroupBuilder {
22+
IsBookmarkingGroupBuilder::default()
23+
.group_id(self.id)
24+
.http_client(self.http_client.clone())
25+
}
26+
}

0 commit comments

Comments
 (0)