Skip to content

Commit e5e2c0d

Browse files
committed
Add support for the Freshly Pressed endpoint
1 parent 627301f commit e5e2c0d

File tree

8 files changed

+8724
-0
lines changed

8 files changed

+8724
-0
lines changed

wp_api/src/wp_com/client.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::endpoint::{
22
followers_endpoint::{FollowersRequestBuilder, FollowersRequestExecutor},
3+
freshly_pressed::{FreshlyPressedRequestBuilder, FreshlyPressedRequestExecutor},
34
jetpack_connection_endpoint::{
45
JetpackConnectionRequestBuilder, JetpackConnectionRequestExecutor,
56
},
@@ -36,6 +37,7 @@ impl UniffiWpComApiRequestBuilder {
3637

3738
pub struct WpComApiRequestBuilder {
3839
followers: Arc<FollowersRequestBuilder>,
40+
freshly_pressed: Arc<FreshlyPressedRequestBuilder>,
3941
jetpack_connection: Arc<JetpackConnectionRequestBuilder>,
4042
oauth2: Arc<Oauth2RequestBuilder>,
4143
subscribers: Arc<SubscribersRequestBuilder>,
@@ -52,6 +54,7 @@ impl WpComApiRequestBuilder {
5254
api_url_resolver,
5355
auth_provider;
5456
followers,
57+
freshly_pressed,
5558
jetpack_connection,
5659
oauth2,
5760
subscribers,
@@ -79,6 +82,7 @@ impl UniffiWpComApiClient {
7982

8083
pub struct WpComApiClient {
8184
followers: Arc<FollowersRequestExecutor>,
85+
freshly_pressed: Arc<FreshlyPressedRequestExecutor>,
8286
jetpack_connection: Arc<JetpackConnectionRequestExecutor>,
8387
oauth2: Arc<Oauth2RequestExecutor>,
8488
subscribers: Arc<SubscribersRequestExecutor>,
@@ -96,6 +100,7 @@ impl WpComApiClient {
96100
api_url_resolver,
97101
delegate;
98102
followers,
103+
freshly_pressed,
99104
jetpack_connection,
100105
oauth2,
101106
subscribers,
@@ -106,6 +111,7 @@ impl WpComApiClient {
106111
}
107112
}
108113
api_client_generate_endpoint_impl!(WpComApi, followers);
114+
api_client_generate_endpoint_impl!(WpComApi, freshly_pressed);
109115
api_client_generate_endpoint_impl!(WpComApi, jetpack_connection);
110116
api_client_generate_endpoint_impl!(WpComApi, oauth2);
111117
api_client_generate_endpoint_impl!(WpComApi, subscribers);

wp_api/src/wp_com/endpoint.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use strum::IntoEnumIterator;
88

99
pub mod extensions;
1010
pub mod followers_endpoint;
11+
pub mod freshly_pressed;
1112
pub mod jetpack_connection_endpoint;
1213
pub mod oauth2;
1314
pub mod subscribers_endpoint;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use crate::{
2+
request::endpoint::{AsNamespace, DerivedRequest},
3+
wp_com::{freshly_pressed::{FreshlyPressedListParams, FreshlyPressedPostList}, WpComNamespace},
4+
};
5+
use wp_derive_request_builder::WpDerivedRequest;
6+
7+
#[derive(WpDerivedRequest)]
8+
enum FreshlyPressedRequest {
9+
#[get(url = "/freshly-pressed", params = &FreshlyPressedListParams, output = FreshlyPressedPostList)]
10+
List,
11+
}
12+
13+
impl DerivedRequest for FreshlyPressedRequest {
14+
fn namespace() -> impl AsNamespace {
15+
WpComNamespace::RestV1_2
16+
}
17+
}
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
use std::collections::HashMap;
2+
3+
use crate::{
4+
date::WpGmtDateTime, posts::PostId, url_query::{
5+
AppendUrlQueryPairs, FromUrlQueryPairs, QueryPairs, QueryPairsExtension, UrlQueryPairsMap,
6+
}, users::UserId, wp_com::WpComSiteId, JsonValue
7+
};
8+
use serde::{Deserialize, Serialize};
9+
use strum_macros::IntoStaticStr;
10+
use wp_serde_helper::{deserialize_false_or_string, deserialize_u64_or_none,deserialize_empty_array_or_hashmap};
11+
12+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
13+
pub struct FreshlyPressedPostList {
14+
pub date_range: FreshlyPressedDateRange,
15+
pub number: u32,
16+
pub posts: Vec<FreshlyPressedPost>,
17+
}
18+
19+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
20+
pub struct FreshlyPressedDateRange {
21+
pub before: WpGmtDateTime,
22+
pub after: WpGmtDateTime,
23+
}
24+
25+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
26+
pub struct FreshlyPressedPost {
27+
#[serde(rename = "ID")]
28+
pub id: PostId,
29+
#[serde(alias = "site_ID")]
30+
pub site_id: WpComSiteId,
31+
pub author: FreshlyPressedAuthor,
32+
pub date: String,
33+
pub modified: String,
34+
pub title: String,
35+
#[serde(rename = "URL")]
36+
pub url: String,
37+
#[serde(rename = "short_URL")]
38+
pub short_url: String,
39+
pub content: String,
40+
pub excerpt: String,
41+
pub slug: String,
42+
pub guid: String,
43+
pub status: String,
44+
pub sticky: bool,
45+
pub password: String,
46+
#[serde(deserialize_with = "deserialize_u64_or_none")]
47+
pub parent: Option<u64>,
48+
pub r#type: String,
49+
pub likes_enabled: bool,
50+
pub sharing_enabled: bool,
51+
pub like_count: u32,
52+
pub i_like: bool,
53+
pub is_reblogged: bool,
54+
pub is_following: bool,
55+
#[serde(rename = "global_ID")]
56+
pub global_id: String,
57+
pub featured_image: String,
58+
pub post_thumbnail: Option<FreshlyPressedPostThumbnail>,
59+
pub format: String,
60+
// pub geo: bool // TODO: need sample data to figure out the shape of this
61+
pub menu_order: u32,
62+
pub page_template: String,
63+
#[serde(rename = "publicize_URLs")]
64+
pub publicize_urls: Vec<String>,
65+
#[serde(deserialize_with = "deserialize_empty_array_or_hashmap")]
66+
pub terms: HashMap<String, HashMap<String, FreshlyPressedTerm>>,
67+
#[serde(deserialize_with = "deserialize_empty_array_or_hashmap")]
68+
pub tags: HashMap<String, FreshlyPressedTerm>,
69+
#[serde(deserialize_with = "deserialize_empty_array_or_hashmap")]
70+
pub categories: HashMap<String, FreshlyPressedTerm>,
71+
#[serde(deserialize_with = "deserialize_empty_array_or_hashmap")]
72+
pub attachments: HashMap<String, FreshlyPressedAttachment>,
73+
pub attachment_count: u64,
74+
pub metadata: Vec<FreshlyPressedKeyValuePair>,
75+
pub meta: FreshlyPressedObjectMeta,
76+
pub capabilities: HashMap<String, bool>,
77+
#[serde(alias = "other_URLs")]
78+
pub other_urls: HashMap<String, String>,
79+
#[serde(alias = "pseudo_ID")]
80+
pub pseudo_id: String,
81+
pub is_external: bool,
82+
pub site_name: String,
83+
#[serde(alias = "site_URL")]
84+
pub site_url: String,
85+
pub site_is_private: bool,
86+
#[serde(deserialize_with = "deserialize_empty_array_or_hashmap")]
87+
pub site_icon: HashMap<String, String>,
88+
pub featured_media: HashMap<String, String>,
89+
#[serde(alias = "feed_ID")]
90+
pub feed_id: u64,
91+
#[serde(alias = "feed_URL")]
92+
pub feed_url: String,
93+
}
94+
95+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
96+
pub struct FreshlyPressedPostThumbnail {
97+
#[serde(rename = "ID")]
98+
pub id: u64,
99+
#[serde(rename = "URL")]
100+
pub url: String,
101+
pub guid: String,
102+
pub mime_type: String,
103+
pub width: u32,
104+
pub height: u32,
105+
}
106+
107+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
108+
pub struct FreshlyPressedTerm {
109+
#[serde(rename = "ID")]
110+
pub id: u64,
111+
pub name: String,
112+
pub slug: String,
113+
pub description: String,
114+
pub post_count: u32,
115+
pub parent: Option<u64>,
116+
pub meta: FreshlyPressedObjectMeta,
117+
}
118+
119+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
120+
pub struct FreshlyPressedObjectMeta {
121+
pub links: HashMap<String, String>,
122+
}
123+
124+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
125+
pub struct FreshlyPressedKeyValuePair{
126+
pub id: String,
127+
pub key: String,
128+
pub value: JsonValue,
129+
}
130+
131+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
132+
pub struct FreshlyPressedAttachment {
133+
#[serde(alias = "ID")]
134+
pub id: u64,
135+
#[serde(alias = "URL")]
136+
pub url: String,
137+
pub guid: String,
138+
pub date: String,
139+
#[serde(alias = "post_ID")]
140+
pub post_id: u64,
141+
#[serde(alias = "author_ID")]
142+
pub author_id: u64,
143+
pub file: String,
144+
pub mime_type: String,
145+
pub extension: String,
146+
pub title: String,
147+
pub caption: String,
148+
pub description: String,
149+
pub alt: String,
150+
pub thumbnails: HashMap<String, String>,
151+
pub height: u32,
152+
pub width: u32,
153+
pub exif: FreshlyPressedAttachmentExifData,
154+
pub meta: FreshlyPressedObjectMeta,
155+
}
156+
157+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
158+
pub struct FreshlyPressedAttachmentExifData {
159+
pub aperture: String,
160+
pub credit: String,
161+
pub camera: String,
162+
pub caption: String,
163+
pub created_timestamp: String,
164+
pub copyright: String,
165+
pub focal_length: String,
166+
pub iso: String,
167+
pub shutter_speed: String,
168+
pub title: String,
169+
pub orientation: String,
170+
pub keywords: Vec<String>,
171+
}
172+
173+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
174+
pub struct FreshlyPressedAuthor {
175+
#[serde(rename = "ID")]
176+
pub id: UserId,
177+
pub login: String,
178+
#[serde(default, deserialize_with = "deserialize_false_or_string")]
179+
pub email: Option<String>,
180+
pub name: String,
181+
pub first_name: String,
182+
pub last_name: String,
183+
pub nice_name: String,
184+
#[serde(alias = "URL")]
185+
pub url: String,
186+
#[serde(alias = "avatar_URL")]
187+
pub avatar_url: String,
188+
#[serde(alias = "profile_URL")]
189+
pub profile_url: String,
190+
#[serde(alias = "site_ID", deserialize_with = "deserialize_u64_or_none")]
191+
pub site_id: Option<u64>,
192+
pub has_avatar: bool,
193+
pub wpcom_id: u64,
194+
pub wpcom_login: String,
195+
}
196+
197+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
198+
pub struct FreshlyPressedDiscussionSettings {
199+
pub comments_open: bool,
200+
pub comment_status: String,
201+
pub pings_open: bool,
202+
pub ping_status: String,
203+
pub comment_count: u32,
204+
}
205+
206+
#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
207+
pub struct FreshlyPressedEditorialSettings {
208+
pub blog_id: String,
209+
pub post_id: String,
210+
pub image: String,
211+
pub custom_headline: String,
212+
pub custom_blog_title: String,
213+
214+
pub displayed_on: WpGmtDateTime,
215+
pub picked_on: WpGmtDateTime,
216+
pub highlight_topic: String,
217+
pub highlight_topic_title: String,
218+
pub screen_offset: String,
219+
pub blog_name: String,
220+
pub site_id: String,
221+
}
222+
223+
#[derive(Debug, Default, Serialize, PartialEq, Eq, uniffi::Record)]
224+
pub struct FreshlyPressedListParams {
225+
#[uniffi(default = None)]
226+
pub number: Option<u32>,
227+
#[uniffi(default = None)]
228+
pub page: Option<u32>,
229+
}
230+
231+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, IntoStaticStr)]
232+
enum FreshlyPressedListParamsField {
233+
#[strum(serialize = "number")]
234+
Number,
235+
#[strum(serialize = "page")]
236+
Page,
237+
}
238+
239+
impl AppendUrlQueryPairs for FreshlyPressedListParams {
240+
fn append_query_pairs(&self, query_pairs_mut: &mut QueryPairs) {
241+
query_pairs_mut
242+
.append_option_query_value_pair(FreshlyPressedListParamsField::Number, self.number.as_ref())
243+
.append_option_query_value_pair(FreshlyPressedListParamsField::Page, self.page.as_ref());
244+
}
245+
}
246+
247+
impl FromUrlQueryPairs for FreshlyPressedListParams {
248+
fn from_url_query_pairs(query_pairs: UrlQueryPairsMap) -> Option<Self> {
249+
Some(Self {
250+
number: query_pairs.get(FreshlyPressedListParamsField::Number),
251+
page: query_pairs.get(FreshlyPressedListParamsField::Page),
252+
})
253+
}
254+
255+
fn supports_pagination() -> bool {
256+
true
257+
}
258+
}
259+
260+
261+
#[cfg(test)]
262+
mod tests {
263+
use super::*;
264+
265+
#[test]
266+
fn test_freshly_pressed_post_deserialization() {
267+
let json = include_str!("../../tests/wpcom/freshly_pressed/post-list-1.json");
268+
let conversation: FreshlyPressedPostList =
269+
serde_json::from_str(json).expect("Failed to deserialize freshly pressed post list");
270+
assert_eq!(conversation.number, 10);
271+
assert_eq!(conversation.posts[0].id, crate::posts::PostId(16283));
272+
assert_eq!(conversation.posts[0].site_id, crate::wp_com::WpComSiteId(121838035));
273+
assert_eq!(conversation.posts[0].author.id, crate::users::UserId(1));
274+
}
275+
}

wp_api/src/wp_com/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{num::ParseIntError, str::FromStr, sync::Arc};
66
pub mod client;
77
pub mod endpoint;
88
pub mod followers;
9+
pub mod freshly_pressed;
910
pub mod jetpack_connection;
1011
pub mod oauth2;
1112
pub mod subscribers;
@@ -26,6 +27,12 @@ impl FromStr for WpComSiteId {
2627
}
2728
}
2829

30+
impl From<u64> for WpComSiteId {
31+
fn from(value: u64) -> Self {
32+
Self(value)
33+
}
34+
}
35+
2936
impl std::fmt::Display for WpComSiteId {
3037
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3138
write!(f, "{}", self.0)
@@ -35,6 +42,7 @@ impl std::fmt::Display for WpComSiteId {
3542
pub(crate) enum WpComNamespace {
3643
Oauth2,
3744
RestV1_1,
45+
RestV1_2,
3846
V2,
3947
}
4048

@@ -43,6 +51,7 @@ impl AsNamespace for WpComNamespace {
4351
match self {
4452
WpComNamespace::Oauth2 => "/oauth2",
4553
WpComNamespace::RestV1_1 => "/rest/v1.1",
54+
WpComNamespace::RestV1_2 => "/rest/v1.2",
4655
WpComNamespace::V2 => "/wpcom/v2",
4756
}
4857
}

0 commit comments

Comments
 (0)