events: Add relates_to field on StickerEventContent

This commit is contained in:
Neek 2024-10-15 17:29:36 +02:00 committed by strawberry
parent 5627c5109e
commit 1c4eeb4c41
3 changed files with 139 additions and 7 deletions

View File

@ -2,6 +2,7 @@
Bug fixes: Bug fixes:
- Fix missing `relates_to` field on `StickerEventContent`
- Fix deserialization of `AnyGlobalAccountDataEvent` for variants with a type - Fix deserialization of `AnyGlobalAccountDataEvent` for variants with a type
fragment. fragment.
- Fix serialization of `room::message::Relation` and `room::encrypted::Relation` - Fix serialization of `room::message::Relation` and `room::encrypted::Relation`

View File

@ -8,7 +8,7 @@ use serde::{de, Deserialize, Serialize};
#[cfg(feature = "compat-encrypted-stickers")] #[cfg(feature = "compat-encrypted-stickers")]
use crate::room::EncryptedFile; use crate::room::EncryptedFile;
use crate::room::{ImageInfo, MediaSource}; use crate::room::{message::Relation, ImageInfo, MediaSource};
/// The source of a sticker media file. /// The source of a sticker media file.
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
@ -81,7 +81,7 @@ impl From<MediaSource> for StickerMediaSource {
/// A sticker message. /// A sticker message.
#[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[ruma_event(type = "m.sticker", kind = MessageLike)] #[ruma_event(type = "m.sticker", kind = MessageLike, without_relation)]
pub struct StickerEventContent { pub struct StickerEventContent {
/// A textual representation or associated description of the sticker image. /// A textual representation or associated description of the sticker image.
/// ///
@ -95,16 +95,24 @@ pub struct StickerEventContent {
/// The media source of the sticker image. /// The media source of the sticker image.
#[serde(flatten)] #[serde(flatten)]
pub source: StickerMediaSource, pub source: StickerMediaSource,
/// Information about related messages.
#[serde(
flatten,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::room::message::relation_serde::deserialize_relation"
)]
pub relates_to: Option<Relation<StickerEventContentWithoutRelation>>,
} }
impl StickerEventContent { impl StickerEventContent {
/// Creates a new `StickerEventContent` with the given body, image info and URL. /// Creates a new `StickerEventContent` with the given body, image info and URL.
pub fn new(body: String, info: ImageInfo, url: OwnedMxcUri) -> Self { pub fn new(body: String, info: ImageInfo, url: OwnedMxcUri) -> Self {
Self { body, info, source: StickerMediaSource::Plain(url.clone()) } Self { body, info, source: StickerMediaSource::Plain(url.clone()), relates_to: None }
} }
/// Creates a new `StickerEventContent` with the given body, image info, URL, and media source. /// Creates a new `StickerEventContent` with the given body, image info, URL, and media source.
pub fn with_source(body: String, info: ImageInfo, source: StickerMediaSource) -> Self { pub fn with_source(body: String, info: ImageInfo, source: StickerMediaSource) -> Self {
Self { body, info, source } Self { body, info, source, relates_to: None }
} }
} }

View File

@ -1,10 +1,11 @@
use assert_matches2::assert_matches; use assert_matches2::assert_matches;
use assign::assign; use assign::assign;
use js_int::{uint, UInt}; use js_int::{uint, UInt};
use ruma_common::{mxc_uri, serde::CanBeEmpty, MilliSecondsSinceUnixEpoch}; use ruma_common::{mxc_uri, owned_event_id, serde::CanBeEmpty, MilliSecondsSinceUnixEpoch};
use ruma_events::{ use ruma_events::{
room::{ImageInfo, MediaSource, ThumbnailInfo}, relation::Replacement,
sticker::{StickerEventContent, StickerMediaSource}, room::{message::Relation, ImageInfo, MediaSource, ThumbnailInfo},
sticker::{StickerEventContent, StickerEventContentWithoutRelation, StickerMediaSource},
AnyMessageLikeEvent, MessageLikeEvent, AnyMessageLikeEvent, MessageLikeEvent,
}; };
use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
@ -27,6 +28,43 @@ fn content_serialization() {
); );
} }
#[test]
fn replace_content_serialization() {
let mut message_event_content = StickerEventContent::new(
"* Upload: my_image.jpg".to_owned(),
ImageInfo::new(),
mxc_uri!("mxc://notareal.hs/file").to_owned(),
);
let old_event_id = owned_event_id!("$15827405538098VGFWH:example.com");
let new_message_event_content = StickerEventContent::new(
"Upload: my_image.jpg".to_owned(),
ImageInfo::new(),
mxc_uri!("mxc://notareal.hs/file").to_owned(),
);
let new_content = StickerEventContentWithoutRelation::from(new_message_event_content);
let replacement = Replacement::new(old_event_id.clone(), new_content);
let relation = Relation::Replacement(replacement);
message_event_content.relates_to = Some(relation);
assert_eq!(
to_json_value(&message_event_content).unwrap(),
json!({
"body": "* Upload: my_image.jpg",
"url": "mxc://notareal.hs/file",
"info": {},
"m.new_content": {
"body": "Upload: my_image.jpg",
"url": "mxc://notareal.hs/file",
"info": {},
},
"m.relates_to": {
"rel_type": "m.replace",
"event_id": old_event_id,
}
})
);
}
#[test] #[test]
fn event_serialization() { fn event_serialization() {
let content = StickerEventContent::new( let content = StickerEventContent::new(
@ -119,6 +157,91 @@ fn content_deserialization() {
} }
} }
#[test]
fn replace_content_deserialization() {
let old_event_id = owned_event_id!("$15827405538098VGFWH:example.com");
let json_data = json!({
"body": "* Upload: my_image.jpg",
"url": "mxc://notareal.hs/file",
"info": {},
"m.new_content": {
"body": "Upload: my_image.jpg",
"url": "mxc://notareal.hs/file",
"info": {},
},
"m.relates_to": {
"rel_type": "m.replace",
"event_id": old_event_id,
}
});
let content = from_json_value::<StickerEventContent>(json_data).unwrap();
assert_eq!(content.body, "* Upload: my_image.jpg");
assert_matches!(content.source, StickerMediaSource::Plain(sticker_url));
assert_eq!(sticker_url, "mxc://notareal.hs/file");
assert_matches!(content.relates_to, Some(Relation::Replacement(replacement)));
assert_eq!(replacement.new_content.body, "Upload: my_image.jpg");
assert_matches!(replacement.new_content.source, StickerMediaSource::Plain(sticker_url));
assert_eq!(sticker_url, "mxc://notareal.hs/file");
let encrypted_json_data = json!({
"body": "* Upload: my_image.jpg",
"file": {
"url": "mxc://notareal.hs/file",
"key": {
"kty": "oct",
"key_ops": ["encrypt", "decrypt"],
"alg": "A256CTR",
"k": "TLlG_OpX807zzQuuwv4QZGJ21_u7weemFGYJFszMn9A",
"ext": true
},
"iv": "S22dq3NAX8wAAAAAAAAAAA",
"hashes": {
"sha256": "aWOHudBnDkJ9IwaR1Nd8XKoI7DOrqDTwt6xDPfVGN6Q"
},
"v": "v2",
},
"m.new_content": {
"body": "Upload: my_image.jpg",
"url": "mxc://notareal.hs/file",
"info": {},
},
"m.relates_to": {
"event_id": old_event_id,
"rel_type": "m.replace"
},
"info": {},
});
#[cfg(not(feature = "compat-encrypted-stickers"))]
{
from_json_value::<StickerEventContent>(encrypted_json_data).unwrap_err();
}
#[cfg(feature = "compat-encrypted-stickers")]
{
let encrypted_content =
from_json_value::<StickerEventContent>(encrypted_json_data).unwrap();
assert_eq!(encrypted_content.body, "Upload: my_image.jpg");
assert_matches!(
encrypted_content.source,
StickerMediaSource::Encrypted(encrypted_sticker_url)
);
assert_eq!(encrypted_sticker_url.url, "mxc://notareal.hs/file");
assert_matches!(
encrypted_content.relates_to,
Some(Relation::Replacement(encrypted_replacement))
);
assert_eq!(encrypted_replacement.new_content.body, "Upload: my_image.jpg");
assert_matches!(
encrypted_replacement.new_content.source,
StickerMediaSource::Plain(encrypted_sticker_url)
);
assert_eq!(encrypted_sticker_url, "mxc://notareal.hs/file");
}
}
#[test] #[test]
fn event_deserialization() { fn event_deserialization() {
let json_data = json!({ let json_data = json!({