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 #[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}