wechat_minapp/mp_message/
send_message.rs1use super::TemplateMessage;
43use crate::utils::{RequestBuilder, ResponseExt};
44use crate::{Result, constants, error::Error};
45use serde::{Deserialize, Serialize};
46use serde_json::Value;
47use tracing::debug;
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct SendMessageArgs {
54 pub touser: String, pub template_id: String, pub url: Option<String>, pub data: serde_json::Value, pub miniprogram: Option<MinappProgram>, pub client_msg_id: Option<String>, }
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct MinappProgram {
67 pub appid: String, pub pagepath: String, }
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct SendMessageResponse {
74 pub msgid: Option<String>, pub errcode: Option<i32>, pub errmsg: Option<String>, }
78
79#[derive(Debug, Default)]
81pub struct SendMessageArgsBuilder {
82 touser: Option<String>,
83 template_id: Option<String>,
84 url: Option<String>,
85 data: Option<serde_json::Value>,
86 miniprogram: Option<MinappProgram>,
87 client_msg_id: Option<String>,
88}
89
90impl SendMessageArgs {
91 pub fn builder() -> SendMessageArgsBuilder {
93 SendMessageArgsBuilder::new()
94 }
95
96 pub fn touser(&self) -> &str {
98 &self.touser
99 }
100
101 pub fn template_id(&self) -> &str {
103 &self.template_id
104 }
105
106 pub fn url(&self) -> Option<&String> {
108 self.url.as_ref()
109 }
110
111 pub fn data(&self) -> &Value {
113 &self.data
114 }
115
116 pub fn miniprogram(&self) -> Option<MinappProgram> {
118 self.miniprogram.clone()
119 }
120
121 pub fn client_msg_id(&self) -> Option<&String> {
123 self.client_msg_id.as_ref()
124 }
125}
126
127impl SendMessageArgsBuilder {
128 pub fn new() -> Self {
129 Self::default()
130 }
131
132 pub fn touser(mut self, touser: impl Into<String>) -> Self {
134 self.touser = Some(touser.into());
135 self
136 }
137
138 pub fn template_id(mut self, template_id: impl Into<String>) -> Self {
140 self.template_id = Some(template_id.into());
141 self
142 }
143
144 pub fn url(mut self, url: impl Into<String>) -> Self {
146 self.url = Some(url.into());
147 self
148 }
149
150 pub fn data(mut self, data: impl Into<serde_json::Value>) -> Self {
152 self.data = Some(data.into());
153 self
154 }
155
156 pub fn miniprogram(mut self, minapp: MinappProgram) -> Self {
158 self.miniprogram = Some(minapp);
159 self
160 }
161
162 pub fn client_msg_id(mut self, client_msg_id: impl Into<String>) -> Self {
166 self.client_msg_id = Some(client_msg_id.into());
167 self
168 }
169
170 pub fn build(self) -> Result<SendMessageArgs> {
172 let touser = self
173 .touser
174 .ok_or_else(|| Error::InvalidParameter("接收者openid不能为空".to_string()))?;
175
176 let template_id = self
177 .template_id
178 .ok_or_else(|| Error::InvalidParameter("模板ID不能为空".to_string()))?;
179
180 let data = self
181 .data
182 .ok_or_else(|| Error::InvalidParameter("模板数据不能为空".to_string()))?;
183
184 Self::validate_data(&data)?;
186
187 Ok(SendMessageArgs {
188 touser,
189 template_id,
190 url: self.url,
191 data,
192 miniprogram: self.miniprogram,
193 client_msg_id: self.client_msg_id,
194 })
195 }
196
197 fn validate_data(data: &Value) -> Result<()> {
199 if let Value::Object(map) = data {
200 for (key, value) in map {
201 if key.len() > 20 {
202 return Err(Error::InvalidParameter(format!(
203 "字段名'{}'长度不能超过20个字符",
204 key
205 )));
206 }
207
208 if let Value::Object(item) = value {
209 if let Some(val) = item.get("value") {
210 if let Value::String(s) = val
211 && s.len() > 20
212 {
213 return Err(Error::InvalidParameter(format!(
214 "字段'{}'的值长度不能超过20个字符",
215 key
216 )));
217 }
218 } else {
219 return Err(Error::InvalidParameter(format!(
220 "字段'{}'缺少value属性",
221 key
222 )));
223 }
224 } else {
225 return Err(Error::InvalidParameter(format!(
226 "字段'{}'格式不正确,应为{{value: string}}",
227 key
228 )));
229 }
230 }
231 Ok(())
232 } else {
233 Err(Error::InvalidParameter(
234 "模板数据必须是对象类型".to_string(),
235 ))
236 }
237 }
238}
239
240impl TemplateMessage {
241 pub async fn send_message(&self, args: SendMessageArgs) -> Result<SendMessageResponse> {
281 debug!("send mp message args {:?}", &args);
282
283 let query = serde_json::json!({
284 "access_token": self.client.token().await?
285 });
286
287 let body = serde_json::to_value(args)?;
288
289 let request = RequestBuilder::new(constants::MP_MESSAGE_SEND_END_POINT)
290 .query(query)
291 .body(body)
292 .build()?;
293
294 let client = &self.client.client;
295 let response = client.execute(request).await?;
296
297 debug!("response: {:#?}", response);
298 response.to_json::<SendMessageResponse>()
299 }
300}