use crate::client::Client;
use crate::error::Result;
use crate::types::{Paging, SuccessResponse};
use serde::{Deserialize, Serialize};
pub struct TemplatesApi {
client: Client,
}
impl TemplatesApi {
pub(crate) fn new(client: Client) -> Self {
Self { client }
}
pub async fn list(&self, waba_id: &str) -> Result<TemplatesResponse> {
let url = self.client.endpoint_url(&format!("{}/message_templates", waba_id));
self.client.get(&url).await
}
pub async fn list_by_status(
&self,
waba_id: &str,
status: TemplateStatus,
) -> Result<TemplatesResponse> {
let url = self.client.endpoint_url(&format!(
"{}/message_templates?status={}",
waba_id,
status.as_str()
));
self.client.get(&url).await
}
pub async fn get_by_name(&self, waba_id: &str, name: &str) -> Result<TemplatesResponse> {
let url = self.client.endpoint_url(&format!(
"{}/message_templates?name={}",
waba_id, name
));
self.client.get(&url).await
}
pub async fn create(
&self,
waba_id: &str,
template: &CreateTemplate,
) -> Result<CreateTemplateResponse> {
let url = self.client.endpoint_url(&format!("{}/message_templates", waba_id));
self.client.post(&url, template).await
}
pub async fn delete(&self, waba_id: &str, template_name: &str) -> Result<SuccessResponse> {
let url = self.client.endpoint_url(&format!(
"{}/message_templates?name={}",
waba_id, template_name
));
self.client.delete(&url).await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplatesResponse {
pub data: Vec<MessageTemplate>,
#[serde(default)]
pub paging: Option<Paging>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageTemplate {
pub name: String,
pub components: Vec<TemplateComponentDef>,
pub language: String,
pub status: String,
pub category: String,
#[serde(default)]
pub id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateComponentDef {
#[serde(rename = "type")]
pub component_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub buttons: Option<Vec<TemplateButton>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub example: Option<TemplateExample>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateButton {
#[serde(rename = "type")]
pub button_type: String,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phone_number: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemplateExample {
#[serde(skip_serializing_if = "Option::is_none")]
pub header_handle: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub header_text: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body_text: Option<Vec<Vec<String>>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateTemplate {
pub name: String,
pub category: String,
pub language: String,
pub components: Vec<TemplateComponentDef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_category_change: Option<bool>,
}
impl CreateTemplate {
pub fn new(name: impl Into<String>, category: TemplateCategory, language: impl Into<String>) -> Self {
Self {
name: name.into(),
category: category.as_str().to_string(),
language: language.into(),
components: Vec::new(),
allow_category_change: None,
}
}
pub fn with_header(mut self, format: HeaderFormat, text: Option<String>) -> Self {
self.components.push(TemplateComponentDef {
component_type: "HEADER".to_string(),
format: Some(format.as_str().to_string()),
text,
buttons: None,
example: None,
});
self
}
pub fn with_body(mut self, text: impl Into<String>) -> Self {
self.components.push(TemplateComponentDef {
component_type: "BODY".to_string(),
format: None,
text: Some(text.into()),
buttons: None,
example: None,
});
self
}
pub fn with_footer(mut self, text: impl Into<String>) -> Self {
self.components.push(TemplateComponentDef {
component_type: "FOOTER".to_string(),
format: None,
text: Some(text.into()),
buttons: None,
example: None,
});
self
}
pub fn with_buttons(mut self, buttons: Vec<TemplateButton>) -> Self {
self.components.push(TemplateComponentDef {
component_type: "BUTTONS".to_string(),
format: None,
text: None,
buttons: Some(buttons),
example: None,
});
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateTemplateResponse {
pub id: String,
pub status: String,
pub category: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TemplateStatus {
Approved,
Pending,
Rejected,
Paused,
Disabled,
}
impl TemplateStatus {
pub fn as_str(&self) -> &str {
match self {
TemplateStatus::Approved => "APPROVED",
TemplateStatus::Pending => "PENDING",
TemplateStatus::Rejected => "REJECTED",
TemplateStatus::Paused => "PAUSED",
TemplateStatus::Disabled => "DISABLED",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TemplateCategory {
Marketing,
Utility,
Authentication,
}
impl TemplateCategory {
pub fn as_str(&self) -> &str {
match self {
TemplateCategory::Marketing => "MARKETING",
TemplateCategory::Utility => "UTILITY",
TemplateCategory::Authentication => "AUTHENTICATION",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HeaderFormat {
Text,
Image,
Video,
Document,
Location,
}
impl HeaderFormat {
pub fn as_str(&self) -> &str {
match self {
HeaderFormat::Text => "TEXT",
HeaderFormat::Image => "IMAGE",
HeaderFormat::Video => "VIDEO",
HeaderFormat::Document => "DOCUMENT",
HeaderFormat::Location => "LOCATION",
}
}
}