From 184ce2441dea4d41a164c22fa3c20fc3166b56a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 13 Dec 2024 13:08:29 +0100 Subject: [PATCH] feat(room): Separate `RoomState::Ban` from `RoomState::Left`. This is needed to tell apart rooms in left and banned state in places like `RoomInfo` or `RoomPreview`. The banned rooms will still count as left rooms in the sync processes. --- bindings/matrix-sdk-ffi/src/room.rs | 2 + crates/matrix-sdk-base/src/rooms/normal.rs | 112 +++++++++++++----- .../matrix-sdk-base/src/sliding_sync/mod.rs | 19 ++- 3 files changed, 96 insertions(+), 37 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/room.rs b/bindings/matrix-sdk-ffi/src/room.rs index fd0f6aef3fa..f0d39216d70 100644 --- a/bindings/matrix-sdk-ffi/src/room.rs +++ b/bindings/matrix-sdk-ffi/src/room.rs @@ -50,6 +50,7 @@ pub enum Membership { Joined, Left, Knocked, + Banned, } impl From for Membership { @@ -59,6 +60,7 @@ impl From for Membership { RoomState::Joined => Membership::Joined, RoomState::Left => Membership::Left, RoomState::Knocked => Membership::Knocked, + RoomState::Ban => Membership::Banned, } } } diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 1c8e1f1ea64..6a707e15f69 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -218,14 +218,14 @@ pub enum RoomState { Invited, /// The room is in a knocked state. Knocked, + /// The room is in a banned state. + Ban, } impl From<&MembershipState> for RoomState { fn from(membership_state: &MembershipState) -> Self { - // We consider Ban, Knock and Leave to be Left, because they all mean we are not - // in the room. match membership_state { - MembershipState::Ban => Self::Left, + MembershipState::Ban => Self::Ban, MembershipState::Invite => Self::Invited, MembershipState::Join => Self::Joined, MembershipState::Knock => Self::Knocked, @@ -480,6 +480,7 @@ impl Room { }, } } + RoomState::Ban => Ok(false), // TODO: implement logic once we have the stripped events as we'd have with an Invite RoomState::Knocked => Ok(false), @@ -1330,6 +1331,11 @@ impl RoomInfo { self.set_state(RoomState::Knocked); } + /// Mark this Room as banned. + pub fn mark_as_banned(&mut self) { + self.set_state(RoomState::Ban); + } + /// Set the membership RoomState of this Room pub fn set_state(&mut self, room_state: RoomState) { if room_state != self.room_state { @@ -1886,6 +1892,8 @@ bitflags! { const LEFT = 0b00000100; /// The room is in a knocked state. const KNOCKED = 0b00001000; + /// The room is in a banned state. + const BANNED = 0b00010000; } } @@ -1901,6 +1909,7 @@ impl RoomStateFilter { RoomState::Left => Self::LEFT, RoomState::Invited => Self::INVITED, RoomState::Knocked => Self::KNOCKED, + RoomState::Ban => Self::BANNED, }; self.contains(bit_state) @@ -1919,6 +1928,12 @@ impl RoomStateFilter { if self.contains(Self::INVITED) { states.push(RoomState::Invited); } + if self.contains(Self::KNOCKED) { + states.push(RoomState::Knocked); + } + if self.contains(Self::BANNED) { + states.push(RoomState::Ban); + } states } @@ -1980,30 +1995,21 @@ mod tests { test_json::{sync_events::PINNED_EVENTS, TAG}, ALICE, BOB, CAROL, }; - use ruma::{ - api::client::sync::sync_events::v3::RoomSummary as RumaSummary, - device_id, event_id, - events::{ - call::member::{ - ActiveFocus, ActiveLivekitFocus, Application, CallApplicationContent, - CallMemberEventContent, CallMemberStateKey, Focus, LegacyMembershipData, - LegacyMembershipDataInit, LivekitFocus, OriginalSyncCallMemberEvent, - }, - room::{ - canonical_alias::RoomCanonicalAliasEventContent, - encryption::{OriginalSyncRoomEncryptionEvent, RoomEncryptionEventContent}, - member::{MembershipState, RoomMemberEventContent, StrippedRoomMemberEvent}, - name::RoomNameEventContent, - pinned_events::RoomPinnedEventsEventContent, - }, - AnySyncStateEvent, EmptyStateKey, StateEventType, StateUnsigned, SyncStateEvent, + use ruma::{api::client::sync::sync_events::v3::RoomSummary as RumaSummary, device_id, event_id, events::{ + call::member::{ + ActiveFocus, ActiveLivekitFocus, Application, CallApplicationContent, + CallMemberEventContent, CallMemberStateKey, Focus, LegacyMembershipData, + LegacyMembershipDataInit, LivekitFocus, OriginalSyncCallMemberEvent, }, - owned_event_id, owned_user_id, room_alias_id, room_id, - serde::Raw, - time::SystemTime, - user_id, DeviceId, EventEncryptionAlgorithm, EventId, MilliSecondsSinceUnixEpoch, - OwnedEventId, OwnedUserId, UserId, - }; + room::{ + canonical_alias::RoomCanonicalAliasEventContent, + encryption::{OriginalSyncRoomEncryptionEvent, RoomEncryptionEventContent}, + member::{MembershipState, RoomMemberEventContent, StrippedRoomMemberEvent}, + name::RoomNameEventContent, + pinned_events::RoomPinnedEventsEventContent, + }, + AnySyncStateEvent, EmptyStateKey, StateEventType, StateUnsigned, SyncStateEvent, + }, owned_event_id, owned_room_id, owned_user_id, room_alias_id, room_id, serde::Raw, time::SystemTime, user_id, DeviceId, EventEncryptionAlgorithm, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, UserId}; use serde_json::json; use similar_asserts::assert_eq; use stream_assert::{assert_pending, assert_ready}; @@ -2011,12 +2017,8 @@ mod tests { use super::{compute_display_name_from_heroes, Room, RoomHero, RoomInfo, RoomState, SyncInfo}; #[cfg(any(feature = "experimental-sliding-sync", feature = "e2e-encryption"))] use crate::latest_event::LatestEvent; - use crate::{ - rooms::RoomNotableTags, - store::{IntoStateStore, MemoryStore, StateChanges, StateStore, StoreConfig}, - BaseClient, MinimalStateEvent, OriginalMinimalStateEvent, RoomDisplayName, - RoomInfoNotableUpdateReasons, SessionMeta, - }; + use crate::{rooms::RoomNotableTags, store::{IntoStateStore, MemoryStore, StateChanges, StateStore, StoreConfig}, BaseClient, MinimalStateEvent, OriginalMinimalStateEvent, RoomDisplayName, RoomInfoNotableUpdateReasons, RoomStateFilter, SessionMeta}; + use crate::test_utils::logged_in_base_client; #[test] #[cfg(feature = "experimental-sliding-sync")] @@ -3535,4 +3537,50 @@ mod tests { assert_eq!(room.prev_state(), Some(RoomState::Joined)); assert_eq!(room.state(), RoomState::Left); } + + #[async_test] + async fn test_room_filters() { + let client = logged_in_base_client(None).await; + let user_id = user_id!("@me:example.org"); + + let joined_room_id = owned_room_id!("!joined:example.org"); + client.get_or_create_room(&joined_room_id, RoomState::Joined); + + let invited_room_id = owned_room_id!("!invited:example.org"); + client.get_or_create_room(&invited_room_id, RoomState::Invited); + + let left_room_id = owned_room_id!("!left:example.org"); + client.get_or_create_room(&left_room_id, RoomState::Left); + + let knocked_room_id = owned_room_id!("!knocked:example.org"); + client.get_or_create_room(&knocked_room_id, RoomState::Knocked); + + let banned_room_id = owned_room_id!("!banned:example.org"); + client.get_or_create_room(&banned_room_id, RoomState::Ban); + + let joined_rooms = client.rooms_filtered(RoomStateFilter::JOINED); + assert_eq!(joined_rooms.len(), 1); + assert_eq!(joined_rooms[0].state(), RoomState::Joined); + assert_eq!(joined_rooms[0].room_id, joined_room_id); + + let invited_rooms = client.rooms_filtered(RoomStateFilter::INVITED); + assert_eq!(invited_rooms.len(), 1); + assert_eq!(invited_rooms[0].state(), RoomState::Invited); + assert_eq!(invited_rooms[0].room_id, invited_room_id); + + let left_rooms = client.rooms_filtered(RoomStateFilter::LEFT); + assert_eq!(left_rooms.len(), 1); + assert_eq!(left_rooms[0].state(), RoomState::Left); + assert_eq!(left_rooms[0].room_id, left_room_id); + + let knocked_rooms = client.rooms_filtered(RoomStateFilter::KNOCKED); + assert_eq!(knocked_rooms.len(), 1); + assert_eq!(knocked_rooms[0].state(), RoomState::Knocked); + assert_eq!(knocked_rooms[0].room_id, knocked_room_id); + + let banned_rooms = client.rooms_filtered(RoomStateFilter::BANNED); + assert_eq!(banned_rooms.len(), 1); + assert_eq!(banned_rooms[0].state(), RoomState::Ban); + assert_eq!(banned_rooms[0].room_id, banned_room_id); + } } diff --git a/crates/matrix-sdk-base/src/sliding_sync/mod.rs b/crates/matrix-sdk-base/src/sliding_sync/mod.rs index 3bf2669030e..a58f968c4a6 100644 --- a/crates/matrix-sdk-base/src/sliding_sync/mod.rs +++ b/crates/matrix-sdk-base/src/sliding_sync/mod.rs @@ -269,7 +269,7 @@ impl BaseClient { .or_insert_with(JoinedRoomUpdate::default) .account_data .append(&mut raw.to_vec()), - RoomState::Left => new_rooms + RoomState::Left | RoomState::Ban => new_rooms .leave .entry(room_id.to_owned()) .or_insert_with(LeftRoomUpdate::default) @@ -546,7 +546,7 @@ impl BaseClient { )) } - RoomState::Left => Ok(( + RoomState::Left | RoomState::Ban => Ok(( room_info, None, Some(LeftRoomUpdate::new( @@ -1247,7 +1247,7 @@ mod tests { room.required_state.push(make_state_event( user_b_id, user_a_id.as_str(), - RoomMemberEventContent::new(membership), + RoomMemberEventContent::new(membership.clone()), None, )); let response = response_with_room(room_id, room); @@ -1256,8 +1256,17 @@ mod tests { .await .expect("Failed to process sync"); - // The room is left. - assert_eq!(client.get_room(room_id).unwrap().state(), RoomState::Left); + match membership { + MembershipState::Leave => { + // The room is left. + assert_eq!(client.get_room(room_id).unwrap().state(), RoomState::Left); + } + MembershipState::Ban => { + // The room is banned. + assert_eq!(client.get_room(room_id).unwrap().state(), RoomState::Ban); + } + _ => panic!("Unexpected membership state found: {membership}"), + } // And it is added to the list of left rooms only. assert!(!sync_resp.rooms.join.contains_key(room_id));