other_pocket/
lib.rs

1use add::*;
2use client::PocketClient;
3use errors::PocketError;
4use futures::TryFutureExt;
5use get::*;
6use hyper::http::uri::InvalidUri;
7use hyper::Uri;
8use send::*;
9use serde::{Deserialize, Serialize};
10use serialization::*;
11use std::convert::TryInto;
12use std::result::Result;
13use url::Url;
14
15pub mod add;
16pub mod auth;
17mod client;
18pub mod errors;
19pub mod get;
20mod headers;
21pub mod send;
22mod serialization;
23mod utils;
24
25pub type PocketResult<T> = Result<T, PocketError>;
26
27#[derive(Deserialize, Debug, PartialEq, Clone)]
28pub struct PocketImage {
29    #[serde(deserialize_with = "from_str")]
30    pub item_id: u64,
31    #[serde(deserialize_with = "from_str")]
32    pub image_id: u64,
33    #[serde(default, deserialize_with = "try_url_from_string")]
34    pub src: Option<Url>,
35    #[serde(deserialize_with = "from_str")]
36    pub width: u16,
37    #[serde(deserialize_with = "from_str")]
38    pub height: u16,
39    pub credit: String,
40    pub caption: String,
41}
42
43#[derive(Deserialize, Debug, PartialEq, Clone)]
44pub struct ItemVideo {
45    #[serde(deserialize_with = "from_str")]
46    pub item_id: u64,
47    #[serde(deserialize_with = "from_str")]
48    pub video_id: u64,
49    #[serde(default, deserialize_with = "try_url_from_string")]
50    pub src: Option<Url>,
51    #[serde(deserialize_with = "from_str")]
52    pub width: u16,
53    #[serde(deserialize_with = "from_str")]
54    pub height: u16,
55    #[serde(deserialize_with = "option_from_str")]
56    pub length: Option<usize>,
57    pub vid: String,
58    #[serde(rename = "type", deserialize_with = "from_str")]
59    pub vtype: u16,
60}
61
62#[derive(Deserialize, Debug, PartialEq, Clone)]
63pub struct ItemAuthor {
64    #[serde(deserialize_with = "from_str")]
65    pub item_id: u64,
66    #[serde(deserialize_with = "from_str")]
67    pub author_id: u64,
68    pub name: String,
69    pub url: String,
70}
71
72#[derive(Deserialize, Debug, PartialEq, Clone, Copy)]
73pub enum PocketItemHas {
74    #[serde(rename = "0")]
75    No,
76    #[serde(rename = "1")]
77    Yes,
78    #[serde(rename = "2")]
79    Is,
80}
81
82#[derive(Serialize)]
83pub struct PocketUserRequest<'a, T> {
84    consumer_key: &'a str,
85    access_token: &'a str,
86    #[serde(flatten)]
87    request: T,
88}
89
90pub struct Pocket {
91    consumer_key: String,
92    access_token: String,
93    client: PocketClient,
94}
95
96impl Pocket {
97    pub fn new(consumer_key: &str, access_token: &str) -> Pocket {
98        Pocket {
99            consumer_key: consumer_key.to_string(),
100            access_token: access_token.to_string(),
101            client: PocketClient::new(),
102        }
103    }
104
105    #[inline]
106    pub fn access_token(&self) -> &str {
107        &self.access_token
108    }
109
110    pub async fn add(&self, request: &PocketAddRequest<'_>) -> PocketResult<PocketAddedItem> {
111        let body = &PocketUserRequest {
112            consumer_key: &*self.consumer_key,
113            access_token: &*self.access_token,
114            request,
115        };
116
117        self.client
118            .post("https://getpocket.com/v3/add", &body)
119            .map_ok(|v: PocketAddResponse| v.item)
120            .await
121    }
122
123    pub async fn get(&self, request: &PocketGetRequest<'_>) -> PocketResult<Vec<PocketItem>> {
124        let body = &PocketUserRequest {
125            consumer_key: &*self.consumer_key,
126            access_token: &*self.access_token,
127            request,
128        };
129
130        self.client
131            .post("https://getpocket.com/v3/get", &body)
132            .map_ok(|v: PocketGetResponse| v.list)
133            .await
134    }
135
136    pub async fn send(&self, request: &PocketSendRequest<'_>) -> PocketResult<PocketSendResponse> {
137        let data = serde_json::to_string(request.actions)?;
138        let params = &[
139            ("consumer_key", &*self.consumer_key),
140            ("access_token", &*self.access_token),
141            ("actions", &data),
142        ];
143
144        let url = Url::parse_with_params("https://getpocket.com/v3/send", params).unwrap();
145
146        self.client.get(url_to_uri(&url).unwrap()).await
147    }
148
149    pub fn filter(&self) -> PocketGetRequest {
150        PocketGetRequest::new()
151    }
152}
153
154fn url_to_uri(url: &Url) -> Result<Uri, InvalidUri> {
155    url.as_str().try_into()
156}
157
158#[cfg(test)]
159mod test {
160    use super::*;
161    use utils::remove_whitespace;
162
163    // ItemImage
164    #[test]
165    fn test_deserialize_item_image() {
166        let expected = ItemImage {
167            item_id: 1,
168            src: Url::parse("http://localhost").ok(),
169            width: 3,
170            height: 4,
171        };
172        let response = remove_whitespace(&format!(
173            r#"
174                    {{
175                        "item_id": "{item_id}",
176                        "src": "{src}",
177                        "width": "{width}",
178                        "height": "{height}"
179                    }}
180               "#,
181            item_id = expected.item_id,
182            src = expected.src.as_ref().unwrap(),
183            width = expected.width,
184            height = expected.height,
185        ));
186
187        let actual: ItemImage = serde_json::from_str(&response).unwrap();
188
189        assert_eq!(actual, expected);
190    }
191}