diff --git a/src/api/client_server/search.rs b/src/api/client_server/search.rs index 115b01b9..897ff3b6 100644 --- a/src/api/client_server/search.rs +++ b/src/api/client_server/search.rs @@ -35,7 +35,7 @@ pub(crate) async fn search_events_route( services() .rooms .state_cache - .rooms_joined(sender_user) + .rooms_once_joined(sender_user) .filter_map(Result::ok) .collect() }); @@ -51,7 +51,7 @@ pub(crate) async fn search_events_route( let mut searches = Vec::new(); for room_id in room_ids { - if !services().rooms.state_cache.is_joined(sender_user, &room_id)? { + if !services().rooms.state_cache.once_joined(sender_user, &room_id)? { return Err(Error::BadRequest( ErrorKind::forbidden(), "You don't have permission to view this room.", diff --git a/src/database/key_value/rooms/state_cache.rs b/src/database/key_value/rooms/state_cache.rs index ce8ce4df..eb70c1a6 100644 --- a/src/database/key_value/rooms/state_cache.rs +++ b/src/database/key_value/rooms/state_cache.rs @@ -615,6 +615,39 @@ impl service::rooms::state_cache::Data for KeyValueDatabase { )) } + /// Returns an iterator over all rooms a user has been in. + #[tracing::instrument(skip(self))] + fn rooms_once_joined<'a>( + &'a self, + user_id: &UserId, + ) -> Box> + 'a> { + let mut prefix = user_id.as_bytes().to_vec(); + prefix.push(0xFF); + + Box::new(self.roomuseroncejoinedids.scan_prefix(prefix).map( + |(key, _)| { + RoomId::parse( + utils::string_from_bytes( + key.rsplit(|&b| b == 0xFF) + .next() + .expect("rsplit always returns an element"), + ) + .map_err(|_| { + Error::bad_database( + "Room ID in roomuseroncejoinedids is invalid \ + unicode.", + ) + })?, + ) + .map_err(|_| { + Error::bad_database( + "Room ID in roomuseroncejoinedids is invalid.", + ) + }) + }, + )) + } + #[tracing::instrument(skip(self))] fn once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result { let mut userroom_id = user_id.as_bytes().to_vec(); diff --git a/src/service/rooms/state_cache.rs b/src/service/rooms/state_cache.rs index af6c7848..0c7ab5a4 100644 --- a/src/service/rooms/state_cache.rs +++ b/src/service/rooms/state_cache.rs @@ -387,6 +387,15 @@ impl Service { self.db.rooms_left(user_id) } + /// Returns an iterator over all rooms a user has been in. + #[tracing::instrument(skip(self))] + pub(crate) fn rooms_once_joined<'a>( + &'a self, + user_id: &UserId, + ) -> impl Iterator> + 'a { + self.db.rooms_once_joined(user_id) + } + #[tracing::instrument(skip(self))] pub(crate) fn once_joined( &self, diff --git a/src/service/rooms/state_cache/data.rs b/src/service/rooms/state_cache/data.rs index 5369e42f..f5d4ac37 100644 --- a/src/service/rooms/state_cache/data.rs +++ b/src/service/rooms/state_cache/data.rs @@ -125,6 +125,12 @@ pub(crate) trait Data: Send + Sync { + 'a, >; + /// Returns an iterator over all rooms a user has been in. + fn rooms_once_joined<'a>( + &'a self, + user_id: &UserId, + ) -> Box> + 'a>; + fn once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result; fn is_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result;