use super::empty::EmptyType;
use super::link::LinkType;
use super::list_member_activity::{CollectionListMemberActivity, ListMemberActivityBuilder};
use super::list_member_goals::{CollectionListMemberGoal, ListMemberGoalBuilder};
use super::list_member_notes::{CollectionListMemberNote, ListMemberNote, ListMemberNoteBuilder};
use super::list_member_tags::{
CollectionListMemberTag, ListMemberTagBuilder, ListMemberTagParam, ListMemberTagType,
};
use crate::api::MailchimpApi;
use crate::internal::error_type::MailchimpErrorType;
use crate::internal::request::MailchimpResult;
use crate::iter::{BuildIter, MailchimpCollection, MalchimpIter, ResourceFilter, SimpleFilter};
use std::collections::HashMap;
use log::error;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ListNote {
#[serde(default)]
pub note_id: u64,
#[serde(default)]
pub created_at: String,
#[serde(default)]
pub created_by: String,
#[serde(default)]
pub note: String,
}
impl Default for ListNote {
fn default() -> Self {
ListNote {
note_id: 0,
created_at: "".to_string(),
created_by: "".to_string(),
note: "".to_string(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ListMarketingPermision {
#[serde(default)]
pub marketing_permission_id: String,
#[serde(default)]
pub text: String,
#[serde(default)]
pub enabled: bool,
}
impl Default for ListMarketingPermision {
fn default() -> Self {
ListMarketingPermision {
marketing_permission_id: "".to_string(),
text: "".to_string(),
enabled: false,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SubscriberStats {
#[serde(default)]
pub avg_open_rate: f32,
#[serde(default)]
pub avg_click_rate: f32,
}
impl Default for SubscriberStats {
fn default() -> Self {
SubscriberStats {
avg_open_rate: 0.0,
avg_click_rate: 0.0,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SubscriberLocation {
#[serde(default)]
pub latitude: f32,
#[serde(default)]
pub longitude: f32,
#[serde(default)]
pub gmtoff: i64,
#[serde(default)]
pub dstoff: i64,
#[serde(default)]
pub country_code: String,
#[serde(default)]
pub timezone: String,
}
impl Default for SubscriberLocation {
fn default() -> Self {
SubscriberLocation {
latitude: 0.0,
longitude: 0.0,
gmtoff: 0,
dstoff: 0,
country_code: "".to_string(),
timezone: "".to_string(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ListMember {
#[serde(default)]
pub id: String,
#[serde(default)]
pub email_address: String,
#[serde(default)]
pub unique_email_id: String,
#[serde(default)]
pub email_type: String,
#[serde(default)]
pub status: String,
#[serde(default)]
pub unsubscribe_reason: String,
#[serde(default)]
pub merge_fields: HashMap<String, String>,
#[serde(default)]
pub interests: HashMap<String, String>,
#[serde(default)]
pub stats: SubscriberStats,
#[serde(default)]
pub timestamp_signup: String,
#[serde(default)]
pub ip_opt: String,
#[serde(default)]
pub timestamp_opt: String,
#[serde(default)]
pub member_rating: u64,
#[serde(default)]
pub last_changed: String,
#[serde(default)]
pub language: String,
#[serde(default)]
pub vip: bool,
#[serde(default)]
pub email_client: String,
#[serde(default)]
pub location: SubscriberLocation,
#[serde(default)]
pub marketing_permissions: Vec<ListMarketingPermision>,
#[serde(default)]
pub last_note: ListNote,
#[serde(default)]
pub tags_count: u64,
#[serde(default)]
pub tags: Vec<String>,
#[serde(default)]
pub ip_signup: String,
#[serde(default)]
pub list_id: String,
#[serde(default)]
pub _links: Vec<LinkType>,
#[serde(skip)]
_api: MailchimpApi,
#[serde(skip)]
_endpoint: String,
}
impl ListMember {
pub fn permanently_delete(&self) -> Option<MailchimpErrorType> {
let mut b_endpoint = self._endpoint.clone();
b_endpoint.push_str("/actions/delete-permanent");
match self
._api
.post::<EmptyType, HashMap<String, String>>(b_endpoint.as_str(), HashMap::new())
{
Ok(_) => None,
Err(e) => Some(e),
}
}
pub fn delete(&self) -> Option<MailchimpErrorType> {
let b_endpoint = self._endpoint.clone();
match self
._api
.delete::<EmptyType>(b_endpoint.as_str(), HashMap::new())
{
Ok(_) => None,
Err(e) => Some(e),
}
}
pub fn set_api(&mut self, n_api: &MailchimpApi) {
self._api = n_api.clone()
}
pub fn set_endpoint<'a>(&mut self, n_endpoint: &'a str) {
self._endpoint = n_endpoint.to_string();
}
pub fn get_base_endpoint(&self) -> String {
let mut endpoint = self._endpoint.clone() + "/";
endpoint.push_str(&self.id);
endpoint
}
pub fn get_activity(&self) -> MalchimpIter<ListMemberActivityBuilder> {
let mut endpoint = self.get_base_endpoint();
endpoint.push_str("/activity");
let filter_params = SimpleFilter::default();
match self
._api
.get::<CollectionListMemberActivity>(&endpoint, filter_params.build_payload())
{
Ok(collection) => MalchimpIter {
builder: ListMemberActivityBuilder {},
data: collection.activity,
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: collection.total_items,
api: self._api.clone(),
endpoint: endpoint.clone(),
},
Err(e) => {
error!( target: "mailchimp", "Get List Members: Response Error details: {:?}", e);
MalchimpIter {
builder: ListMemberActivityBuilder {},
data: Vec::new(),
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: 0,
api: self._api.clone(),
endpoint: endpoint.clone(),
}
}
}
}
pub fn get_goals(&self) -> MalchimpIter<ListMemberGoalBuilder> {
let mut endpoint = self.get_base_endpoint().to_string() + "/";
endpoint.push_str(&self.id);
endpoint.push_str("/goals");
let filter_params = SimpleFilter::default();
match self
._api
.get::<CollectionListMemberGoal>(&endpoint, filter_params.build_payload())
{
Ok(collection) => MalchimpIter {
builder: ListMemberGoalBuilder {},
data: collection.goals,
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: collection.total_items,
api: self._api.clone(),
endpoint: endpoint.clone(),
},
Err(e) => {
error!( target: "mailchimp", "Get List Members: Response Error details: {:?}", e);
MalchimpIter {
builder: ListMemberGoalBuilder {},
data: Vec::new(),
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: 0,
api: self._api.clone(),
endpoint: endpoint.clone(),
}
}
}
}
pub fn get_tags(&self) -> MalchimpIter<ListMemberTagBuilder> {
let mut endpoint = self.get_base_endpoint();
endpoint.push_str("/tags");
let filter_params = SimpleFilter::default();
match self
._api
.get::<CollectionListMemberTag>(&endpoint, filter_params.build_payload())
{
Ok(collection) => MalchimpIter {
builder: ListMemberTagBuilder {},
data: collection.tags,
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: collection.total_items,
api: self._api.clone(),
endpoint: endpoint.clone(),
},
Err(e) => {
error!( target: "mailchimp", "Get List Members: Response Error details: {:?}", e);
MalchimpIter {
builder: ListMemberTagBuilder {},
data: Vec::new(),
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: 0,
api: self._api.clone(),
endpoint: endpoint.clone(),
}
}
}
}
pub fn post_tag(&self, tags: Vec<ListMemberTagType>) -> Option<MailchimpErrorType> {
let mut endpoint = self.get_base_endpoint();
endpoint.push_str("/tags");
let param = ListMemberTagParam { tags: tags };
match self
._api
.post::<EmptyType, ListMemberTagParam>(&endpoint, param)
{
Ok(_) => None,
Err(e) => Some(e),
}
}
pub fn get_notes(&self, filters: Option<SimpleFilter>) -> MalchimpIter<ListMemberNoteBuilder> {
let mut endpoint = self.get_base_endpoint();
endpoint.push_str("/notes");
let filter_params = if let Some(f) = filters {
f
} else {
SimpleFilter::default()
};
match self
._api
.get::<CollectionListMemberNote>(&endpoint, filter_params.build_payload())
{
Ok(collection) => MalchimpIter {
builder: ListMemberNoteBuilder {
endpoint: endpoint.clone(),
},
data: collection.notes,
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: collection.total_items,
api: self._api.clone(),
endpoint: endpoint.clone(),
},
Err(e) => {
error!( target: "mailchimp", "Get List Members: Response Error details: {:?}", e);
MalchimpIter {
builder: ListMemberNoteBuilder {
endpoint: endpoint.clone(),
},
data: Vec::new(),
cur_filters: filter_params.clone(),
cur_it: 0,
total_items: 0,
api: self._api.clone(),
endpoint: endpoint.clone(),
}
}
}
}
pub fn get_specific_note<'a>(&self, note_id: &'a str) -> MailchimpResult<ListMemberNote> {
let mut endpoint = self.get_base_endpoint();
endpoint.push_str("/notes/");
endpoint.push_str(note_id);
self._api.get::<ListMemberNote>(&endpoint, HashMap::new())
}
pub fn create_note<'a>(&self, note: &'a str) -> MailchimpResult<ListMemberNote> {
let mut endpoint = self.get_base_endpoint();
endpoint.push_str("/notes");
let mut payload = HashMap::new();
payload.insert("note".to_string(), note.to_string());
self._api
.post::<ListMemberNote, HashMap<String, String>>(&endpoint, payload)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CollectionListMembers {
#[serde(default)]
pub members: Vec<ListMember>,
#[serde(default)]
pub list_id: String,
#[serde(default)]
pub total_items: u64,
#[serde(default)]
pub _links: Vec<LinkType>,
}
impl MailchimpCollection<ListMember> for CollectionListMembers {
fn get_total_items(&self) -> u64 {
self.total_items
}
fn get_values(&self) -> Vec<ListMember> {
self.members.clone()
}
}
impl Default for CollectionListMembers {
fn default() -> Self {
CollectionListMembers {
list_id: String::new(),
members: Vec::new(),
total_items: 0,
_links: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct ListMembersFilter {
pub fields: Option<String>,
pub exclude_fields: Option<String>,
pub count: Option<u64>,
pub offset: Option<u64>,
pub email_type: Option<String>,
pub status: Option<String>,
pub since_timestamp_opt: Option<String>,
pub before_timestamp_opt: Option<String>,
pub since_last_changed: Option<String>,
pub before_last_changed: Option<String>,
pub unique_email_id: Option<String>,
pub vip_only: Option<String>,
pub interest_category_id: Option<String>,
pub interest_ids: Option<String>,
pub interest_match: Option<String>,
pub sort_field: Option<String>,
pub sort_dir: Option<String>,
pub since_last_campaign: Option<bool>,
pub unsubscribed_since: Option<String>,
}
impl Default for ListMembersFilter {
fn default() -> Self {
ListMembersFilter {
fields: None,
exclude_fields: None,
count: Some(50),
offset: Some(0),
email_type: None,
status: None,
since_timestamp_opt: None,
before_timestamp_opt: None,
since_last_changed: None,
before_last_changed: None,
unique_email_id: None,
vip_only: None,
interest_category_id: None,
interest_ids: None,
interest_match: None,
sort_field: None,
sort_dir: None,
since_last_campaign: None,
unsubscribed_since: None,
}
}
}
impl ResourceFilter for ListMembersFilter {
fn build_payload(&self) -> HashMap<String, String> {
let mut payload = HashMap::new();
if self.fields.is_some() {
payload.insert("fields".to_string(), self.fields.as_ref().unwrap().clone());
}
if self.exclude_fields.is_some() {
payload.insert(
"exclude_fields".to_string(),
self.exclude_fields.as_ref().unwrap().clone(),
);
}
if self.count.is_some() {
payload.insert(
"count".to_string(),
format!("{:}", self.count.as_ref().unwrap().clone()),
);
}
if self.offset.is_some() {
payload.insert(
"offset".to_string(),
format!("{:}", self.offset.as_ref().unwrap().clone()),
);
}
if self.email_type.is_some() {
payload.insert(
"email_type".to_string(),
format!("{:}", self.email_type.as_ref().unwrap().clone()),
);
}
if self.status.is_some() {
payload.insert(
"status".to_string(),
format!("{:}", self.status.as_ref().unwrap().clone()),
);
}
if self.since_timestamp_opt.is_some() {
payload.insert(
"since_timestamp_opt".to_string(),
format!("{:}", self.since_timestamp_opt.as_ref().unwrap().clone()),
);
}
if self.before_timestamp_opt.is_some() {
payload.insert(
"before_timestamp_opt".to_string(),
format!("{:}", self.before_timestamp_opt.as_ref().unwrap().clone()),
);
}
if self.since_last_changed.is_some() {
payload.insert(
"since_last_changed".to_string(),
format!("{:}", self.since_last_changed.as_ref().unwrap().clone()),
);
}
if self.before_last_changed.is_some() {
payload.insert(
"before_last_changed".to_string(),
format!("{:}", self.before_last_changed.as_ref().unwrap().clone()),
);
}
if self.unique_email_id.is_some() {
payload.insert(
"unique_email_id".to_string(),
format!("{:}", self.unique_email_id.as_ref().unwrap().clone()),
);
}
if self.vip_only.is_some() {
payload.insert(
"vip_only".to_string(),
format!("{:}", self.vip_only.as_ref().unwrap().clone()),
);
}
if self.interest_category_id.is_some() {
payload.insert(
"interest_category_id".to_string(),
format!("{:}", self.interest_category_id.as_ref().unwrap().clone()),
);
}
if self.interest_ids.is_some() {
payload.insert(
"interest_ids".to_string(),
format!("{:}", self.interest_ids.as_ref().unwrap().clone()),
);
}
if self.interest_match.is_some() {
payload.insert(
"interest_match".to_string(),
format!("{:}", self.interest_match.as_ref().unwrap().clone()),
);
}
if self.sort_field.is_some() {
payload.insert(
"sort_field".to_string(),
format!("{:}", self.sort_field.as_ref().unwrap().clone()),
);
}
if self.sort_dir.is_some() {
payload.insert(
"sort_dir".to_string(),
format!("{:}", self.sort_dir.as_ref().unwrap().clone()),
);
}
if self.since_last_campaign.is_some() {
payload.insert(
"since_last_campaign".to_string(),
format!("{:}", self.since_last_campaign.as_ref().unwrap().clone()),
);
}
if self.unsubscribed_since.is_some() {
payload.insert(
"unsubscribed_since".to_string(),
format!("{:}", self.unsubscribed_since.as_ref().unwrap().clone()),
);
}
payload
}
}
#[derive(Debug)]
pub struct ListMembersBuilder {
pub endpoint: String,
}
impl BuildIter for ListMembersBuilder {
type Item = ListMember;
type FilterItem = ListMembersFilter;
type Collection = CollectionListMembers;
fn update_item(&self, data: &Self::Item, api: &MailchimpApi) -> Self::Item {
let mut in_data = data.clone();
in_data.set_api(api);
in_data.set_endpoint(&self.endpoint);
in_data
}
fn update_filter_offset(&self, filter: &Self::FilterItem) -> Self::FilterItem {
let mut f = filter.clone();
f.offset = Some(f.count.unwrap() + f.offset.unwrap());
f
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ListMemberParams {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email_address: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status_if_new: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub merge_fields: Option<HashMap<String, String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub interests: Option<HashMap<String, String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub vip: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub location: Option<SubscriberLocation>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub marketing_permissions: Option<Vec<ListMarketingPermision>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tags_count: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ip_signup: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timestamp_signup: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ip_opt: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timestamp_opt: Option<String>,
}