hubcaps_ex/
notifications.rs

1//! Notifications interface
2use std::collections::HashMap;
3
4use serde::Deserialize;
5use url::form_urlencoded;
6
7use crate::users::User;
8use crate::Future;
9use crate::Github;
10
11/// Provides access to notifications.
12/// See the [github docs](https://developer.github.com/v3/activity/notifications/)
13/// for more information.
14pub struct Notifications {
15    github: Github,
16}
17
18impl Notifications {
19    #[doc(hidden)]
20    pub fn new(github: Github) -> Self {
21        Self { github }
22    }
23
24    /// List the authenticated user's notifications.
25    ///
26    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#list-your-notifications)
27    /// for more information.
28    pub fn list(&self, options: &ThreadListOptions) -> Future<Vec<Thread>> {
29        let mut uri = vec!["/notifications".into()];
30        if let Some(query) = options.serialize() {
31            uri.push(query);
32        }
33        self.github.get(&uri.join("?"))
34    }
35
36    /// List the authenticated user's notifications for a repository.
37    ///
38    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository)
39    /// for more information.
40    pub fn list_for_repo<O, R>(
41        &self,
42        owner: O,
43        repo: R,
44        options: &ThreadListOptions,
45    ) -> Future<Vec<Thread>>
46    where
47        O: Into<String>,
48        R: Into<String>,
49    {
50        let mut uri = vec![format!(
51            "/repos/{}/{}/notifications",
52            owner.into(),
53            repo.into()
54        )];
55        if let Some(query) = options.serialize() {
56            uri.push(query);
57        }
58        self.github.get(&uri.join("?"))
59    }
60
61    /// Mark notifications as read. Default: `now`
62    ///
63    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#mark-as-read)
64    /// for more information.
65    pub fn mark_as_read<S>(&self, last_read_at: S) -> Future<()>
66    where
67        S: Into<Option<String>>,
68    {
69        let url = match last_read_at.into() {
70            Some(last_read_at) => format!(
71                "/notifications?{}",
72                form_urlencoded::Serializer::new(String::new())
73                    .append_pair("last_read_at", &last_read_at)
74                    .finish()
75            ),
76            None => String::from("/notifications"),
77        };
78        self.github.put_no_response(&url, Vec::new())
79    }
80
81    /// Mark notifications as read in a repository. Default: `now`
82    ///
83    /// See [github docs](https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository)
84    /// for more information.
85    pub fn mark_as_read_for_repo<O, R, S>(&self, owner: O, repo: R, last_read_at: S) -> Future<()>
86    where
87        O: Into<String>,
88        R: Into<String>,
89        S: Into<Option<String>>,
90    {
91        let path = match last_read_at.into() {
92            Some(last_read_at) => format!(
93                "/notifications?{}",
94                form_urlencoded::Serializer::new(String::new())
95                    .append_pair("last_read_at", &last_read_at)
96                    .finish()
97            ),
98            None => String::from("/notifications"),
99        };
100        self.github.put_no_response(
101            &format!("/repos/{}/{}{}", owner.into(), repo.into(), path),
102            Vec::new(),
103        )
104    }
105
106    /// Return a single thread.
107    ///
108    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#view-a-single-thread)
109    /// for more information.
110    pub fn get_thread<S>(&self, id: S) -> Future<Thread>
111    where
112        S: Into<String>,
113    {
114        self.github
115            .get(&format!("/notifications/threads/{}", id.into()))
116    }
117
118    /// Mark a thread as read
119    ///
120    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read)
121    /// for more information.
122    pub fn mark_thread_as_read<S>(&self, id: S) -> Future<()>
123    where
124        S: Into<String>,
125    {
126        self.github
127            .patch_no_response(&format!("/notifications/threads/{}", id.into()), Vec::new())
128    }
129
130    /// Return the subscription information for a thread.
131    ///
132    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription)
133    /// for more information.
134    pub fn get_subscription<S>(&self, id: S) -> Future<Subscription>
135    where
136        S: Into<String>,
137    {
138        self.github.get(&format!(
139            "/notifications/threads/{}/subscription",
140            id.into(),
141        ))
142    }
143
144    /// Subscribe to a thread and return the subscription information.
145    ///
146    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription)
147    /// for more information.
148    pub fn subscribe<S>(&self, id: S) -> Future<Subscription>
149    where
150        S: Into<String>,
151    {
152        self.github.put(
153            &format!("/notifications/threads/{}/subscription", id.into()),
154            json_lit!({ "subscribed": true }),
155        )
156    }
157
158    /// Unsubscribe to a thread and return the subscription information.
159    ///
160    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription)
161    /// for more information.
162    pub fn unsubscribe<S>(&self, id: S) -> Future<Subscription>
163    where
164        S: Into<String>,
165    {
166        self.github.put(
167            &format!("/notifications/threads/{}/subscription", id.into()),
168            json_lit!({ "ignored": true }),
169        )
170    }
171
172    /// Delete the thread subscription.
173    ///
174    /// See the [github docs](https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription)
175    /// for more information.
176    pub fn delete_subscription<S>(&self, id: S) -> Future<()>
177    where
178        S: Into<String>,
179    {
180        self.github.delete(&format!(
181            "/notifications/threads/{}/subscription",
182            id.into()
183        ))
184    }
185}
186
187// representations
188
189#[derive(Debug, Deserialize)]
190pub struct Thread {
191    pub id: String,
192    pub unread: bool,
193    pub updated_at: String,
194    pub last_read_at: Option<String>,
195    pub reason: String,
196    pub subject: Subject,
197    pub repository: Repository,
198    pub url: String,
199    pub subscription_url: String,
200}
201
202#[derive(Default)]
203pub struct ThreadListOptions {
204    params: HashMap<&'static str, String>,
205}
206
207impl ThreadListOptions {
208    pub fn builder() -> ThreadListOptionsBuilder {
209        ThreadListOptionsBuilder::default()
210    }
211
212    /// serialize options as a string. returns None if no options are defined
213    pub fn serialize(&self) -> Option<String> {
214        if self.params.is_empty() {
215            None
216        } else {
217            let encoded: String = form_urlencoded::Serializer::new(String::new())
218                .extend_pairs(&self.params)
219                .finish();
220            Some(encoded)
221        }
222    }
223}
224
225#[derive(Default)]
226pub struct ThreadListOptionsBuilder(ThreadListOptions);
227
228impl ThreadListOptionsBuilder {
229    /// if `true`, show notifications marked as read. Default: `false`
230    pub fn all(&mut self, all: bool) -> &mut Self {
231        self.0.params.insert("all", all.to_string());
232        self
233    }
234
235    /// if `true`, only shows notifications in which the user is directly participating or
236    /// mentioned. Default: `false`
237    pub fn participating(&mut self, val: bool) -> &mut Self {
238        self.0.params.insert("participating", val.to_string());
239        self
240    }
241
242    /// Only show notifications updated after the given time.
243    pub fn since<T>(&mut self, since: T) -> &mut Self
244    where
245        T: Into<String>,
246    {
247        self.0.params.insert("since", since.into());
248        self
249    }
250
251    /// Only show notifications updated before a given time.
252    pub fn before<T>(&mut self, before: T) -> &mut Self
253    where
254        T: Into<String>,
255    {
256        self.0.params.insert("before", before.into());
257        self
258    }
259
260    pub fn build(&self) -> ThreadListOptions {
261        ThreadListOptions {
262            params: self.0.params.clone(),
263        }
264    }
265}
266
267#[derive(Debug, Deserialize)]
268pub struct Subject {
269    title: String,
270    url: String,
271    latest_comment_url: String,
272    #[serde(rename = "type")]
273    kind: String,
274}
275
276#[derive(Debug, Deserialize)]
277pub struct Repository {
278    pub id: u32,
279    pub node_id: String,
280    pub name: String,
281    pub full_name: String,
282    pub owner: User,
283    pub html_url: String,
284}
285
286#[derive(Debug, Deserialize)]
287pub struct Subscription {
288    pub subscribed: bool,
289    pub ignored: bool,
290    pub reason: String,
291    pub created_at: String,
292    pub url: String,
293    pub thread_url: String,
294}