Skip to content

Commit 2346a28

Browse files
committed
Add public message mapping and tests
Introduce support_public_message and map_support_message helpers to properly handle widget messages that omit the private flag. Replace usage of support_messages with support_public_messages in Chatwoot client to collect public messages. Add support_public_messages collector and unit tests verifying: (1) widget messages without a private field are treated as public, and (2) existing strict behavior for support_message remains None when private is missing. Small refactor to centralize private-flag handling.
1 parent 39a9aaa commit 2346a28

2 files changed

Lines changed: 72 additions & 6 deletions

File tree

core/crates/support/src/chatwoot.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::io;
1010
use crate::{
1111
ChatwootConfigResponse, ChatwootContactResponse, ChatwootContactUpdate, ChatwootMessageInput, ChatwootMessagesResponse, ChatwootSession, ChatwootTypingInput, Message,
1212
constants::{PATH_CONFIG, PATH_CONTACT_SET_USER, PATH_MESSAGES, PATH_TOGGLE_TYPING, PATH_UPDATE_LAST_SEEN, QUERY_WIDGET_PUBLIC_TOKEN},
13-
support_messages,
13+
support_public_messages,
1414
};
1515

1616
#[derive(Clone)]
@@ -54,7 +54,7 @@ impl ChatwootClient {
5454
.json(self.authenticated(self.client.get(self.widget_url(PATH_MESSAGES)), &session.auth_token)?.send().await?)
5555
.await?;
5656

57-
Ok(messages_from_timestamp(support_messages(&response.payload), from_timestamp))
57+
Ok(messages_from_timestamp(support_public_messages(&response.payload), from_timestamp))
5858
}
5959

6060
pub async fn send_message(&self, session: &ChatwootSession, content: String) -> Result<SupportMessage, Box<dyn Error + Send + Sync>> {

core/crates/support/src/model.rs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use primitives::{Device, SupportAgent, SupportMessage, SupportMessageDeliverySta
33
use serde::{Deserialize, Serialize};
44
use std::collections::HashMap;
55

6-
use crate::constants::{
7-
CHATWOOT_CONTENT_TYPE_TEXT, CHATWOOT_DELIVERY_STATUS_DELIVERED, CHATWOOT_DELIVERY_STATUS_READ, CHATWOOT_DELIVERY_STATUS_SENT, CHATWOOT_FILE_TYPE_IMAGE,
8-
};
6+
use crate::constants::{CHATWOOT_CONTENT_TYPE_TEXT, CHATWOOT_DELIVERY_STATUS_DELIVERED, CHATWOOT_DELIVERY_STATUS_READ, CHATWOOT_DELIVERY_STATUS_SENT, CHATWOOT_FILE_TYPE_IMAGE};
97

108
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
119
#[serde(from = "i32", into = "i32")]
@@ -160,6 +158,14 @@ impl ChatwootWebhookPayload {
160158

161159
impl Message {
162160
pub(crate) fn support_message(&self) -> Option<SupportMessage> {
161+
self.map_support_message(self.private)
162+
}
163+
164+
pub(crate) fn support_public_message(&self) -> Option<SupportMessage> {
165+
self.map_support_message(self.private.or(Some(false)))
166+
}
167+
168+
fn map_support_message(&self, private: Option<bool>) -> Option<SupportMessage> {
163169
let sender = match &self.message_type {
164170
MessageType::Incoming => SupportMessageSender::User,
165171
MessageType::Outgoing => SupportMessageSender::Agent(self.sender.as_ref()?.support_agent()?),
@@ -169,7 +175,7 @@ impl Message {
169175
self.id,
170176
self.content.as_deref(),
171177
self.content_type.as_deref(),
172-
self.private,
178+
private,
173179
sender,
174180
support_delivery_status(self.status.as_deref()),
175181
datetime_from_unix_timestamp(self.created_at)?,
@@ -294,6 +300,10 @@ pub(crate) fn support_messages(messages: &[Message]) -> Vec<SupportMessage> {
294300
messages.iter().filter_map(Message::support_message).collect()
295301
}
296302

303+
pub(crate) fn support_public_messages(messages: &[Message]) -> Vec<SupportMessage> {
304+
messages.iter().filter_map(Message::support_public_message).collect()
305+
}
306+
297307
fn support_message(
298308
id: i64,
299309
content: Option<&str>,
@@ -342,3 +352,59 @@ fn support_delivery_status(status: Option<&str>) -> SupportMessageDeliveryStatus
342352
fn datetime_from_unix_timestamp(value: i64) -> Option<DateTime<Utc>> {
343353
DateTime::<Utc>::from_timestamp(value, 0)
344354
}
355+
356+
#[cfg(test)]
357+
mod tests {
358+
use super::*;
359+
use primitives::{SupportAgent, SupportMessageDeliveryStatus, SupportMessageSender};
360+
361+
#[test]
362+
fn test_support_public_messages_maps_widget_messages_without_private() {
363+
let response: ChatwootMessagesResponse = serde_json::from_str(
364+
r#"{
365+
"payload": [{
366+
"id": 1,
367+
"content": "from agent",
368+
"conversation_id": 2,
369+
"message_type": 1,
370+
"content_type": "text",
371+
"created_at": 1766478193,
372+
"sender": {"name": "Test Agent"}
373+
}]
374+
}"#,
375+
)
376+
.unwrap();
377+
378+
let messages = support_public_messages(&response.payload);
379+
380+
assert_eq!(messages.len(), 1);
381+
assert_eq!(messages[0].id, "1");
382+
assert_eq!(messages[0].content, "from agent");
383+
assert_eq!(
384+
messages[0].sender,
385+
SupportMessageSender::Agent(SupportAgent {
386+
name: "Test Agent".to_string(),
387+
avatar_url: None,
388+
})
389+
);
390+
assert_eq!(messages[0].delivery_status, SupportMessageDeliveryStatus::Sent);
391+
}
392+
393+
#[test]
394+
fn test_support_messages_keep_missing_private_strict() {
395+
let message: Message = serde_json::from_str(
396+
r#"{
397+
"id": 1,
398+
"content": "from agent",
399+
"conversation_id": 2,
400+
"message_type": 1,
401+
"content_type": "text",
402+
"created_at": 1766478193,
403+
"sender": {"name": "Test Agent"}
404+
}"#,
405+
)
406+
.unwrap();
407+
408+
assert_eq!(message.support_message(), None);
409+
}
410+
}

0 commit comments

Comments
 (0)