From 4a5d7d0e7a0a6b837b872df5ddc05de89cc79266 Mon Sep 17 00:00:00 2001 From: Doug Date: Fri, 4 Oct 2024 09:53:16 +0100 Subject: [PATCH] events: Add filename helper methods for audio, file, image and video messages. --- crates/ruma-events/CHANGELOG.md | 1 + crates/ruma-events/src/room/message/audio.rs | 13 ++++- crates/ruma-events/src/room/message/file.rs | 13 ++++- crates/ruma-events/src/room/message/image.rs | 13 ++++- crates/ruma-events/src/room/message/video.rs | 13 ++++- crates/ruma-events/tests/it/room_message.rs | 52 ++++++++++++++++++++ 6 files changed, 101 insertions(+), 4 deletions(-) diff --git a/crates/ruma-events/CHANGELOG.md b/crates/ruma-events/CHANGELOG.md index 48879d4a..03ae449f 100644 --- a/crates/ruma-events/CHANGELOG.md +++ b/crates/ruma-events/CHANGELOG.md @@ -24,6 +24,7 @@ The new format (Session) is required to reliably display the call member count ( - `CallMemberStateKey` (instead of `OwnedUserId`) is now used as the state key type for `CallMemberEventContent`. This guarantees correct formatting of the event key. - Add helpers for captions on audio, file, image and video messages. +- Add helpers for filenames on audio, file, image and video messages. Breaking changes: diff --git a/crates/ruma-events/src/room/message/audio.rs b/crates/ruma-events/src/room/message/audio.rs index 438e3f5d..9a194d77 100644 --- a/crates/ruma-events/src/room/message/audio.rs +++ b/crates/ruma-events/src/room/message/audio.rs @@ -27,7 +27,10 @@ pub struct AudioMessageEventContent { #[serde(flatten)] pub formatted: Option, - /// The original filename of the uploaded file. + /// The original filename of the uploaded file as deserialized from the event. + /// + /// It is recommended to use the `filename` method to get the filename which automatically + /// falls back to the `body` field when the `filename` field is not set. #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, @@ -92,6 +95,14 @@ impl AudioMessageEventContent { Self { info: info.into(), ..self } } + /// Computes the filename for the audio file as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). + /// + /// This differs from the `filename` field as this method falls back to the `body` field when + /// the `filename` field is not set. + pub fn filename(&self) -> &str { + self.filename.as_deref().unwrap_or(&self.body) + } + /// Returns the caption for the audio as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). /// /// In short, this is the `body` field if the `filename` field exists and has a different value, diff --git a/crates/ruma-events/src/room/message/file.rs b/crates/ruma-events/src/room/message/file.rs index 0edbc634..d3ee9723 100644 --- a/crates/ruma-events/src/room/message/file.rs +++ b/crates/ruma-events/src/room/message/file.rs @@ -25,7 +25,10 @@ pub struct FileMessageEventContent { #[serde(flatten)] pub formatted: Option, - /// The original filename of the uploaded file. + /// The original filename of the uploaded file as deserialized from the event. + /// + /// It is recommended to use the `filename` method to get the filename which automatically + /// falls back to the `body` field when the `filename` field is not set. #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, @@ -64,6 +67,14 @@ impl FileMessageEventContent { Self { info: info.into(), ..self } } + /// Computes the filename for the file as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). + /// + /// This differs from the `filename` field as this method falls back to the `body` field when + /// the `filename` field is not set. + pub fn filename(&self) -> &str { + self.filename.as_deref().unwrap_or(&self.body) + } + /// Returns the caption of the media file as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). /// /// In short, this is the `body` field if the `filename` field exists and has a different value, diff --git a/crates/ruma-events/src/room/message/image.rs b/crates/ruma-events/src/room/message/image.rs index 29e1c60c..70b6898b 100644 --- a/crates/ruma-events/src/room/message/image.rs +++ b/crates/ruma-events/src/room/message/image.rs @@ -24,7 +24,10 @@ pub struct ImageMessageEventContent { #[serde(flatten)] pub formatted: Option, - /// The original filename of the uploaded file. + /// The original filename of the uploaded file as deserialized from the event. + /// + /// It is recommended to use the `filename` method to get the filename which automatically + /// falls back to the `body` field when the `filename` field is not set. #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, @@ -63,6 +66,14 @@ impl ImageMessageEventContent { Self { info: info.into(), ..self } } + /// Computes the filename of the image as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). + /// + /// This differs from the `filename` field as this method falls back to the `body` field when + /// the `filename` field is not set. + pub fn filename(&self) -> &str { + self.filename.as_deref().unwrap_or(&self.body) + } + /// Returns the caption for the image as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). /// /// In short, this is the `body` field if the `filename` field exists and has a different value, diff --git a/crates/ruma-events/src/room/message/video.rs b/crates/ruma-events/src/room/message/video.rs index df8ac0c1..74a5b3b0 100644 --- a/crates/ruma-events/src/room/message/video.rs +++ b/crates/ruma-events/src/room/message/video.rs @@ -27,7 +27,10 @@ pub struct VideoMessageEventContent { #[serde(flatten)] pub formatted: Option, - /// The original filename of the uploaded file. + /// The original filename of the uploaded file as deserialized from the event. + /// + /// It is recommended to use the `filename` method to get the filename which automatically + /// falls back to the `body` field when the `filename` field is not set. #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, @@ -66,6 +69,14 @@ impl VideoMessageEventContent { Self { info: info.into(), ..self } } + /// Computes the filename of the video as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). + /// + /// This differs from the `filename` field as this method falls back to the `body` field when + /// the `filename` field is not set. + pub fn filename(&self) -> &str { + self.filename.as_deref().unwrap_or(&self.body) + } + /// Returns the caption of the video as defined by the [spec](https://spec.matrix.org/latest/client-server-api/#media-captions). /// /// In short, this is the `body` field if the `filename` field exists and has a different value, diff --git a/crates/ruma-events/tests/it/room_message.rs b/crates/ruma-events/tests/it/room_message.rs index 717f5685..febac08c 100644 --- a/crates/ruma-events/tests/it/room_message.rs +++ b/crates/ruma-events/tests/it/room_message.rs @@ -1335,6 +1335,19 @@ fn invalid_replacement() { assert_eq!(JsonValue::Object(data.into_owned()), relation); } +#[test] +fn test_audio_filename() { + let mut content = AudioMessageEventContent::plain( + "my_sound.ogg".to_owned(), + mxc_uri!("mxc://notareal.hs/abcdef").to_owned(), + ); + assert_eq!(content.filename(), "my_sound.ogg"); + + content.body = "This was a great podcast episode".to_owned(); + content.filename = Some("sound.ogg".to_owned()); + assert_eq!(content.filename(), "sound.ogg"); +} + #[test] fn test_audio_caption() { let mut content = AudioMessageEventContent::plain( @@ -1361,6 +1374,19 @@ fn test_audio_caption() { ); } +#[test] +fn test_file_filename() { + let mut content = FileMessageEventContent::plain( + "my_file.txt".to_owned(), + mxc_uri!("mxc://notareal.hs/abcdef").to_owned(), + ); + assert_eq!(content.filename(), "my_file.txt"); + + content.body = "Please check these notes".to_owned(); + content.filename = Some("notes.txt".to_owned()); + assert_eq!(content.filename(), "notes.txt"); +} + #[test] fn test_file_caption() { let mut content = FileMessageEventContent::plain( @@ -1387,6 +1413,19 @@ fn test_file_caption() { ); } +#[test] +fn test_image_filename() { + let mut content = ImageMessageEventContent::plain( + "my_image.jpg".to_owned(), + mxc_uri!("mxc://notareal.hs/abcdef").to_owned(), + ); + assert_eq!(content.filename(), "my_image.jpg"); + + content.body = "Check it out 😎".to_owned(); + content.filename = Some("image.jpg".to_owned()); + assert_eq!(content.filename(), "image.jpg"); +} + #[test] fn test_image_caption() { let mut content = ImageMessageEventContent::plain( @@ -1412,6 +1451,19 @@ fn test_image_caption() { ); } +#[test] +fn test_video_filename() { + let mut content = VideoMessageEventContent::plain( + "my_video.mp4".to_owned(), + mxc_uri!("mxc://notareal.hs/abcdef").to_owned(), + ); + assert_eq!(content.filename(), "my_video.mp4"); + + content.body = "You missed a great evening".to_owned(); + content.filename = Some("video.mp4".to_owned()); + assert_eq!(content.filename(), "video.mp4"); +} + #[test] fn test_video_caption() { let mut content = VideoMessageEventContent::plain(