diff --git a/crates/ruma-common/src/events/room/member.rs b/crates/ruma-common/src/events/room/member.rs index cf883992..38b83c63 100644 --- a/crates/ruma-common/src/events/room/member.rs +++ b/crates/ruma-common/src/events/room/member.rs @@ -15,9 +15,13 @@ use crate::{ }, serde::StringEnum, MxcUri, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, PrivOwnedStr, RoomVersionId, - UserId, }; +mod change; + +use self::change::membership_change; +pub use self::change::{MembershipChange, MembershipDetails}; + /// The content of an `m.room.member` event. /// /// The current membership state of a user in the room. @@ -293,101 +297,6 @@ impl SignedContent { } } -/// The details of a member event required to calculate a [`MembershipChange`]. -pub struct MembershipDetails<'a> { - // These fields are intentionally private, this struct is only meant for - // passing it to one of the membership_change methods on redacted events. - avatar_url: Option<&'a MxcUri>, - displayname: Option<&'a str>, - membership: &'a MembershipState, -} - -/// Translation of the membership change in `m.room.member` event. -#[derive(Clone, Debug, Deserialize, Serialize)] -#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -pub enum MembershipChange { - /// No change. - None, - - /// Must never happen. - Error, - - /// User joined the room. - Joined, - - /// User left the room. - Left, - - /// User was banned. - Banned, - - /// User was unbanned. - Unbanned, - - /// User was kicked. - Kicked, - - /// User was invited. - Invited, - - /// User was kicked and banned. - KickedAndBanned, - - /// User rejected the invite. - InvitationRejected, - - /// User had their invite revoked. - InvitationRevoked, - - /// `displayname` or `avatar_url` changed. - ProfileChanged { - /// Whether the `displayname` changed. - displayname_changed: bool, - - /// Whether the `avatar_url` changed. - avatar_url_changed: bool, - }, - - /// Not implemented. - NotImplemented, -} - -/// Internal function so all `RoomMemberEventContent` state event kinds can share the same -/// implementation. -fn membership_change( - details: MembershipDetails<'_>, - prev_details: Option>, - sender: &UserId, - state_key: &UserId, -) -> MembershipChange { - use MembershipChange as Ch; - use MembershipState as St; - - let prev_details = match prev_details { - Some(prev) => prev, - None => MembershipDetails { avatar_url: None, displayname: None, membership: &St::Leave }, - }; - - match (&prev_details.membership, &details.membership) { - (St::Invite, St::Invite) | (St::Leave, St::Leave) | (St::Ban, St::Ban) => Ch::None, - (St::Invite, St::Join) | (St::Leave, St::Join) => Ch::Joined, - (St::Invite, St::Leave) if sender == state_key => Ch::InvitationRevoked, - (St::Invite, St::Leave) => Ch::InvitationRejected, - (St::Invite, St::Ban) | (St::Leave, St::Ban) => Ch::Banned, - (St::Join, St::Invite) | (St::Ban, St::Invite) | (St::Ban, St::Join) => Ch::Error, - (St::Join, St::Join) => Ch::ProfileChanged { - displayname_changed: prev_details.displayname != details.displayname, - avatar_url_changed: prev_details.avatar_url != details.avatar_url, - }, - (St::Join, St::Leave) if sender == state_key => Ch::Left, - (St::Join, St::Leave) => Ch::Kicked, - (St::Join, St::Ban) => Ch::KickedAndBanned, - (St::Leave, St::Invite) => Ch::Invited, - (St::Ban, St::Leave) => Ch::Unbanned, - _ => Ch::NotImplemented, - } -} - impl OriginalRoomMemberEvent { /// Obtain the details about this event that are required to calculate a membership change. /// diff --git a/crates/ruma-common/src/events/room/member/change.rs b/crates/ruma-common/src/events/room/member/change.rs new file mode 100644 index 00000000..9d015ea7 --- /dev/null +++ b/crates/ruma-common/src/events/room/member/change.rs @@ -0,0 +1,97 @@ +use serde::{Deserialize, Serialize}; + +use super::MembershipState; +use crate::{MxcUri, UserId}; + +/// The details of a member event required to calculate a [`MembershipChange`]. +pub struct MembershipDetails<'a> { + pub(crate) avatar_url: Option<&'a MxcUri>, + pub(crate) displayname: Option<&'a str>, + pub(crate) membership: &'a MembershipState, +} + +/// Translation of the membership change in `m.room.member` event. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +pub enum MembershipChange { + /// No change. + None, + + /// Must never happen. + Error, + + /// User joined the room. + Joined, + + /// User left the room. + Left, + + /// User was banned. + Banned, + + /// User was unbanned. + Unbanned, + + /// User was kicked. + Kicked, + + /// User was invited. + Invited, + + /// User was kicked and banned. + KickedAndBanned, + + /// User rejected the invite. + InvitationRejected, + + /// User had their invite revoked. + InvitationRevoked, + + /// `displayname` or `avatar_url` changed. + ProfileChanged { + /// Whether the `displayname` changed. + displayname_changed: bool, + + /// Whether the `avatar_url` changed. + avatar_url_changed: bool, + }, + + /// Not implemented. + NotImplemented, +} + +/// Internal function so all `RoomMemberEventContent` state event kinds can share the same +/// implementation. +pub(super) fn membership_change( + details: MembershipDetails<'_>, + prev_details: Option>, + sender: &UserId, + state_key: &UserId, +) -> MembershipChange { + use MembershipChange as Ch; + use MembershipState as St; + + let prev_details = match prev_details { + Some(prev) => prev, + None => MembershipDetails { avatar_url: None, displayname: None, membership: &St::Leave }, + }; + + match (&prev_details.membership, &details.membership) { + (St::Invite, St::Invite) | (St::Leave, St::Leave) | (St::Ban, St::Ban) => Ch::None, + (St::Invite, St::Join) | (St::Leave, St::Join) => Ch::Joined, + (St::Invite, St::Leave) if sender == state_key => Ch::InvitationRevoked, + (St::Invite, St::Leave) => Ch::InvitationRejected, + (St::Invite, St::Ban) | (St::Leave, St::Ban) => Ch::Banned, + (St::Join, St::Invite) | (St::Ban, St::Invite) | (St::Ban, St::Join) => Ch::Error, + (St::Join, St::Join) => Ch::ProfileChanged { + displayname_changed: prev_details.displayname != details.displayname, + avatar_url_changed: prev_details.avatar_url != details.avatar_url, + }, + (St::Join, St::Leave) if sender == state_key => Ch::Left, + (St::Join, St::Leave) => Ch::Kicked, + (St::Join, St::Ban) => Ch::KickedAndBanned, + (St::Leave, St::Invite) => Ch::Invited, + (St::Ban, St::Leave) => Ch::Unbanned, + _ => Ch::NotImplemented, + } +}