sdk-base: Allow to filter get_user_ids results by any membership state

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
Kévin Commaille
2023-04-19 17:32:48 +02:00
committed by Jonas Platte
parent 58a1ad1b93
commit 4ffa20abde
10 changed files with 102 additions and 142 deletions

View File

@@ -6,6 +6,8 @@
- Add `RoomInfo::state` accessor
- Remove `members` and `stripped_members` fields in `StateChanges`. Room member events are now with
other state events in `state` and `stripped_state`.
- `StateStore::get_user_ids` takes a `RoomMemberships` to be able to filter the results by any
membership state.
## 0.5.1

View File

@@ -44,7 +44,7 @@ use crate::{
deserialized_responses::MemberEvent,
store::{DynStateStore, Result as StoreResult, StateStoreExt},
sync::UnreadNotificationsCount,
MinimalStateEvent,
MinimalStateEvent, RoomMemberships,
};
/// The underlying room data structure collecting state for joined, left and
@@ -323,7 +323,7 @@ impl Room {
/// Get the all `RoomMember`s of this room that are known to the store.
pub async fn members(&self) -> StoreResult<Vec<RoomMember>> {
let user_ids = self.store.get_user_ids(self.room_id()).await?;
let user_ids = self.store.get_user_ids(self.room_id(), RoomMemberships::empty()).await?;
let mut members = Vec::new();
for u in user_ids {

View File

@@ -35,7 +35,7 @@ use crate::{
deserialized_responses::MemberEvent,
media::{MediaFormat, MediaRequest, MediaThumbnailSize},
store::{Result, StateStoreExt},
RoomInfo, RoomState, StateChanges, StateStoreDataKey, StateStoreDataValue,
RoomInfo, RoomMemberships, RoomState, StateChanges, StateStoreDataKey, StateStoreDataValue,
};
/// `StateStore` integration tests.
@@ -330,7 +330,7 @@ impl StateStoreIntegrationTests for DynStateStore {
assert!(self.get_profile(room_id, user_id).await?.is_some());
assert!(self.get_member_event(room_id, user_id).await?.is_some());
assert_eq!(
self.get_user_ids(room_id).await?.len(),
self.get_user_ids(room_id, RoomMemberships::empty()).await?.len(),
2,
"Expected to find 2 members for room"
);
@@ -394,7 +394,7 @@ impl StateStoreIntegrationTests for DynStateStore {
self.save_changes(&changes).await.unwrap();
assert!(self.get_member_event(room_id, user_id).await.unwrap().is_some());
let members = self.get_user_ids(room_id).await.unwrap();
let members = self.get_user_ids(room_id, RoomMemberships::empty()).await.unwrap();
assert!(!members.is_empty(), "We expected to find members for the room")
}
@@ -466,7 +466,7 @@ impl StateStoreIntegrationTests for DynStateStore {
self.save_changes(&changes).await.unwrap();
assert!(self.get_member_event(room_id, user_id).await.unwrap().is_some());
let members = self.get_user_ids(room_id).await.unwrap();
let members = self.get_user_ids(room_id, RoomMemberships::empty()).await.unwrap();
assert!(!members.is_empty(), "We expected to find members for the room")
}
@@ -774,7 +774,7 @@ impl StateStoreIntegrationTests for DynStateStore {
assert_eq!(self.get_room_infos().await.unwrap().len(), 1);
assert_eq!(self.get_stripped_room_infos().await.unwrap().len(), 0);
let members = self.get_user_ids(room_id).await.unwrap();
let members = self.get_user_ids(room_id, RoomMemberships::empty()).await.unwrap();
assert_eq!(members, vec![user_id.to_owned()]);
let mut changes = StateChanges::default();
@@ -788,7 +788,7 @@ impl StateStoreIntegrationTests for DynStateStore {
assert_eq!(self.get_room_infos().await.unwrap().len(), 0);
assert_eq!(self.get_stripped_room_infos().await.unwrap().len(), 1);
let members = self.get_user_ids(room_id).await.unwrap();
let members = self.get_user_ids(room_id, RoomMemberships::empty()).await.unwrap();
assert_eq!(members, vec![user_id.to_owned()]);
Ok(())
@@ -813,7 +813,10 @@ impl StateStoreIntegrationTests for DynStateStore {
);
assert!(self.get_profile(room_id, user_id).await?.is_none());
assert!(self.get_member_event(room_id, user_id).await?.is_none());
assert!(self.get_user_ids(room_id).await?.is_empty(), "still user ids found");
assert!(
self.get_user_ids(room_id, RoomMemberships::empty()).await?.is_empty(),
"still user ids found"
);
assert!(
self.get_invited_user_ids(room_id).await?.is_empty(),
"still invited user ids found"

View File

@@ -456,30 +456,6 @@ impl MemoryStore {
.unwrap_or_default()
}
fn get_user_ids(&self, room_id: &RoomId) -> Vec<OwnedUserId> {
let v = self.get_user_ids_inner(room_id, RoomMemberships::empty(), true);
if !v.is_empty() {
return v;
}
self.get_user_ids_inner(room_id, RoomMemberships::empty(), false)
}
fn get_invited_user_ids(&self, room_id: &RoomId) -> Vec<OwnedUserId> {
self.get_user_ids_inner(room_id, RoomMemberships::INVITE, false)
}
fn get_joined_user_ids(&self, room_id: &RoomId) -> Vec<OwnedUserId> {
self.get_user_ids_inner(room_id, RoomMemberships::JOIN, false)
}
fn get_stripped_invited_user_ids(&self, room_id: &RoomId) -> Vec<OwnedUserId> {
self.get_user_ids_inner(room_id, RoomMemberships::INVITE, true)
}
fn get_stripped_joined_user_ids(&self, room_id: &RoomId) -> Vec<OwnedUserId> {
self.get_user_ids_inner(room_id, RoomMemberships::JOIN, true)
}
fn get_room_infos(&self) -> Vec<RoomInfo> {
self.room_info.iter().map(|r| r.clone()).collect()
}
@@ -643,24 +619,24 @@ impl StateStore for MemoryStore {
self.get_member_event(room_id, state_key).await
}
async fn get_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
Ok(self.get_user_ids(room_id))
async fn get_user_ids(
&self,
room_id: &RoomId,
memberships: RoomMemberships,
) -> Result<Vec<OwnedUserId>> {
let v = self.get_user_ids_inner(room_id, memberships, true);
if !v.is_empty() {
return Ok(v);
}
Ok(self.get_user_ids_inner(room_id, memberships, false))
}
async fn get_invited_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
let v = self.get_stripped_invited_user_ids(room_id);
if !v.is_empty() {
return Ok(v);
}
Ok(self.get_invited_user_ids(room_id))
StateStore::get_user_ids(self, room_id, RoomMemberships::INVITE).await
}
async fn get_joined_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
let v = self.get_stripped_joined_user_ids(room_id);
if !v.is_empty() {
return Ok(v);
}
Ok(self.get_joined_user_ids(room_id))
StateStore::get_user_ids(self, room_id, RoomMemberships::JOIN).await
}
async fn get_room_infos(&self) -> Result<Vec<RoomInfo>> {

View File

@@ -33,6 +33,7 @@ use ruma::{
use super::{StateChanges, StoreError};
use crate::{
deserialized_responses::RawMemberEvent, media::MediaRequest, MinimalRoomMemberEvent, RoomInfo,
RoomMemberships,
};
/// An abstract state store trait that can be used to implement different stores
@@ -142,9 +143,13 @@ pub trait StateStore: AsyncTraitDeps {
state_key: &UserId,
) -> Result<Option<RawMemberEvent>, Self::Error>;
/// Get all the user ids of members for a given room, for stripped and
/// regular rooms alike.
async fn get_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>, Self::Error>;
/// Get the user ids of members for a given room with the given memberships,
/// for stripped and regular rooms alike.
async fn get_user_ids(
&self,
room_id: &RoomId,
memberships: RoomMemberships,
) -> Result<Vec<OwnedUserId>, Self::Error>;
/// Get all the user ids of members that are in the invited state for a
/// given room, for stripped and regular rooms alike.
@@ -391,8 +396,12 @@ impl<T: StateStore> StateStore for EraseStateStoreError<T> {
self.0.get_member_event(room_id, state_key).await.map_err(Into::into)
}
async fn get_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>, Self::Error> {
self.0.get_user_ids(room_id).await.map_err(Into::into)
async fn get_user_ids(
&self,
room_id: &RoomId,
memberships: RoomMemberships,
) -> Result<Vec<OwnedUserId>, Self::Error> {
self.0.get_user_ids(room_id, memberships).await.map_err(Into::into)
}
async fn get_invited_user_ids(

View File

@@ -605,8 +605,8 @@ mod tests {
use assert_matches::assert_matches;
use indexed_db_futures::prelude::*;
use matrix_sdk_base::{
deserialized_responses::RawMemberEvent, RoomInfo, RoomState, StateStore, StateStoreDataKey,
StoreError,
deserialized_responses::RawMemberEvent, RoomInfo, RoomMemberships, RoomState, StateStore,
StateStoreDataKey, StoreError,
};
use matrix_sdk_test::{async_test, test_json};
use ruma::{
@@ -1166,23 +1166,30 @@ mod tests {
// this transparently migrates to the latest version
let store = IndexeddbStateStore::builder().name(name).build().await?;
assert_eq!(store.get_joined_user_ids(room_id).await.unwrap().len(), 0);
assert_eq!(store.get_user_ids(room_id, RoomMemberships::JOIN).await.unwrap().len(), 0);
assert_eq!(
store.get_invited_user_ids(room_id).await.unwrap().as_slice(),
store.get_user_ids(room_id, RoomMemberships::INVITE).await.unwrap().as_slice(),
[invite_user_id.to_owned()]
);
let user_ids = store.get_user_ids(room_id).await.unwrap();
let user_ids = store.get_user_ids(room_id, RoomMemberships::empty()).await.unwrap();
assert_eq!(user_ids.len(), 2);
assert!(user_ids.contains(&invite_user_id.to_owned()));
assert!(user_ids.contains(&ban_user_id.to_owned()));
assert_eq!(
store.get_stripped_joined_user_ids(stripped_room_id).await.unwrap().as_slice(),
store.get_user_ids(stripped_room_id, RoomMemberships::JOIN).await.unwrap().as_slice(),
[stripped_user_id.to_owned()]
);
assert_eq!(store.get_stripped_invited_user_ids(stripped_room_id).await.unwrap().len(), 0);
assert_eq!(
store.get_user_ids(stripped_room_id).await.unwrap().as_slice(),
store.get_user_ids(stripped_room_id, RoomMemberships::INVITE).await.unwrap().len(),
0
);
assert_eq!(
store
.get_user_ids(stripped_room_id, RoomMemberships::empty())
.await
.unwrap()
.as_slice(),
[stripped_user_id.to_owned()]
);

View File

@@ -312,9 +312,6 @@ impl IndexeddbStateStore {
/// Get user IDs for the given room with the given memberships and stripped
/// state.
///
/// If `memberships` is empty, returns all user IDs in the room with the
/// given stripped state.
pub async fn get_user_ids_inner(
&self,
room_id: &RoomId,
@@ -364,17 +361,6 @@ impl IndexeddbStateStore {
Ok(user_ids)
}
pub async fn get_stripped_invited_user_ids(
&self,
room_id: &RoomId,
) -> Result<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::INVITE, true).await
}
pub async fn get_stripped_joined_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::JOIN, true).await
}
async fn get_custom_value_for_js(&self, jskey: &JsValue) -> Result<Option<Vec<u8>>> {
self.inner
.transaction_on_one_with_mode(keys::CUSTOM, IdbTransactionMode::Readonly)?
@@ -1146,28 +1132,20 @@ impl_state_store! {
tx.await.into_result().map_err(|e| e.into())
}
async fn get_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
let ids = self.get_user_ids_inner(room_id, RoomMemberships::empty(), true).await?;
async fn get_user_ids(&self, room_id: &RoomId, memberships: RoomMemberships) -> Result<Vec<OwnedUserId>> {
let ids = self.get_user_ids_inner(room_id, memberships, true).await?;
if !ids.is_empty() {
return Ok(ids);
}
self.get_user_ids_inner(room_id, RoomMemberships::empty(), false).await
self.get_user_ids_inner(room_id, memberships, false).await
}
async fn get_invited_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
let ids: Vec<OwnedUserId> = self.get_stripped_invited_user_ids(room_id).await?;
if !ids.is_empty() {
return Ok(ids);
}
self.get_user_ids_inner(room_id, RoomMemberships::INVITE, false).await
self.get_user_ids(room_id, RoomMemberships::INVITE).await
}
async fn get_joined_user_ids(&self, room_id: &RoomId) -> Result<Vec<OwnedUserId>> {
let ids: Vec<OwnedUserId> = self.get_stripped_joined_user_ids(room_id).await?;
if !ids.is_empty() {
return Ok(ids);
}
self.get_user_ids_inner(room_id, RoomMemberships::JOIN, false).await
self.get_user_ids(room_id, RoomMemberships::JOIN).await
}
}

View File

@@ -390,7 +390,8 @@ pub const V1_DB_STORES: &[&str] = &[
mod test {
use assert_matches::assert_matches;
use matrix_sdk_base::{
deserialized_responses::RawMemberEvent, RoomInfo, RoomState, StateStoreDataKey,
deserialized_responses::RawMemberEvent, RoomInfo, RoomMemberships, RoomState,
StateStoreDataKey,
};
use matrix_sdk_test::{async_test, test_json};
use ruma::{
@@ -774,23 +775,41 @@ mod test {
.build()
.unwrap();
assert_eq!(store.get_joined_user_ids(room_id).await.unwrap().len(), 0);
assert_eq!(
store.get_invited_user_ids(room_id).await.unwrap().as_slice(),
store.get_user_ids(room_id, RoomMemberships::JOIN, false).await.unwrap().len(),
0
);
assert_eq!(
store.get_user_ids(room_id, RoomMemberships::INVITE, false).await.unwrap().as_slice(),
[invite_user_id.to_owned()]
);
let user_ids = store.get_user_ids(room_id).await.unwrap();
let user_ids = store.get_user_ids(room_id, RoomMemberships::empty(), false).await.unwrap();
assert_eq!(user_ids.len(), 2);
assert!(user_ids.contains(&invite_user_id.to_owned()));
assert!(user_ids.contains(&ban_user_id.to_owned()));
assert_eq!(
store.get_stripped_joined_user_ids(stripped_room_id).await.unwrap().as_slice(),
store
.get_user_ids(stripped_room_id, RoomMemberships::JOIN, true)
.await
.unwrap()
.as_slice(),
[stripped_user_id.to_owned()]
);
assert_eq!(store.get_stripped_invited_user_ids(stripped_room_id).await.unwrap().len(), 0);
assert_eq!(
store.get_stripped_user_ids(stripped_room_id).await.unwrap().as_slice(),
store
.get_user_ids(stripped_room_id, RoomMemberships::INVITE, true)
.await
.unwrap()
.len(),
0
);
assert_eq!(
store
.get_user_ids(stripped_room_id, RoomMemberships::empty(), true)
.await
.unwrap()
.as_slice(),
[stripped_user_id.to_owned()]
);
}

View File

@@ -852,12 +852,9 @@ impl SledStateStore {
.await?
}
/// Get a stream of user IDs for the given room with the given memberships
/// and stripped state.
///
/// If `memberships` is empty, returns all user IDs in the room with the
/// given stripped state.
pub async fn get_user_ids_inner(
/// Get the user IDs for the given room with the given memberships and
/// stripped state.
pub async fn get_user_ids(
&self,
room_id: &RoomId,
memberships: RoomMemberships,
@@ -888,36 +885,6 @@ impl SledStateStore {
.map_err(StoreError::backend)?
}
pub async fn get_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::empty(), false).await
}
pub async fn get_stripped_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::empty(), true).await
}
pub async fn get_invited_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::INVITE, false).await
}
pub async fn get_joined_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::JOIN, false).await
}
pub async fn get_stripped_invited_user_ids(
&self,
room_id: &RoomId,
) -> StoreResult<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::INVITE, true).await
}
pub async fn get_stripped_joined_user_ids(
&self,
room_id: &RoomId,
) -> StoreResult<Vec<OwnedUserId>> {
self.get_user_ids_inner(room_id, RoomMemberships::JOIN, true).await
}
pub async fn get_room_infos(&self) -> Result<impl Stream<Item = Result<RoomInfo>>> {
let db = self.clone();
spawn_blocking(move || {
@@ -1292,28 +1259,24 @@ impl StateStore for SledStateStore {
self.get_member_event(room_id, state_key).await.map_err(Into::into)
}
async fn get_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
let v = self.get_stripped_user_ids(room_id).await?;
async fn get_user_ids(
&self,
room_id: &RoomId,
memberships: RoomMemberships,
) -> StoreResult<Vec<OwnedUserId>> {
let v = self.get_user_ids(room_id, memberships, true).await?;
if !v.is_empty() {
return Ok(v);
}
self.get_user_ids(room_id).await
self.get_user_ids(room_id, memberships, false).await
}
async fn get_invited_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
let v = self.get_stripped_invited_user_ids(room_id).await?;
if !v.is_empty() {
return Ok(v);
}
self.get_invited_user_ids(room_id).await
StateStore::get_user_ids(self, room_id, RoomMemberships::INVITE).await
}
async fn get_joined_user_ids(&self, room_id: &RoomId) -> StoreResult<Vec<OwnedUserId>> {
let v = self.get_stripped_joined_user_ids(room_id).await?;
if !v.is_empty() {
return Ok(v);
}
self.get_joined_user_ids(room_id).await
StateStore::get_user_ids(self, room_id, RoomMemberships::JOIN).await
}
async fn get_room_infos(&self) -> StoreResult<Vec<RoomInfo>> {

View File

@@ -701,7 +701,10 @@ impl Common {
/// Returns true if all devices in the room are verified, otherwise false.
#[cfg(feature = "e2e-encryption")]
pub async fn contains_only_verified_devices(&self) -> Result<bool> {
let user_ids = self.client.store().get_user_ids(self.room_id()).await?;
use matrix_sdk_base::RoomMemberships;
let user_ids =
self.client.store().get_user_ids(self.room_id(), RoomMemberships::empty()).await?;
for user_id in user_ids {
let devices = self.client.encryption().get_user_devices(&user_id).await?;