rust_freely/client/
handlers.rs

1/// This module provides wrappers for top-level (ie, not referencing a specific entity) API methods
2pub mod api_handlers {
3
4    use serde_derive::{Deserialize, Serialize};
5
6    use crate::{
7        api_client::{ApiError, Client},
8        api_models::{
9            collections::Collection,
10            posts::{Post, PostCreation, PostCreationBuilder},
11            users::User,
12        },
13    };
14
15    #[derive(Clone, Debug)]
16    /// Handler for [User] methods
17    pub struct UserHandler {
18        client: Client,
19        current: Option<User>,
20    }
21
22    impl UserHandler {
23        /// Creates a new [UserHandler] instance, and preloads the authenticated user info if available.
24        pub async fn new(client: Client) -> Self {
25            if client.is_authenticated() {
26                UserHandler {
27                    client: client.clone(),
28                    current: match client.api().get::<User>("/me").await {
29                        Ok(user) => Some(user),
30                        Err(_) => None,
31                    },
32                }
33            } else {
34                UserHandler {
35                    client: client.clone(),
36                    current: None,
37                }
38            }
39        }
40
41        /// Returns the current [User] if available
42        pub fn info(&self) -> Option<User> {
43            self.current.clone()
44        }
45
46        /// Returns all [Post]s associated with the authenticated [User]
47        pub async fn posts(&self) -> Result<Vec<Post>, ApiError> {
48            if self.client.is_authenticated() {
49                self.client
50                    .api()
51                    .get::<Vec<Post>>("/me/posts")
52                    .await
53                    .and_then(|mut v| {
54                        Ok(v.iter_mut()
55                            .map(|x| x.with_client(self.client.clone()))
56                            .collect())
57                    })
58            } else {
59                Err(ApiError::LoggedOut {})
60            }
61        }
62
63        /// Returns the specified [Post]
64        pub async fn post(&self, id: &str) -> Result<Post, ApiError> {
65            if self.client.is_authenticated() {
66                self.client
67                    .api()
68                    .get::<Post>(format!("/posts/{id}").as_str())
69                    .await
70                    .and_then(|mut v| Ok(v.with_client(self.client.clone())))
71            } else {
72                Err(ApiError::LoggedOut {})
73            }
74        }
75
76        /// Returns all [Collection]s associated with the authenticated [User]
77        pub async fn collections(&self) -> Result<Vec<Collection>, ApiError> {
78            if self.client.is_authenticated() {
79                self.client
80                    .api()
81                    .get::<Vec<Collection>>("/me/collections")
82                    .await
83                    .and_then(|mut v| {
84                        Ok(v.iter_mut()
85                            .map(|x| x.with_client(self.client.clone()))
86                            .collect())
87                    })
88            } else {
89                Err(ApiError::LoggedOut {})
90            }
91        }
92
93        /// Returns the specified [Collection]
94        pub async fn collection(&self, alias: &str) -> Result<Collection, ApiError> {
95            if self.client.is_authenticated() {
96                self.client
97                    .api()
98                    .get::<Collection>(format!("/collections/{alias}").as_str())
99                    .await
100                    .and_then(|mut v| Ok(v.with_client(self.client.clone())))
101            } else {
102                Err(ApiError::LoggedOut {})
103            }
104        }
105    }
106
107    #[derive(Clone, Debug)]
108    /// Handler for [Post] methods
109    pub struct PostHandler {
110        client: Client,
111    }
112
113    impl PostHandler {
114        /// Creates a new [PostHandler] with a [Client] instance
115        pub fn new(client: Client) -> Self {
116            PostHandler {
117                client: client.clone(),
118            }
119        }
120
121        /// Gets a specific [Post] by ID
122        pub async fn get(&self, id: &str) -> Result<Post, ApiError> {
123            self.client
124                .api()
125                .get::<Post>(format!("/posts/{id}").as_str())
126                .await
127                .and_then(|mut p| Ok(p.with_client(self.client.clone())))
128        }
129
130        /// Creates a [PostCreationBuilder] with the desired body.
131        pub fn create(&self, body: String) -> PostCreationBuilder {
132            PostCreationBuilder::default()
133                .client(Some(self.client.clone()))
134                .body(body)
135                .clone()
136        }
137
138        /// Publishes a previously-made [PostCreation] instance
139        pub async fn publish(&self, post: PostCreation) -> Result<Post, ApiError> {
140            if let Some(collection) = post.collection.clone() {
141                self.client
142                    .api()
143                    .post::<Post, PostCreation>(format!("/collections/{collection}/post").as_str(), Some(post))
144                    .await
145                    .and_then(|mut p| Ok(p.with_client(self.client.clone())))
146            } else {
147                self.client
148                    .api()
149                    .post::<Post, PostCreation>("/posts", Some(post))
150                    .await
151                    .and_then(|mut p| Ok(p.with_client(self.client.clone())))
152            }
153        }
154    }
155
156    #[derive(Clone, Debug, Serialize, Deserialize)]
157    struct CollectionParameters {
158        pub alias: Option<String>,
159        pub title: Option<String>,
160    }
161
162    #[derive(Clone, Debug)]
163    /// Handler for [Collection] methods
164    pub struct CollectionHandler {
165        client: Client,
166    }
167
168    impl CollectionHandler {
169        /// Creates a new [CollectionHandler] with a [Client] instance
170        pub fn new(client: Client) -> Self {
171            CollectionHandler {
172                client: client.clone(),
173            }
174        }
175
176        /// Creates a new [Collection]. At least one of `alias` and `title` must be specified.
177        pub async fn create(
178            &self,
179            alias: Option<String>,
180            title: Option<String>,
181        ) -> Result<Collection, ApiError> {
182            if alias.is_none() && title.is_none() {
183                return Err(ApiError::UsageError {});
184            }
185
186            if !self.client.is_authenticated() {
187                return Err(ApiError::LoggedOut {});
188            }
189
190            let params = CollectionParameters { alias, title };
191            self.client
192                .api()
193                .post::<Collection, CollectionParameters>("/collections", Some(params))
194                .await
195                .and_then(|mut v| Ok(v.with_client(self.client.clone())))
196        }
197
198        /// Retrieves a [Collection] by its alias.
199        pub async fn get(&self, alias: &str) -> Result<Collection, ApiError> {
200            self.client
201                .api()
202                .get::<Collection>(format!("/collections/{alias}").as_str())
203                .await
204                .and_then(|mut v| Ok(v.with_client(self.client.clone())))
205        }
206    }
207}