ruma_events/
media_preview_config.rs

1//! Types for the [`m.media_preview_config`] event.
2//!
3//! [`m.media_preview_config`]: https://github.com/matrix-org/matrix-spec-proposals/pull/4278
4
5use ruma_common::serde::JsonCastable;
6use ruma_macros::StringEnum;
7use serde::{Deserialize, Serialize};
8
9use crate::{PrivOwnedStr, macros::EventContent};
10
11/// The content of an `m.media_preview_config` event.
12#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
13#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
14#[ruma_event(type = "m.media_preview_config", kind = GlobalAccountData + RoomAccountData)]
15pub struct MediaPreviewConfigEventContent {
16    /// The media previews configuration.
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub media_previews: Option<MediaPreviews>,
19
20    /// The invite avatars configuration.
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub invite_avatars: Option<InviteAvatars>,
23}
24
25impl JsonCastable<UnstableMediaPreviewConfigEventContent> for MediaPreviewConfigEventContent {}
26
27/// The content of an `io.element.msc4278.media_preview_config` event,
28/// the unstable version of `m.media_preview_config` in global account data.
29#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
30#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
31#[ruma_event(type = "io.element.msc4278.media_preview_config", kind = GlobalAccountData + RoomAccountData)]
32#[serde(transparent)]
33pub struct UnstableMediaPreviewConfigEventContent(pub MediaPreviewConfigEventContent);
34
35impl JsonCastable<MediaPreviewConfigEventContent> for UnstableMediaPreviewConfigEventContent {}
36
37/// The configuration that handles if media previews should be shown in the timeline.
38#[derive(Clone, StringEnum, Default)]
39#[ruma_enum(rename_all = "lowercase")]
40#[non_exhaustive]
41pub enum MediaPreviews {
42    /// Media previews should be hidden.
43    Off,
44
45    /// Media previews should be only shown in private rooms.
46    Private,
47
48    /// Media previews should always be shown.
49    #[default]
50    On,
51
52    #[doc(hidden)]
53    _Custom(PrivOwnedStr),
54}
55
56/// The configuration to handle if avatars should be shown in invites.
57#[derive(Clone, StringEnum, Default)]
58#[ruma_enum(rename_all = "lowercase")]
59#[non_exhaustive]
60pub enum InviteAvatars {
61    /// Avatars in invites should be hidden.
62    Off,
63
64    /// Avatars in invites should be shown.
65    #[default]
66    On,
67
68    #[doc(hidden)]
69    _Custom(PrivOwnedStr),
70}
71
72impl MediaPreviewConfigEventContent {
73    /// Create a new empty [`MediaPreviewConfigEventContent`].
74    pub fn new() -> Self {
75        Self::default()
76    }
77
78    /// Set the value of the setting for the media previews.
79    pub fn media_previews(mut self, media_previews: Option<MediaPreviews>) -> Self {
80        self.media_previews = media_previews;
81        self
82    }
83
84    /// Set the value of the setting for the media previews.
85    pub fn invite_avatars(mut self, invite_avatars: Option<InviteAvatars>) -> Self {
86        self.invite_avatars = invite_avatars;
87        self
88    }
89
90    /// Merge the config from the global account data with the config from the room account data.
91    ///
92    /// The values that are set in the room account data take precedence over the values in the
93    /// global account data.
94    pub fn merge_global_and_room_config(global_config: Self, room_config: Self) -> Self {
95        Self {
96            media_previews: room_config.media_previews.or(global_config.media_previews),
97            invite_avatars: room_config.invite_avatars.or(global_config.invite_avatars),
98        }
99    }
100}
101
102impl std::ops::Deref for UnstableMediaPreviewConfigEventContent {
103    type Target = MediaPreviewConfigEventContent;
104
105    fn deref(&self) -> &Self::Target {
106        &self.0
107    }
108}
109
110impl From<MediaPreviewConfigEventContent> for UnstableMediaPreviewConfigEventContent {
111    fn from(value: MediaPreviewConfigEventContent) -> Self {
112        Self(value)
113    }
114}
115
116impl From<UnstableMediaPreviewConfigEventContent> for MediaPreviewConfigEventContent {
117    fn from(value: UnstableMediaPreviewConfigEventContent) -> Self {
118        value.0
119    }
120}
121
122#[cfg(all(test, feature = "unstable-msc4278"))]
123mod tests {
124    use assert_matches2::assert_matches;
125    use ruma_common::canonical_json::assert_to_canonical_json_eq;
126    use serde_json::{from_value as from_json_value, json};
127
128    use super::{MediaPreviewConfigEventContent, UnstableMediaPreviewConfigEventContent};
129    use crate::{
130        AnyGlobalAccountDataEvent, GlobalAccountDataEvent,
131        media_preview_config::{InviteAvatars, MediaPreviews},
132    };
133
134    #[test]
135    fn deserialize() {
136        let raw_unstable_media_preview_config = json!({
137            "type": "io.element.msc4278.media_preview_config",
138            "content": {
139                "media_previews": "private",
140                "invite_avatars": "off",
141            },
142        });
143        let unstable_media_preview_config_data =
144            from_json_value::<AnyGlobalAccountDataEvent>(raw_unstable_media_preview_config)
145                .unwrap();
146        assert_matches!(
147            unstable_media_preview_config_data,
148            AnyGlobalAccountDataEvent::UnstableMediaPreviewConfig(unstable_media_preview_config)
149        );
150        assert_eq!(
151            unstable_media_preview_config.content.media_previews,
152            Some(MediaPreviews::Private)
153        );
154        assert_eq!(unstable_media_preview_config.content.invite_avatars, Some(InviteAvatars::Off));
155
156        let raw_media_preview_config = json!({
157            "type": "m.media_preview_config",
158            "content": {
159                "media_previews": "on",
160                "invite_avatars": "on",
161            },
162        });
163        let media_preview_config_data =
164            from_json_value::<AnyGlobalAccountDataEvent>(raw_media_preview_config).unwrap();
165        assert_matches!(
166            media_preview_config_data,
167            AnyGlobalAccountDataEvent::MediaPreviewConfig(media_preview_config)
168        );
169        assert_eq!(media_preview_config.content.media_previews, Some(MediaPreviews::On));
170        assert_eq!(media_preview_config.content.invite_avatars, Some(InviteAvatars::On));
171    }
172
173    #[test]
174    fn serialize() {
175        let unstable_media_preview_config = UnstableMediaPreviewConfigEventContent(
176            MediaPreviewConfigEventContent::new()
177                .media_previews(Some(MediaPreviews::Off))
178                .invite_avatars(Some(InviteAvatars::On)),
179        );
180        let unstable_media_preview_config_account_data =
181            GlobalAccountDataEvent { content: unstable_media_preview_config };
182        assert_to_canonical_json_eq!(
183            unstable_media_preview_config_account_data,
184            json!({
185                "type": "io.element.msc4278.media_preview_config",
186                "content": {
187                    "media_previews": "off",
188                    "invite_avatars": "on",
189                },
190            })
191        );
192
193        let media_preview_config = MediaPreviewConfigEventContent::new()
194            .media_previews(Some(MediaPreviews::On))
195            .invite_avatars(Some(InviteAvatars::Off));
196        let media_preview_config_account_data =
197            GlobalAccountDataEvent { content: media_preview_config };
198        assert_to_canonical_json_eq!(
199            media_preview_config_account_data,
200            json!({
201                "type": "m.media_preview_config",
202                "content": {
203                    "media_previews": "on",
204                    "invite_avatars": "off",
205                },
206            })
207        );
208    }
209}