Skip to content

Add country field support to subscribers API #809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions wp_api/src/wp_com/subscribers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, ops::Not};
use wp_serde_helper::deserialize_u64_or_string;
use wp_serde_helper::{deserialize_false_or_string, deserialize_u64_or_string};

#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
pub struct Subscriber {
Expand Down Expand Up @@ -74,8 +74,10 @@ pub enum SubscriptionStatus {

#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
pub struct SubscriberCountry {
code: String,
name: String,
#[serde(default, deserialize_with = "deserialize_false_or_string")]
code: Option<String>,
#[serde(default, deserialize_with = "deserialize_false_or_string")]
name: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
Expand All @@ -95,27 +97,30 @@ pub struct SubscriptionPlan {

#[derive(Debug, Default, PartialEq, Eq, uniffi::Record)]
pub struct SubscribersListParams {
// The current page.
/// The current page.
#[uniffi(default = None)]
pub page: Option<u64>,
// The amount of items to show per page.
/// The amount of items to show per page.
#[uniffi(default = None)]
pub per_page: Option<u64>,
// Search for subscribers
/// Search for subscribers
#[uniffi(default = None)]
pub search: Option<String>,
// Sort subscribers by a specific field
/// Sort subscribers by a specific field
#[uniffi(default = None)]
pub sort: Option<ListSubscribersSortField>,
// Sort order
/// Sort order
#[uniffi(default = None)]
pub sort_order: Option<WpApiParamOrder>,
// Filter subscribers by a specific subscriber type
/// Filter subscribers by a specific subscriber type
#[uniffi(default = None)]
pub filter: Option<SubscriberType>,
// Array of filters to apply (combined with AND logic). If provided, overrides the single filter parameter.
/// Array of filters to apply (combined with AND logic). If provided, overrides the single filter parameter.
#[uniffi(default = None)]
pub filters: Option<Vec<SubscriberType>>,
/// An array of additional fields to include
#[uniffi(default = [])]
pub include: Vec<ListSubscribersIncludeField>,
}

impl AppendUrlQueryPairs for SubscribersListParams {
Expand All @@ -125,7 +130,8 @@ impl AppendUrlQueryPairs for SubscribersListParams {
.append_option_query_value_pair("per_page", self.per_page.as_ref())
.append_option_query_value_pair("search", self.search.as_ref())
.append_option_query_value_pair("sort", self.sort.as_ref())
.append_option_query_value_pair("sort_order", self.sort_order.as_ref());
.append_option_query_value_pair("sort_order", self.sort_order.as_ref())
.append_vec_query_value_pair("include", self.include.as_ref());

if let Some(filters) = &self.filters {
query_pairs_mut.append_pair(
Expand Down Expand Up @@ -165,6 +171,23 @@ pub enum ListSubscribersSortField {

impl_as_query_value_from_to_string!(ListSubscribersSortField);

#[derive(
Debug,
Serialize,
Deserialize,
Eq,
PartialEq,
uniffi::Enum,
strum_macros::EnumString,
strum_macros::Display,
)]
#[strum(serialize_all = "snake_case")]
pub enum ListSubscribersIncludeField {
Country,
}

impl_as_query_value_from_to_string!(ListSubscribersIncludeField);

#[derive(Debug, Serialize, Deserialize, uniffi::Record)]
pub struct ListSubscribersResponse {
pub total: u64,
Expand Down Expand Up @@ -396,6 +419,7 @@ mod tests {
sort_order: Some(WpApiParamOrder::Asc),
filter: Some(SubscriberType::All),
filters: Some(vec![SubscriberType::All]),
include: vec![],
};

let mut query_pairs = url.query_pairs_mut();
Expand All @@ -421,6 +445,7 @@ mod tests {
sort_order: Some(WpApiParamOrder::Asc),
filter: Some(SubscriberType::EmailSubscriber),
filters: None,
include: vec![],
};

let mut query_pairs = url.query_pairs_mut();
Expand Down
34 changes: 32 additions & 2 deletions wp_api_integration_tests/tests/test_wp_com_subscribers_immut.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use wp_api::wp_com::{
WpComSiteId,
subscribers::{
IndividualSubscriberParams, IndividualSubscriberStatsParams, ListSubscribersSortField,
SubscribersListParams, SubscriptionId,
IndividualSubscriberParams, IndividualSubscriberStatsParams, ListSubscribersIncludeField,
ListSubscribersSortField, SubscribersListParams, SubscriptionId,
},
};
use wp_api_integration_tests::{WpComTestCredentials, prelude::*, wp_com_client};
Expand All @@ -26,6 +26,36 @@ async fn list_subscribers(#[case] params: SubscribersListParams) {
);
}

#[tokio::test]
#[parallel]
#[ignore]
async fn list_subscribers_include_country() {
let subscribers = wp_com_client()
.subscribers()
.list_subscribers(
&WpComSiteId(WpComTestCredentials::instance().site_id),
&SubscribersListParams {
include: vec![ListSubscribersIncludeField::Country],
..Default::default()
},
)
.await
.assert_response();
assert!(
subscribers.data.total > 0,
"Retrieved no subscribers: {subscribers:#?}"
);
let first_subscriber = subscribers
.data
.subscribers
.first()
.expect("Confirmed that there is at least one subscriber");
assert!(
first_subscriber.country.is_some(),
"'country' field is requested and should be available"
);
}

#[tokio::test]
#[apply(retrieve_cases)]
#[parallel]
Expand Down