diff --git a/native/swift/Sources/wordpress-api/WPComExtensions.swift b/native/swift/Sources/wordpress-api/WPComExtensions.swift index 33f2009ef..2d74520a1 100644 --- a/native/swift/Sources/wordpress-api/WPComExtensions.swift +++ b/native/swift/Sources/wordpress-api/WPComExtensions.swift @@ -19,3 +19,9 @@ public extension BotConversation { return false } } + +public extension SupportAttachment { + var dimensions: AttachmentDimensions? { + getAttachmentDimensions(attachment: self) + } +} diff --git a/wp_api/src/wp_com/support_tickets.rs b/wp_api/src/wp_com/support_tickets.rs index 324ce334a..1b8353b2f 100644 --- a/wp_api/src/wp_com/support_tickets.rs +++ b/wp_api/src/wp_com/support_tickets.rs @@ -65,7 +65,7 @@ pub struct SupportAttachment { pub content_type: String, pub size: u64, pub url: String, - pub metadata: HashMap, + pub metadata: HashMap, } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)] @@ -75,12 +75,25 @@ pub enum SupportMessageAuthor { SupportAgent(SupportAgentIdentity), } -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum, strum_macros::Display)] -#[strum(serialize_all = "snake_case")] +#[derive( + Debug, + Hash, + PartialEq, + Eq, + Serialize, + Deserialize, + uniffi::Enum, + strum_macros::Display, + strum_macros::EnumString, +)] pub enum AttachmentMetadataKey { + #[serde(alias = "width")] Width, + #[serde(alias = "height")] Height, - Other(String), + #[serde(untagged)] + #[strum(default)] + Custom(String), } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)] @@ -91,6 +104,40 @@ pub enum AttachmentMetadataValue { Boolean(bool), } +impl AttachmentMetadataValue { + pub fn get_number(&self) -> Option { + match self { + AttachmentMetadataValue::Number(number) => Some(*number), + _ => None, + } + } +} +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Record)] +pub struct AttachmentDimensions { + pub width: u64, + pub height: u64, +} + +#[uniffi::export] +pub fn get_attachment_dimensions(attachment: &SupportAttachment) -> Option { + let metadata = &attachment.metadata; + + let width = metadata + .get(&AttachmentMetadataKey::Width) + .and_then(|v| v.get_number()); + let height = metadata + .get(&AttachmentMetadataKey::Height) + .and_then(|v| v.get_number()); + + if let Some(width) = width + && let Some(height) = height + { + return Some(AttachmentDimensions { width, height }); + } + + None +} + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Record)] pub struct SupportAgentIdentity { pub id: u64, @@ -126,6 +173,7 @@ impl std::fmt::Display for ConversationId { #[cfg(test)] mod tests { use super::*; + use rstest::*; #[test] fn test_support_conversation_deserialization() { @@ -142,4 +190,83 @@ mod tests { serde_json::from_str(json).expect("Failed to deserialize support conversation list"); assert_eq!(conversation_list.len(), 11); } + + #[test] + fn test_support_conversation_with_attachments_deserialization() { + let json = include_str!( + "../../tests/wpcom/support_tickets/single-conversation-with-attachments.json" + ); + let conversation: SupportConversation = + serde_json::from_str(json).expect("Failed to deserialize support conversation"); + assert_eq!(conversation.messages.len(), 1); + assert_eq!(conversation.messages[0].attachments.len(), 2); + assert_eq!( + conversation.messages[0].attachments[0].filename, + "sample-image-1.jpg" + ); + assert_eq!( + conversation.messages[0].attachments[0].content_type, + "image/jpeg" + ); + assert_eq!(conversation.messages[0].attachments[0].size, 123456); + assert_eq!( + conversation.messages[0].attachments[0].url, + "https://example.com/attachments/token/token1/?name=sample-image-1.jpg" + ); + + let dimensions = + get_attachment_dimensions(&conversation.messages[0].attachments[0]).unwrap(); + + assert_eq!(dimensions.width, 1000); + assert_eq!(dimensions.height, 800); + + assert_eq!( + conversation.messages[0].attachments[1].filename, + "sample-image-2.jpg" + ); + assert_eq!( + conversation.messages[0].attachments[1].content_type, + "image/jpeg" + ); + assert_eq!(conversation.messages[0].attachments[1].size, 654321); + assert_eq!( + conversation.messages[0].attachments[1].url, + "https://example.com/attachments/token/token2/?name=sample-image-2.jpg" + ); + + let dimensions = + get_attachment_dimensions(&conversation.messages[0].attachments[1]).unwrap(); + assert_eq!(dimensions.width, 2000); + assert_eq!(dimensions.height, 1600); + } + + #[test] + fn test_attachment_metadata_key_custom_deserialization() { + let json = r#"{"Custom": "test"}"#; + let metadata: HashMap = + serde_json::from_str(json).expect("Failed to deserialize attachment metadata"); + assert_eq!(metadata.len(), 1); + } + + #[rstest] + #[case(AttachmentMetadataKey::Width, "Width")] + #[case(AttachmentMetadataKey::Height, "Height")] + #[case( + AttachmentMetadataKey::Custom(String::from("testlowercase")), + "testlowercase" + )] + #[case( + AttachmentMetadataKey::Custom(String::from("testWithCamelCase")), + "testWithCamelCase" + )] + #[case( + AttachmentMetadataKey::Custom(String::from("test_with_snake_case")), + "test_with_snake_case" + )] + fn test_attachment_metadata_key_to_string( + #[case] key: AttachmentMetadataKey, + #[case] expected_str: &str, + ) { + assert_eq!(key.to_string(), expected_str); + } } diff --git a/wp_api/tests/wpcom/support_tickets/single-conversation-with-attachments.json b/wp_api/tests/wpcom/support_tickets/single-conversation-with-attachments.json new file mode 100644 index 000000000..ff3f08d85 --- /dev/null +++ b/wp_api/tests/wpcom/support_tickets/single-conversation-with-attachments.json @@ -0,0 +1,46 @@ +{ + "id": 10000001, + "title": "Test Ticket", + "description": "Redacted for privacy", + "status": "new", + "messages": [ + { + "id": 20000001, + "content": "Redacted for privacy", + "role": "user", + "author": { + "id": 30000001, + "name": "Test User", + "email": "test.user@example.com" + }, + "author_is_current_user": true, + "created_at": "2025-10-27T21:30:43+00:00", + "attachments": [ + { + "id": 40000001, + "filename": "sample-image-1.jpg", + "content_type": "image/jpeg", + "size": 123456, + "url": "https://example.com/attachments/token/token1/?name=sample-image-1.jpg", + "metadata": { + "width": 1000, + "height": 800 + } + }, + { + "id": 40000002, + "filename": "sample-image-2.jpg", + "content_type": "image/jpeg", + "size": 654321, + "url": "https://example.com/attachments/token/token2/?name=sample-image-2.jpg", + "metadata": { + "width": 2000, + "height": 1600 + } + } + ] + } + ], + "created_at": "2025-10-27T21:30:43+00:00", + "updated_at": "2025-10-27T21:30:43+00:00" +}