ruma_events/room/
power_levels.rs

1//! Types for the [`m.room.power_levels`] event.
2//!
3//! [`m.room.power_levels`]: https://spec.matrix.org/latest/client-server-api/#mroompower_levels
4
5use std::{cmp::max, collections::BTreeMap};
6
7use js_int::{int, Int};
8use ruma_common::{
9    power_levels::{default_power_level, NotificationPowerLevels},
10    push::PushConditionPowerLevelsCtx,
11    room_version_rules::RedactionRules,
12    OwnedUserId, UserId,
13};
14use ruma_macros::EventContent;
15use serde::{Deserialize, Serialize};
16
17use crate::{
18    EmptyStateKey, EventContent, MessageLikeEventType, RedactContent, RedactedStateEventContent,
19    StateEventType, StaticEventContent, TimelineEventType,
20};
21
22/// The content of an `m.room.power_levels` event.
23///
24/// Defines the power levels (privileges) of users in the room.
25#[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
26#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
27#[ruma_event(type = "m.room.power_levels", kind = State, state_key_type = EmptyStateKey, custom_redacted)]
28pub struct RoomPowerLevelsEventContent {
29    /// The level required to ban a user.
30    #[serde(
31        default = "default_power_level",
32        skip_serializing_if = "is_default_power_level",
33        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
34    )]
35    pub ban: Int,
36
37    /// The level required to send specific event types.
38    ///
39    /// This is a mapping from event type to power level required.
40    #[serde(
41        default,
42        skip_serializing_if = "BTreeMap::is_empty",
43        deserialize_with = "ruma_common::serde::btreemap_deserialize_v1_powerlevel_values"
44    )]
45    pub events: BTreeMap<TimelineEventType, Int>,
46
47    /// The default level required to send message events.
48    #[serde(
49        default,
50        skip_serializing_if = "ruma_common::serde::is_default",
51        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
52    )]
53    pub events_default: Int,
54
55    /// The level required to invite a user.
56    #[serde(
57        default,
58        skip_serializing_if = "ruma_common::serde::is_default",
59        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
60    )]
61    pub invite: Int,
62
63    /// The level required to kick a user.
64    #[serde(
65        default = "default_power_level",
66        skip_serializing_if = "is_default_power_level",
67        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
68    )]
69    pub kick: Int,
70
71    /// The level required to redact an event.
72    #[serde(
73        default = "default_power_level",
74        skip_serializing_if = "is_default_power_level",
75        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
76    )]
77    pub redact: Int,
78
79    /// The default level required to send state events.
80    #[serde(
81        default = "default_power_level",
82        skip_serializing_if = "is_default_power_level",
83        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
84    )]
85    pub state_default: Int,
86
87    /// The power levels for specific users.
88    ///
89    /// This is a mapping from `user_id` to power level for that user.
90    #[serde(
91        default,
92        skip_serializing_if = "BTreeMap::is_empty",
93        deserialize_with = "ruma_common::serde::btreemap_deserialize_v1_powerlevel_values"
94    )]
95    pub users: BTreeMap<OwnedUserId, Int>,
96
97    /// The default power level for every user in the room.
98    #[serde(
99        default,
100        skip_serializing_if = "ruma_common::serde::is_default",
101        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
102    )]
103    pub users_default: Int,
104
105    /// The power level requirements for specific notification types.
106    ///
107    /// This is a mapping from `key` to power level for that notifications key.
108    #[serde(default, skip_serializing_if = "NotificationPowerLevels::is_default")]
109    pub notifications: NotificationPowerLevels,
110}
111
112impl RoomPowerLevelsEventContent {
113    /// Creates a new `RoomPowerLevelsEventContent` with all-default values.
114    pub fn new() -> Self {
115        // events_default, users_default and invite having a default of 0 while the others have a
116        // default of 50 is not an oversight, these defaults are from the Matrix specification.
117        Self {
118            ban: default_power_level(),
119            events: BTreeMap::new(),
120            events_default: int!(0),
121            invite: int!(0),
122            kick: default_power_level(),
123            redact: default_power_level(),
124            state_default: default_power_level(),
125            users: BTreeMap::new(),
126            users_default: int!(0),
127            notifications: NotificationPowerLevels::default(),
128        }
129    }
130}
131
132impl Default for RoomPowerLevelsEventContent {
133    fn default() -> Self {
134        Self::new()
135    }
136}
137
138impl RedactContent for RoomPowerLevelsEventContent {
139    type Redacted = RedactedRoomPowerLevelsEventContent;
140
141    fn redact(self, rules: &RedactionRules) -> Self::Redacted {
142        let Self {
143            ban,
144            events,
145            events_default,
146            invite,
147            kick,
148            redact,
149            state_default,
150            users,
151            users_default,
152            ..
153        } = self;
154
155        let invite = if rules.keep_room_power_levels_invite { invite } else { int!(0) };
156
157        RedactedRoomPowerLevelsEventContent {
158            ban,
159            events,
160            events_default,
161            invite,
162            kick,
163            redact,
164            state_default,
165            users,
166            users_default,
167        }
168    }
169}
170
171/// Used with `#[serde(skip_serializing_if)]` to omit default power levels.
172#[allow(clippy::trivially_copy_pass_by_ref)]
173fn is_default_power_level(l: &Int) -> bool {
174    *l == int!(50)
175}
176
177impl RoomPowerLevelsEvent {
178    /// Obtain the effective power levels, regardless of whether this event is redacted.
179    pub fn power_levels(&self) -> RoomPowerLevels {
180        match self {
181            Self::Original(ev) => ev.content.clone().into(),
182            Self::Redacted(ev) => ev.content.clone().into(),
183        }
184    }
185}
186
187impl SyncRoomPowerLevelsEvent {
188    /// Obtain the effective power levels, regardless of whether this event is redacted.
189    pub fn power_levels(&self) -> RoomPowerLevels {
190        match self {
191            Self::Original(ev) => ev.content.clone().into(),
192            Self::Redacted(ev) => ev.content.clone().into(),
193        }
194    }
195}
196
197impl StrippedRoomPowerLevelsEvent {
198    /// Obtain the effective power levels from this event.
199    pub fn power_levels(&self) -> RoomPowerLevels {
200        self.content.clone().into()
201    }
202}
203
204/// Redacted form of [`RoomPowerLevelsEventContent`].
205#[derive(Clone, Debug, Deserialize, Serialize)]
206#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
207pub struct RedactedRoomPowerLevelsEventContent {
208    /// The level required to ban a user.
209    #[serde(
210        default = "default_power_level",
211        skip_serializing_if = "is_default_power_level",
212        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
213    )]
214    pub ban: Int,
215
216    /// The level required to send specific event types.
217    ///
218    /// This is a mapping from event type to power level required.
219    #[serde(
220        default,
221        skip_serializing_if = "BTreeMap::is_empty",
222        deserialize_with = "ruma_common::serde::btreemap_deserialize_v1_powerlevel_values"
223    )]
224    pub events: BTreeMap<TimelineEventType, Int>,
225
226    /// The default level required to send message events.
227    #[serde(
228        default,
229        skip_serializing_if = "ruma_common::serde::is_default",
230        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
231    )]
232    pub events_default: Int,
233
234    /// The level required to invite a user.
235    ///
236    /// This field was redacted in room versions 1 through 10. Starting from room version 11 it is
237    /// preserved.
238    #[serde(
239        default,
240        skip_serializing_if = "ruma_common::serde::is_default",
241        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
242    )]
243    pub invite: Int,
244
245    /// The level required to kick a user.
246    #[serde(
247        default = "default_power_level",
248        skip_serializing_if = "is_default_power_level",
249        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
250    )]
251    pub kick: Int,
252
253    /// The level required to redact an event.
254    #[serde(
255        default = "default_power_level",
256        skip_serializing_if = "is_default_power_level",
257        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
258    )]
259    pub redact: Int,
260
261    /// The default level required to send state events.
262    #[serde(
263        default = "default_power_level",
264        skip_serializing_if = "is_default_power_level",
265        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
266    )]
267    pub state_default: Int,
268
269    /// The power levels for specific users.
270    ///
271    /// This is a mapping from `user_id` to power level for that user.
272    #[serde(
273        default,
274        skip_serializing_if = "BTreeMap::is_empty",
275        deserialize_with = "ruma_common::serde::btreemap_deserialize_v1_powerlevel_values"
276    )]
277    pub users: BTreeMap<OwnedUserId, Int>,
278
279    /// The default power level for every user in the room.
280    #[serde(
281        default,
282        skip_serializing_if = "ruma_common::serde::is_default",
283        deserialize_with = "ruma_common::serde::deserialize_v1_powerlevel"
284    )]
285    pub users_default: Int,
286}
287
288impl EventContent for RedactedRoomPowerLevelsEventContent {
289    type EventType = StateEventType;
290
291    fn event_type(&self) -> Self::EventType {
292        StateEventType::RoomPowerLevels
293    }
294}
295
296impl StaticEventContent for RedactedRoomPowerLevelsEventContent {
297    const TYPE: &'static str = "m.room.power_levels";
298}
299
300impl RedactedStateEventContent for RedactedRoomPowerLevelsEventContent {
301    type StateKey = EmptyStateKey;
302}
303
304/// The effective power levels of a room.
305///
306/// This struct contains the same fields as [`RoomPowerLevelsEventContent`] and be created from that
307/// using a `From` trait implementation, but it is also implements
308/// `From<`[`RedactedRoomPowerLevelsEventContent`]`>`, so can be used when wanting to inspect the
309/// power levels of a room, regardless of whether the most recent power-levels event is redacted or
310/// not.
311#[derive(Clone, Debug)]
312#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
313pub struct RoomPowerLevels {
314    /// The level required to ban a user.
315    pub ban: Int,
316
317    /// The level required to send specific event types.
318    ///
319    /// This is a mapping from event type to power level required.
320    pub events: BTreeMap<TimelineEventType, Int>,
321
322    /// The default level required to send message events.
323    pub events_default: Int,
324
325    /// The level required to invite a user.
326    pub invite: Int,
327
328    /// The level required to kick a user.
329    pub kick: Int,
330
331    /// The level required to redact an event.
332    pub redact: Int,
333
334    /// The default level required to send state events.
335    pub state_default: Int,
336
337    /// The power levels for specific users.
338    ///
339    /// This is a mapping from `user_id` to power level for that user.
340    pub users: BTreeMap<OwnedUserId, Int>,
341
342    /// The default power level for every user in the room.
343    pub users_default: Int,
344
345    /// The power level requirements for specific notification types.
346    ///
347    /// This is a mapping from `key` to power level for that notifications key.
348    pub notifications: NotificationPowerLevels,
349}
350
351impl RoomPowerLevels {
352    /// Get the power level of a specific user.
353    pub fn for_user(&self, user_id: &UserId) -> Int {
354        self.users.get(user_id).map_or(self.users_default, |pl| *pl)
355    }
356
357    /// Get the power level required to perform a given action.
358    pub fn for_action(&self, action: PowerLevelAction) -> Int {
359        match action {
360            PowerLevelAction::Ban => self.ban,
361            PowerLevelAction::Unban => self.ban.max(self.kick),
362            PowerLevelAction::Invite => self.invite,
363            PowerLevelAction::Kick => self.kick,
364            PowerLevelAction::RedactOwn => self.for_message(MessageLikeEventType::RoomRedaction),
365            PowerLevelAction::RedactOther => {
366                self.redact.max(self.for_message(MessageLikeEventType::RoomRedaction))
367            }
368            PowerLevelAction::SendMessage(msg_type) => self.for_message(msg_type),
369            PowerLevelAction::SendState(state_type) => self.for_state(state_type),
370            PowerLevelAction::TriggerNotification(NotificationPowerLevelType::Room) => {
371                self.notifications.room
372            }
373        }
374    }
375
376    /// Get the power level required to send the given message type.
377    pub fn for_message(&self, msg_type: MessageLikeEventType) -> Int {
378        self.events.get(&msg_type.into()).copied().unwrap_or(self.events_default)
379    }
380
381    /// Get the power level required to send the given state event type.
382    pub fn for_state(&self, state_type: StateEventType) -> Int {
383        self.events.get(&state_type.into()).copied().unwrap_or(self.state_default)
384    }
385
386    /// Whether the given user can ban other users based on the power levels.
387    ///
388    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::Ban)`.
389    pub fn user_can_ban(&self, user_id: &UserId) -> bool {
390        self.for_user(user_id) >= self.ban
391    }
392
393    /// Whether the acting user can ban the target user based on the power levels.
394    ///
395    /// On top of `power_levels.user_can_ban(acting_user_id)`, this performs an extra check
396    /// to make sure the acting user has at greater power level than the target user.
397    ///
398    /// Shorthand for `power_levels.user_can_do_to_user(acting_user_id, target_user_id,
399    /// PowerLevelUserAction::Ban)`.
400    pub fn user_can_ban_user(&self, acting_user_id: &UserId, target_user_id: &UserId) -> bool {
401        let acting_pl = self.for_user(acting_user_id);
402        let target_pl = self.for_user(target_user_id);
403        acting_pl >= self.ban && target_pl < acting_pl
404    }
405
406    /// Whether the given user can unban other users based on the power levels.
407    ///
408    /// This action requires to be allowed to ban and to kick.
409    ///
410    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::Unban)`.
411    pub fn user_can_unban(&self, user_id: &UserId) -> bool {
412        let pl = self.for_user(user_id);
413        pl >= self.ban && pl >= self.kick
414    }
415
416    /// Whether the acting user can unban the target user based on the power levels.
417    ///
418    /// This action requires to be allowed to ban and to kick.
419    ///
420    /// On top of `power_levels.user_can_unban(acting_user_id)`, this performs an extra check
421    /// to make sure the acting user has at greater power level than the target user.
422    ///
423    /// Shorthand for `power_levels.user_can_do_to_user(acting_user_id, target_user_id,
424    /// PowerLevelUserAction::Unban)`.
425    pub fn user_can_unban_user(&self, acting_user_id: &UserId, target_user_id: &UserId) -> bool {
426        let acting_pl = self.for_user(acting_user_id);
427        let target_pl = self.for_user(target_user_id);
428        acting_pl >= self.ban && acting_pl >= self.kick && target_pl < acting_pl
429    }
430
431    /// Whether the given user can invite other users based on the power levels.
432    ///
433    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::Invite)`.
434    pub fn user_can_invite(&self, user_id: &UserId) -> bool {
435        self.for_user(user_id) >= self.invite
436    }
437
438    /// Whether the given user can kick other users based on the power levels.
439    ///
440    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::Kick)`.
441    pub fn user_can_kick(&self, user_id: &UserId) -> bool {
442        self.for_user(user_id) >= self.kick
443    }
444
445    /// Whether the acting user can kick the target user based on the power levels.
446    ///
447    /// On top of `power_levels.user_can_kick(acting_user_id)`, this performs an extra check
448    /// to make sure the acting user has at least the same power level as the target user.
449    ///
450    /// Shorthand for `power_levels.user_can_do_to_user(acting_user_id, target_user_id,
451    /// PowerLevelUserAction::Kick)`.
452    pub fn user_can_kick_user(&self, acting_user_id: &UserId, target_user_id: &UserId) -> bool {
453        let acting_pl = self.for_user(acting_user_id);
454        let target_pl = self.for_user(target_user_id);
455        acting_pl >= self.kick && target_pl < acting_pl
456    }
457
458    /// Whether the given user can redact their own events based on the power levels.
459    ///
460    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::RedactOwn)`.
461    pub fn user_can_redact_own_event(&self, user_id: &UserId) -> bool {
462        self.user_can_send_message(user_id, MessageLikeEventType::RoomRedaction)
463    }
464
465    /// Whether the given user can redact events of other users based on the power levels.
466    ///
467    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::RedactOthers)`.
468    pub fn user_can_redact_event_of_other(&self, user_id: &UserId) -> bool {
469        self.user_can_redact_own_event(user_id) && self.for_user(user_id) >= self.redact
470    }
471
472    /// Whether the given user can send message events based on the power levels.
473    ///
474    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::SendMessage(msg_type))`.
475    pub fn user_can_send_message(&self, user_id: &UserId, msg_type: MessageLikeEventType) -> bool {
476        self.for_user(user_id) >= self.for_message(msg_type)
477    }
478
479    /// Whether the given user can send state events based on the power levels.
480    ///
481    /// Shorthand for `power_levels.user_can_do(user_id, PowerLevelAction::SendState(state_type))`.
482    pub fn user_can_send_state(&self, user_id: &UserId, state_type: StateEventType) -> bool {
483        self.for_user(user_id) >= self.for_state(state_type)
484    }
485
486    /// Whether the given user can notify everybody in the room by writing `@room` in a message.
487    ///
488    /// Shorthand for `power_levels.user_can_do(user_id,
489    /// PowerLevelAction::TriggerNotification(NotificationPowerLevelType::Room))`.
490    pub fn user_can_trigger_room_notification(&self, user_id: &UserId) -> bool {
491        self.for_user(user_id) >= self.notifications.room
492    }
493
494    /// Whether the acting user can change the power level of the target user.
495    ///
496    /// Shorthand for `power_levels.user_can_do_to_user(acting_user_id, target_user_id,
497    /// PowerLevelUserAction::ChangePowerLevel`.
498    pub fn user_can_change_user_power_level(
499        &self,
500        acting_user_id: &UserId,
501        target_user_id: &UserId,
502    ) -> bool {
503        // Check that the user can change the power levels first.
504        if !self.user_can_send_state(acting_user_id, StateEventType::RoomPowerLevels) {
505            return false;
506        }
507
508        // A user can change their own power level.
509        if acting_user_id == target_user_id {
510            return true;
511        }
512
513        // The permission is different whether the target user is added or changed/removed, so
514        // we need to check that.
515        if let Some(target_pl) = self.users.get(target_user_id).copied() {
516            self.for_user(acting_user_id) > target_pl
517        } else {
518            true
519        }
520    }
521
522    /// Whether the given user can do the given action based on the power levels.
523    pub fn user_can_do(&self, user_id: &UserId, action: PowerLevelAction) -> bool {
524        match action {
525            PowerLevelAction::Ban => self.user_can_ban(user_id),
526            PowerLevelAction::Unban => self.user_can_unban(user_id),
527            PowerLevelAction::Invite => self.user_can_invite(user_id),
528            PowerLevelAction::Kick => self.user_can_kick(user_id),
529            PowerLevelAction::RedactOwn => self.user_can_redact_own_event(user_id),
530            PowerLevelAction::RedactOther => self.user_can_redact_event_of_other(user_id),
531            PowerLevelAction::SendMessage(message_type) => {
532                self.user_can_send_message(user_id, message_type)
533            }
534            PowerLevelAction::SendState(state_type) => {
535                self.user_can_send_state(user_id, state_type)
536            }
537            PowerLevelAction::TriggerNotification(NotificationPowerLevelType::Room) => {
538                self.user_can_trigger_room_notification(user_id)
539            }
540        }
541    }
542
543    /// Whether the acting user can do the given action to the target user based on the power
544    /// levels.
545    pub fn user_can_do_to_user(
546        &self,
547        acting_user_id: &UserId,
548        target_user_id: &UserId,
549        action: PowerLevelUserAction,
550    ) -> bool {
551        match action {
552            PowerLevelUserAction::Ban => self.user_can_ban_user(acting_user_id, target_user_id),
553            PowerLevelUserAction::Unban => self.user_can_unban_user(acting_user_id, target_user_id),
554            PowerLevelUserAction::Invite => self.user_can_invite(acting_user_id),
555            PowerLevelUserAction::Kick => self.user_can_kick_user(acting_user_id, target_user_id),
556            PowerLevelUserAction::ChangePowerLevel => {
557                self.user_can_change_user_power_level(acting_user_id, target_user_id)
558            }
559        }
560    }
561
562    /// Get the maximum power level of any user.
563    pub fn max(&self) -> Int {
564        self.users.values().fold(self.users_default, |max_pl, user_pl| max(max_pl, *user_pl))
565    }
566}
567
568impl From<RoomPowerLevelsEventContent> for RoomPowerLevels {
569    fn from(c: RoomPowerLevelsEventContent) -> Self {
570        Self {
571            ban: c.ban,
572            events: c.events,
573            events_default: c.events_default,
574            invite: c.invite,
575            kick: c.kick,
576            redact: c.redact,
577            state_default: c.state_default,
578            users: c.users,
579            users_default: c.users_default,
580            notifications: c.notifications,
581        }
582    }
583}
584
585impl From<RedactedRoomPowerLevelsEventContent> for RoomPowerLevels {
586    fn from(c: RedactedRoomPowerLevelsEventContent) -> Self {
587        Self {
588            ban: c.ban,
589            events: c.events,
590            events_default: c.events_default,
591            invite: c.invite,
592            kick: c.kick,
593            redact: c.redact,
594            state_default: c.state_default,
595            users: c.users,
596            users_default: c.users_default,
597            notifications: NotificationPowerLevels::default(),
598        }
599    }
600}
601
602impl From<RoomPowerLevels> for RoomPowerLevelsEventContent {
603    fn from(c: RoomPowerLevels) -> Self {
604        Self {
605            ban: c.ban,
606            events: c.events,
607            events_default: c.events_default,
608            invite: c.invite,
609            kick: c.kick,
610            redact: c.redact,
611            state_default: c.state_default,
612            users: c.users,
613            users_default: c.users_default,
614            notifications: c.notifications,
615        }
616    }
617}
618
619impl From<RoomPowerLevels> for PushConditionPowerLevelsCtx {
620    fn from(c: RoomPowerLevels) -> Self {
621        Self { users: c.users, users_default: c.users_default, notifications: c.notifications }
622    }
623}
624
625/// The actions that can be limited by power levels.
626#[derive(Clone, Debug, PartialEq, Eq)]
627#[non_exhaustive]
628pub enum PowerLevelAction {
629    /// Ban a user.
630    Ban,
631
632    /// Unban a user.
633    Unban,
634
635    /// Invite a user.
636    Invite,
637
638    /// Kick a user.
639    Kick,
640
641    /// Redact one's own event.
642    RedactOwn,
643
644    /// Redact the event of another user.
645    RedactOther,
646
647    /// Send a message-like event.
648    SendMessage(MessageLikeEventType),
649
650    /// Send a state event.
651    SendState(StateEventType),
652
653    /// Trigger a notification.
654    TriggerNotification(NotificationPowerLevelType),
655}
656
657/// The notification types that can be limited by power levels.
658#[derive(Clone, Debug, PartialEq, Eq)]
659#[non_exhaustive]
660pub enum NotificationPowerLevelType {
661    /// `@room` notifications.
662    Room,
663}
664
665/// The actions to other users that can be limited by power levels.
666#[derive(Clone, Debug, PartialEq, Eq)]
667#[non_exhaustive]
668pub enum PowerLevelUserAction {
669    /// Ban a user.
670    Ban,
671
672    /// Unban a user.
673    Unban,
674
675    /// Invite a user.
676    Invite,
677
678    /// Kick a user.
679    Kick,
680
681    /// Change a user's power level.
682    ChangePowerLevel,
683}
684
685#[cfg(test)]
686mod tests {
687    use std::collections::BTreeMap;
688
689    use assign::assign;
690    use js_int::int;
691    use maplit::btreemap;
692    use ruma_common::user_id;
693    use serde_json::{json, to_value as to_json_value};
694
695    use super::{default_power_level, NotificationPowerLevels, RoomPowerLevelsEventContent};
696
697    #[test]
698    fn serialization_with_optional_fields_as_none() {
699        let default = default_power_level();
700
701        let power_levels = RoomPowerLevelsEventContent {
702            ban: default,
703            events: BTreeMap::new(),
704            events_default: int!(0),
705            invite: int!(0),
706            kick: default,
707            redact: default,
708            state_default: default,
709            users: BTreeMap::new(),
710            users_default: int!(0),
711            notifications: NotificationPowerLevels::default(),
712        };
713
714        let actual = to_json_value(&power_levels).unwrap();
715        let expected = json!({});
716
717        assert_eq!(actual, expected);
718    }
719
720    #[test]
721    fn serialization_with_all_fields() {
722        let user = user_id!("@carl:example.com");
723        let power_levels_event = RoomPowerLevelsEventContent {
724            ban: int!(23),
725            events: btreemap! {
726                "m.dummy".into() => int!(23)
727            },
728            events_default: int!(23),
729            invite: int!(23),
730            kick: int!(23),
731            redact: int!(23),
732            state_default: int!(23),
733            users: btreemap! {
734                user.to_owned() => int!(23)
735            },
736            users_default: int!(23),
737            notifications: assign!(NotificationPowerLevels::new(), { room: int!(23) }),
738        };
739
740        let actual = to_json_value(&power_levels_event).unwrap();
741        let expected = json!({
742            "ban": 23,
743            "events": {
744                "m.dummy": 23
745            },
746            "events_default": 23,
747            "invite": 23,
748            "kick": 23,
749            "redact": 23,
750            "state_default": 23,
751            "users": {
752                "@carl:example.com": 23
753            },
754            "users_default": 23,
755            "notifications": {
756                "room": 23
757            },
758        });
759
760        assert_eq!(actual, expected);
761    }
762}