use super::TemplateMessage;
use crate::utils::{RequestBuilder, ResponseExt};
use crate::{Result, constants, error::Error};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tracing::debug;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendMessageArgs {
pub touser: String, pub template_id: String, pub page: Option<String>, pub data: serde_json::Value, pub miniprogram_state: Option<String>, pub lang: Option<String>, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendMessageResponse {
pub msgid: Option<String>, pub errcode: Option<i32>, pub errmsg: Option<String>, }
#[derive(Debug, Default)]
pub struct SendMessageArgsBuilder {
touser: Option<String>,
template_id: Option<String>,
page: Option<String>,
data: Option<serde_json::Value>,
miniprogram_state: Option<String>,
lang: Option<String>,
}
impl SendMessageArgs {
pub fn builder() -> SendMessageArgsBuilder {
SendMessageArgsBuilder::new()
}
pub fn touser(&self) -> &str {
&self.touser
}
pub fn template_id(&self) -> &str {
&self.template_id
}
pub fn page(&self) -> Option<&String> {
self.page.as_ref()
}
pub fn data(&self) -> &Value {
&self.data
}
pub fn miniprogram_state(&self) -> Option<&String> {
self.miniprogram_state.as_ref()
}
pub fn lang(&self) -> Option<&String> {
self.lang.as_ref()
}
}
impl SendMessageArgsBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn touser(mut self, touser: impl Into<String>) -> Self {
self.touser = Some(touser.into());
self
}
pub fn template_id(mut self, template_id: impl Into<String>) -> Self {
self.template_id = Some(template_id.into());
self
}
pub fn page(mut self, page: impl Into<String>) -> Self {
self.page = Some(page.into());
self
}
pub fn data(mut self, data: impl Into<serde_json::Value>) -> Self {
self.data = Some(data.into());
self
}
pub fn miniprogram_state(mut self, state: impl Into<String>) -> Self {
self.miniprogram_state = Some(state.into());
self
}
pub fn lang(mut self, lang: impl Into<String>) -> Self {
self.lang = Some(lang.into());
self
}
pub fn build(self) -> Result<SendMessageArgs> {
let touser = self
.touser
.ok_or_else(|| Error::InvalidParameter("接收者openid不能为空".to_string()))?;
let template_id = self
.template_id
.ok_or_else(|| Error::InvalidParameter("模板ID不能为空".to_string()))?;
let data = self
.data
.ok_or_else(|| Error::InvalidParameter("模板数据不能为空".to_string()))?;
Self::validate_data(&data)?;
Ok(SendMessageArgs {
touser,
template_id,
page: self.page,
data,
miniprogram_state: self.miniprogram_state,
lang: self.lang,
})
}
fn validate_data(data: &Value) -> Result<()> {
if let Value::Object(map) = data {
for (key, value) in map {
if key.chars().count() > 20 {
return Err(Error::InvalidParameter(format!(
"字段名'{}'长度不能超过20个字符",
key
)));
}
if let Value::Object(item) = value {
if let Some(val) = item.get("value") {
if let Value::String(s) = val
&& s.chars().count() > 50
{
return Err(Error::InvalidParameter(format!(
"字段'{}'的值长度不能超过50个字符",
key
)));
}
} else {
return Err(Error::InvalidParameter(format!(
"字段'{}'缺少value属性",
key
)));
}
} else {
return Err(Error::InvalidParameter(format!(
"字段'{}'格式不正确,应为{{value: string}}",
key
)));
}
}
Ok(())
} else {
Err(Error::InvalidParameter(
"模板数据必须是对象类型".to_string(),
))
}
}
}
impl TemplateMessage {
pub async fn send_message(&self, args: SendMessageArgs) -> Result<SendMessageResponse> {
debug!("send template message args {:?}", &args);
let query = serde_json::json!({
"access_token": self.client.token().await?
});
let body = serde_json::to_value(args)?;
let request = RequestBuilder::new(constants::TEMPLATE_MESSAGE_SEND_END_POINT)
.query(query)
.body(body)
.build()?;
let client = &self.client.client;
let response = client.execute(request).await?;
debug!("response: {:#?}", response);
response.to_json::<SendMessageResponse>()
}
}