Skip to content

Commit

Permalink
feat(send queue): allow setting intentional mentions in media caption…
Browse files Browse the repository at this point in the history
…s edits

Fixes #4302.
  • Loading branch information
bnjbvr committed Jan 7, 2025
1 parent 618e472 commit 8205da8
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 28 deletions.
24 changes: 18 additions & 6 deletions bindings/matrix-sdk-ffi/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ use crate::{
event::EventOrTransactionId,
helpers::unwrap_or_clone_arc,
ruma::{
AssetType, AudioInfo, FileInfo, FormattedBody, ImageInfo, PollKind, ThumbnailInfo,
VideoInfo,
AssetType, AudioInfo, FileInfo, FormattedBody, ImageInfo, Mentions, PollKind,
ThumbnailInfo, VideoInfo,
},
task_handle::TaskHandle,
utils::Timestamp,
Expand Down Expand Up @@ -1295,22 +1295,32 @@ impl From<ReceiptType> for ruma::api::client::receipt::create_receipt::v3::Recei

#[derive(Clone, uniffi::Enum)]
pub enum EditedContent {
RoomMessage { content: Arc<RoomMessageEventContentWithoutRelation> },
MediaCaption { caption: Option<String>, formatted_caption: Option<FormattedBody> },
PollStart { poll_data: PollData },
RoomMessage {
content: Arc<RoomMessageEventContentWithoutRelation>,
},
MediaCaption {
caption: Option<String>,
formatted_caption: Option<FormattedBody>,
mentions: Option<Mentions>,
},
PollStart {
poll_data: PollData,
},
}

impl TryFrom<EditedContent> for SdkEditedContent {
type Error = ClientError;

fn try_from(value: EditedContent) -> Result<Self, Self::Error> {
match value {
EditedContent::RoomMessage { content } => {
Ok(SdkEditedContent::RoomMessage((*content).clone()))
}
EditedContent::MediaCaption { caption, formatted_caption } => {
EditedContent::MediaCaption { caption, formatted_caption, mentions } => {
Ok(SdkEditedContent::MediaCaption {
caption,
formatted_caption: formatted_caption.map(Into::into),
mentions: mentions.map(Into::into),
})
}
EditedContent::PollStart { poll_data } => {
Expand All @@ -1332,12 +1342,14 @@ impl TryFrom<EditedContent> for SdkEditedContent {
fn create_caption_edit(
caption: Option<String>,
formatted_caption: Option<FormattedBody>,
mentions: Option<Mentions>,
) -> EditedContent {
let formatted_caption =
formatted_body_from(caption.as_deref(), formatted_caption.map(Into::into));
EditedContent::MediaCaption {
caption,
formatted_caption: formatted_caption.as_ref().map(Into::into),
mentions,
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/matrix-sdk-ui/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,9 @@ impl Timeline {
}
}

EditedContent::MediaCaption { caption, formatted_caption } => {
EditedContent::MediaCaption { caption, formatted_caption, mentions } => {
if handle
.edit_media_caption(caption, formatted_caption)
.edit_media_caption(caption, formatted_caption, mentions)
.await
.map_err(RoomSendQueueError::StorageError)?
{
Expand Down
120 changes: 108 additions & 12 deletions crates/matrix-sdk/src/room/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use ruma::{
RoomMessageEventContentWithoutRelation,
},
AnyMessageLikeEvent, AnyMessageLikeEventContent, AnySyncMessageLikeEvent,
AnySyncTimelineEvent, AnyTimelineEvent, MessageLikeEvent, OriginalMessageLikeEvent,
SyncMessageLikeEvent,
AnySyncTimelineEvent, AnyTimelineEvent, Mentions, MessageLikeEvent,
OriginalMessageLikeEvent, SyncMessageLikeEvent,
},
EventId, RoomId, UserId,
};
Expand All @@ -54,6 +54,10 @@ pub enum EditedContent {
///
/// Set to `None` to remove an existing formatted caption.
formatted_caption: Option<FormattedBody>,

/// New set of intentional mentions to be included in the edited
/// caption.
mentions: Option<Mentions>,
},

/// The content is a new poll start.
Expand Down Expand Up @@ -196,7 +200,7 @@ async fn make_edit_event<S: EventSource>(
Ok(replacement.into())
}

EditedContent::MediaCaption { caption, formatted_caption } => {
EditedContent::MediaCaption { caption, formatted_caption, mentions } => {
// Handle edits of m.room.message.
let AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original(original)) =
message_like_event
Expand All @@ -207,21 +211,21 @@ async fn make_edit_event<S: EventSource>(
});
};

let mentions = original.content.mentions.clone();
let original_mentions = original.content.mentions.clone();
let replied_to_original_room_msg =
extract_replied_to(source, room_id, original.content.relates_to.clone()).await;

let mut prev_content = original.content;

if !update_media_caption(&mut prev_content, caption, formatted_caption) {
if !update_media_caption(&mut prev_content, caption, formatted_caption, mentions) {
return Err(EditError::IncompatibleEditType {
target: prev_content.msgtype.msgtype().to_owned(),
new_content: "caption for a media room message",
});
}

let replacement = prev_content.make_replacement(
ReplacementMetadata::new(event_id.to_owned(), mentions),
ReplacementMetadata::new(event_id.to_owned(), original_mentions),
replied_to_original_room_msg.as_ref(),
);

Expand Down Expand Up @@ -282,7 +286,10 @@ pub(crate) fn update_media_caption(
content: &mut RoomMessageEventContent,
caption: Option<String>,
formatted_caption: Option<FormattedBody>,
mentions: Option<Mentions>,
) -> bool {
content.mentions = mentions;

match &mut content.msgtype {
MessageType::Audio(event) => {
set_caption!(event, caption);
Expand Down Expand Up @@ -358,9 +365,9 @@ mod tests {
event_id,
events::{
room::message::{MessageType, Relation, RoomMessageEventContentWithoutRelation},
AnyMessageLikeEventContent, AnySyncTimelineEvent,
AnyMessageLikeEventContent, AnySyncTimelineEvent, Mentions,
},
owned_mxc_uri, room_id,
owned_mxc_uri, owned_user_id, room_id,
serde::Raw,
user_id, EventId, OwnedEventId,
};
Expand Down Expand Up @@ -506,7 +513,11 @@ mod tests {
room_id,
own_user_id,
event_id,
EditedContent::MediaCaption { caption: Some("yo".to_owned()), formatted_caption: None },
EditedContent::MediaCaption {
caption: Some("yo".to_owned()),
formatted_caption: None,
mentions: None,
},
)
.await
.unwrap_err();
Expand Down Expand Up @@ -543,6 +554,7 @@ mod tests {
EditedContent::MediaCaption {
caption: Some("Best joke ever".to_owned()),
formatted_caption: None,
mentions: None,
},
)
.await
Expand Down Expand Up @@ -572,12 +584,12 @@ mod tests {
let mut cache = TestEventCache::default();
let f = EventFactory::new();

let event: SyncTimelineEvent = f
let event = f
.image(filename.to_owned(), owned_mxc_uri!("mxc://sdk.rs/rickroll"))
.caption(Some("caption".to_owned()), None)
.event_id(event_id)
.sender(own_user_id)
.into();
.into_sync();

{
// Sanity checks.
Expand All @@ -602,7 +614,7 @@ mod tests {
own_user_id,
event_id,
// Remove the caption by setting it to None.
EditedContent::MediaCaption { caption: None, formatted_caption: None },
EditedContent::MediaCaption { caption: None, formatted_caption: None, mentions: None },
)
.await
.unwrap();
Expand All @@ -621,6 +633,90 @@ mod tests {
assert!(new_image.formatted_caption().is_none());
}

#[async_test]
async fn test_add_media_caption_mention() {
let event_id = event_id!("$1");
let own_user_id = user_id!("@me:saucisse.bzh");

let filename = "rickroll.gif";

let mut cache = TestEventCache::default();
let f = EventFactory::new();

// Start with a media event that has no mentions.
let event = f
.image(filename.to_owned(), owned_mxc_uri!("mxc://sdk.rs/rickroll"))
.event_id(event_id)
.sender(own_user_id)
.into_sync();

{
// Sanity checks.
let event = event.raw().deserialize().unwrap();
assert_let!(AnySyncTimelineEvent::MessageLike(event) = event);
assert_let!(
AnyMessageLikeEventContent::RoomMessage(msg) = event.original_content().unwrap()
);
assert_matches!(msg.mentions, None);
}

cache.events.insert(event_id.to_owned(), event);

let room_id = room_id!("!galette:saucisse.bzh");

// Add an intentional mention in the caption.
let mentioned_user_id = owned_user_id!("@crepe:saucisse.bzh");
let edit_event = {
let mentions = Mentions::with_user_ids([mentioned_user_id.clone()]);
make_edit_event(
cache,
room_id,
own_user_id,
event_id,
EditedContent::MediaCaption {
caption: None,
formatted_caption: None,
mentions: Some(mentions),
},
)
.await
.unwrap()
};

assert_let!(AnyMessageLikeEventContent::RoomMessage(msg) = edit_event);
assert_let!(MessageType::Image(image) = msg.msgtype);

assert!(image.caption().is_none());
assert!(image.formatted_caption().is_none());

// The raw event doesn't contain the mention :(
// TODO: this is a bug in Ruma! When Ruma gets upgraded in the SDK, this test
// may start failing. In this case, remove the following code, and replace it
// with the commented code below.

assert_matches!(msg.mentions, None);

/*
// The raw event contains the mention.
assert_let!(Some(mentions) = msg.mentions);
assert!(!mentions.room);
assert_eq!(
mentions.user_ids.into_iter().collect::<Vec<_>>(),
vec![mentioned_user_id.clone()]
);
*/

assert_let!(Some(Relation::Replacement(repl)) = msg.relates_to);
assert_let!(MessageType::Image(new_image) = repl.new_content.msgtype);
assert!(new_image.caption().is_none());
assert!(new_image.formatted_caption().is_none());

// The replacement contains the mention.
assert_let!(Some(mentions) = repl.new_content.mentions);
assert!(!mentions.room);
assert_eq!(mentions.user_ids.into_iter().collect::<Vec<_>>(), vec![mentioned_user_id]);
}

#[async_test]
async fn test_make_edit_event_success_with_response() {
let event_id = event_id!("$1");
Expand Down
5 changes: 3 additions & 2 deletions crates/matrix-sdk/src/send_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ use ruma::{
message::{FormattedBody, RoomMessageEventContent},
MediaSource,
},
AnyMessageLikeEventContent, EventContent as _,
AnyMessageLikeEventContent, EventContent as _, Mentions,
},
serde::Raw,
OwnedEventId, OwnedRoomId, OwnedTransactionId, TransactionId,
Expand Down Expand Up @@ -1995,12 +1995,13 @@ impl SendHandle {
&self,
caption: Option<String>,
formatted_caption: Option<FormattedBody>,
mentions: Option<Mentions>,
) -> Result<bool, RoomSendQueueStorageError> {
if let Some(new_content) = self
.room
.inner
.queue
.edit_media_caption(&self.transaction_id, caption, formatted_caption)
.edit_media_caption(&self.transaction_id, caption, formatted_caption, mentions)
.await?
{
trace!("successful edit of media caption");
Expand Down
7 changes: 4 additions & 3 deletions crates/matrix-sdk/src/send_queue/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use mime::Mime;
use ruma::{
events::{
room::message::{FormattedBody, MessageType, RoomMessageEventContent},
AnyMessageLikeEventContent,
AnyMessageLikeEventContent, Mentions,
},
OwnedTransactionId, TransactionId,
};
Expand Down Expand Up @@ -489,6 +489,7 @@ impl QueueStorage {
txn: &TransactionId,
caption: Option<String>,
formatted_caption: Option<FormattedBody>,
mentions: Option<Mentions>,
) -> Result<Option<AnyMessageLikeEventContent>, RoomSendQueueStorageError> {
// This error will be popular here.
use RoomSendQueueStorageError::InvalidMediaCaptionEdit;
Expand Down Expand Up @@ -523,7 +524,7 @@ impl QueueStorage {
return Err(InvalidMediaCaptionEdit);
};

if !update_media_caption(&mut local_echo, caption, formatted_caption) {
if !update_media_caption(&mut local_echo, caption, formatted_caption, mentions) {
return Err(InvalidMediaCaptionEdit);
}

Expand Down Expand Up @@ -562,7 +563,7 @@ impl QueueStorage {
return Err(InvalidMediaCaptionEdit);
};

if !update_media_caption(&mut content, caption, formatted_caption) {
if !update_media_caption(&mut content, caption, formatted_caption, mentions) {
return Err(InvalidMediaCaptionEdit);
}

Expand Down
Loading

0 comments on commit 8205da8

Please sign in to comment.