Skip to content

Commit 24bca97

Browse files
authored
Make support attachment dimensions strongly typed (#983)
1 parent fa5b84f commit 24bca97

File tree

3 files changed

+183
-4
lines changed

3 files changed

+183
-4
lines changed

native/swift/Sources/wordpress-api/WPComExtensions.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ public extension BotConversation {
1919
return false
2020
}
2121
}
22+
23+
public extension SupportAttachment {
24+
var dimensions: AttachmentDimensions? {
25+
getAttachmentDimensions(attachment: self)
26+
}
27+
}

wp_api/src/wp_com/support_tickets.rs

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub struct SupportAttachment {
9090
pub content_type: String,
9191
pub size: u64,
9292
pub url: String,
93-
pub metadata: HashMap<String, AttachmentMetadataValue>,
93+
pub metadata: HashMap<AttachmentMetadataKey, AttachmentMetadataValue>,
9494
}
9595

9696
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
@@ -100,12 +100,25 @@ pub enum SupportMessageAuthor {
100100
SupportAgent(SupportAgentIdentity),
101101
}
102102

103-
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum, strum_macros::Display)]
104-
#[strum(serialize_all = "snake_case")]
103+
#[derive(
104+
Debug,
105+
Hash,
106+
PartialEq,
107+
Eq,
108+
Serialize,
109+
Deserialize,
110+
uniffi::Enum,
111+
strum_macros::Display,
112+
strum_macros::EnumString,
113+
)]
105114
pub enum AttachmentMetadataKey {
115+
#[serde(alias = "width")]
106116
Width,
117+
#[serde(alias = "height")]
107118
Height,
108-
Other(String),
119+
#[serde(untagged)]
120+
#[strum(default)]
121+
Custom(String),
109122
}
110123

111124
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
@@ -116,6 +129,40 @@ pub enum AttachmentMetadataValue {
116129
Boolean(bool),
117130
}
118131

132+
impl AttachmentMetadataValue {
133+
pub fn get_number(&self) -> Option<u64> {
134+
match self {
135+
AttachmentMetadataValue::Number(number) => Some(*number),
136+
_ => None,
137+
}
138+
}
139+
}
140+
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Record)]
141+
pub struct AttachmentDimensions {
142+
pub width: u64,
143+
pub height: u64,
144+
}
145+
146+
#[uniffi::export]
147+
pub fn get_attachment_dimensions(attachment: &SupportAttachment) -> Option<AttachmentDimensions> {
148+
let metadata = &attachment.metadata;
149+
150+
let width = metadata
151+
.get(&AttachmentMetadataKey::Width)
152+
.and_then(|v| v.get_number());
153+
let height = metadata
154+
.get(&AttachmentMetadataKey::Height)
155+
.and_then(|v| v.get_number());
156+
157+
if let Some(width) = width
158+
&& let Some(height) = height
159+
{
160+
return Some(AttachmentDimensions { width, height });
161+
}
162+
163+
None
164+
}
165+
119166
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, uniffi::Record)]
120167
pub struct SupportAgentIdentity {
121168
pub id: u64,
@@ -151,6 +198,7 @@ impl std::fmt::Display for ConversationId {
151198
#[cfg(test)]
152199
mod tests {
153200
use super::*;
201+
use rstest::*;
154202

155203
#[test]
156204
fn test_support_conversation_deserialization() {
@@ -167,4 +215,83 @@ mod tests {
167215
serde_json::from_str(json).expect("Failed to deserialize support conversation list");
168216
assert_eq!(conversation_list.len(), 11);
169217
}
218+
219+
#[test]
220+
fn test_support_conversation_with_attachments_deserialization() {
221+
let json = include_str!(
222+
"../../tests/wpcom/support_tickets/single-conversation-with-attachments.json"
223+
);
224+
let conversation: SupportConversation =
225+
serde_json::from_str(json).expect("Failed to deserialize support conversation");
226+
assert_eq!(conversation.messages.len(), 1);
227+
assert_eq!(conversation.messages[0].attachments.len(), 2);
228+
assert_eq!(
229+
conversation.messages[0].attachments[0].filename,
230+
"sample-image-1.jpg"
231+
);
232+
assert_eq!(
233+
conversation.messages[0].attachments[0].content_type,
234+
"image/jpeg"
235+
);
236+
assert_eq!(conversation.messages[0].attachments[0].size, 123456);
237+
assert_eq!(
238+
conversation.messages[0].attachments[0].url,
239+
"https://example.com/attachments/token/token1/?name=sample-image-1.jpg"
240+
);
241+
242+
let dimensions =
243+
get_attachment_dimensions(&conversation.messages[0].attachments[0]).unwrap();
244+
245+
assert_eq!(dimensions.width, 1000);
246+
assert_eq!(dimensions.height, 800);
247+
248+
assert_eq!(
249+
conversation.messages[0].attachments[1].filename,
250+
"sample-image-2.jpg"
251+
);
252+
assert_eq!(
253+
conversation.messages[0].attachments[1].content_type,
254+
"image/jpeg"
255+
);
256+
assert_eq!(conversation.messages[0].attachments[1].size, 654321);
257+
assert_eq!(
258+
conversation.messages[0].attachments[1].url,
259+
"https://example.com/attachments/token/token2/?name=sample-image-2.jpg"
260+
);
261+
262+
let dimensions =
263+
get_attachment_dimensions(&conversation.messages[0].attachments[1]).unwrap();
264+
assert_eq!(dimensions.width, 2000);
265+
assert_eq!(dimensions.height, 1600);
266+
}
267+
268+
#[test]
269+
fn test_attachment_metadata_key_custom_deserialization() {
270+
let json = r#"{"Custom": "test"}"#;
271+
let metadata: HashMap<AttachmentMetadataKey, AttachmentMetadataValue> =
272+
serde_json::from_str(json).expect("Failed to deserialize attachment metadata");
273+
assert_eq!(metadata.len(), 1);
274+
}
275+
276+
#[rstest]
277+
#[case(AttachmentMetadataKey::Width, "Width")]
278+
#[case(AttachmentMetadataKey::Height, "Height")]
279+
#[case(
280+
AttachmentMetadataKey::Custom(String::from("testlowercase")),
281+
"testlowercase"
282+
)]
283+
#[case(
284+
AttachmentMetadataKey::Custom(String::from("testWithCamelCase")),
285+
"testWithCamelCase"
286+
)]
287+
#[case(
288+
AttachmentMetadataKey::Custom(String::from("test_with_snake_case")),
289+
"test_with_snake_case"
290+
)]
291+
fn test_attachment_metadata_key_to_string(
292+
#[case] key: AttachmentMetadataKey,
293+
#[case] expected_str: &str,
294+
) {
295+
assert_eq!(key.to_string(), expected_str);
296+
}
170297
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"id": 10000001,
3+
"title": "Test Ticket",
4+
"description": "Redacted for privacy",
5+
"status": "new",
6+
"messages": [
7+
{
8+
"id": 20000001,
9+
"content": "Redacted for privacy",
10+
"role": "user",
11+
"author": {
12+
"id": 30000001,
13+
"name": "Test User",
14+
"email": "test.user@example.com"
15+
},
16+
"author_is_current_user": true,
17+
"created_at": "2025-10-27T21:30:43+00:00",
18+
"attachments": [
19+
{
20+
"id": 40000001,
21+
"filename": "sample-image-1.jpg",
22+
"content_type": "image/jpeg",
23+
"size": 123456,
24+
"url": "https://example.com/attachments/token/token1/?name=sample-image-1.jpg",
25+
"metadata": {
26+
"width": 1000,
27+
"height": 800
28+
}
29+
},
30+
{
31+
"id": 40000002,
32+
"filename": "sample-image-2.jpg",
33+
"content_type": "image/jpeg",
34+
"size": 654321,
35+
"url": "https://example.com/attachments/token/token2/?name=sample-image-2.jpg",
36+
"metadata": {
37+
"width": 2000,
38+
"height": 1600
39+
}
40+
}
41+
]
42+
}
43+
],
44+
"created_at": "2025-10-27T21:30:43+00:00",
45+
"updated_at": "2025-10-27T21:30:43+00:00"
46+
}

0 commit comments

Comments
 (0)