Fetch sender profile when returning latest event

This commit is contained in:
Andy Balaam
2023-07-07 12:59:49 +01:00
parent 98882b9c23
commit 3fd1542a25
4 changed files with 96 additions and 17 deletions

View File

@@ -373,8 +373,8 @@ impl RoomListItem {
self.inner.unsubscribe();
}
fn latest_event(&self) -> Option<Arc<EventTimelineItem>> {
self.inner.latest_event().map(EventTimelineItem).map(Arc::new)
async fn latest_event(&self) -> Option<Arc<EventTimelineItem>> {
self.inner.latest_event().await.map(EventTimelineItem).map(Arc::new)
}
fn has_unread_notifications(&self) -> bool {

View File

@@ -135,8 +135,8 @@ impl Room {
///
/// It's different from `Self::timeline().latest_event()` as it won't track
/// the read marker and receipts.
pub fn latest_event(&self) -> Option<EventTimelineItem> {
self.inner.sliding_sync_room.latest_timeline_item()
pub async fn latest_event(&self) -> Option<EventTimelineItem> {
self.inner.sliding_sync_room.latest_timeline_item().await
}
/// Is there any unread notifications?

View File

@@ -83,10 +83,12 @@ impl EventTimelineItem {
/// If the supplied low-level SyncTimelineEventy is suitable for use as the
/// latest_event in a message preview, wrap it as an EventTimelineItem,
#[cfg(feature = "experimental-sliding-sync")]
pub(crate) fn from_latest_event(
pub(crate) async fn from_latest_event(
room: &SlidingSyncRoom,
sync_event: SyncTimelineEvent,
) -> Option<EventTimelineItem> {
use super::traits::RoomDataProvider;
let raw_sync_event = sync_event.event;
let encryption_info = sync_event.encryption_info;
@@ -135,10 +137,15 @@ impl EventTimelineItem {
}
.into();
// If we need to sender profiles in the message previews, we will need to
// cache the contents of a Profile struct inside RoomInfo similar to how we
// are caching the event at the moment.
let sender_profile = TimelineDetails::Unavailable;
let room = room.client().get_room(room.room_id());
let sender_profile = if let Some(room) = room {
room.profile(&sender)
.await
.map(TimelineDetails::Ready)
.unwrap_or(TimelineDetails::Unavailable)
} else {
TimelineDetails::Unavailable
};
Some(EventTimelineItem::new(sender, sender_profile, timestamp, item_content, event_kind))
}
@@ -480,9 +487,9 @@ mod test {
);
// When we construct a timeline event from it
let timeline_item = EventTimelineItem::from_latest_event(&room, event).unwrap();
let timeline_item = EventTimelineItem::from_latest_event(&room, event).await.unwrap();
// Then its properieis correctly translate
// Then its properties correctly translate
assert_eq!(timeline_item.sender, user_id);
assert_matches!(timeline_item.sender_profile, TimelineDetails::Unavailable);
assert_eq!(timeline_item.timestamp.0, UInt::new(122344).unwrap());
@@ -496,6 +503,77 @@ mod test {
}
}
#[async_test]
#[cfg(feature = "experimental-sliding-sync")]
async fn latest_message_event_can_be_wrapped_as_a_timeline_item_with_sender() {
// Given a sync event that is suitable to be used as a latest_event, and a room
// with a member event for the sender
use ruma::owned_mxc_uri;
let room_id = room_id!("!q:x.uk");
let user_id = user_id!("@t:o.uk");
let event = message_event(room_id, user_id, "**My M**", "<b>My M</b>", 122344);
let client = logged_in_client(None).await;
let mut room = v4::SlidingSyncRoom::new();
room.timeline.push(member_event(room_id, user_id, "Alice Margatroid", "mxc://e.org/SEs"));
let ss_room =
SlidingSyncRoom::new(client.clone(), room_id.to_owned(), room.clone(), Vec::new());
// And the room is stored in the client so it can be extracted when needed
let response = response_with_room(room_id, room).await;
client.process_sliding_sync(&response).await.unwrap();
// When we construct a timeline event from it
let timeline_item = EventTimelineItem::from_latest_event(&ss_room, event).await.unwrap();
// Then its sender is properly populated
let profile = assert_matches!(timeline_item.sender_profile, TimelineDetails::Ready(p) => p);
assert_eq!(
profile,
Profile {
display_name: Some("Alice Margatroid".to_owned()),
display_name_ambiguous: false,
avatar_url: Some(owned_mxc_uri!("mxc://e.org/SEs"))
}
);
}
fn member_event(
room_id: &RoomId,
user_id: &UserId,
display_name: &str,
avatar_url: &str,
) -> Raw<AnySyncTimelineEvent> {
Raw::from_json_string(
json!({
"type": "m.room.member",
"content": {
"avatar_url": avatar_url,
"displayname": display_name,
"membership": "join",
"reason": ""
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 143273583,
"room_id": room_id,
"sender": "@example:example.org",
"state_key": user_id,
"type": "m.room.member",
"unsigned": {
"age": 1234
}
})
.to_string(),
)
.unwrap()
}
async fn response_with_room(room_id: &RoomId, room: v4::SlidingSyncRoom) -> v4::Response {
let mut response = v4::Response::new("6".to_owned());
response.rooms.insert(room_id.to_owned(), room);
response
}
fn message_event(
room_id: &RoomId,
user_id: &UserId,

View File

@@ -14,7 +14,7 @@
use async_trait::async_trait;
use matrix_sdk::SlidingSyncRoom;
use tracing::{error, instrument, warn};
use tracing::{error, instrument};
use super::{EventTimelineItem, Timeline, TimelineBuilder};
@@ -27,7 +27,7 @@ pub trait SlidingSyncRoomExt {
///
/// Use `Timeline::latest_event` instead if you already have a timeline for
/// this `SlidingSyncRoom`.
fn latest_timeline_item(&self) -> Option<EventTimelineItem>;
async fn latest_timeline_item(&self) -> Option<EventTimelineItem>;
}
#[async_trait]
@@ -40,8 +40,9 @@ impl SlidingSyncRoomExt for SlidingSyncRoom {
/// This method wraps latest_event, converting the event into an
/// EventTimelineItem.
#[instrument(skip_all)]
fn latest_timeline_item(&self) -> Option<EventTimelineItem> {
self.latest_event().and_then(|e| EventTimelineItem::from_latest_event(self, e))
async fn latest_timeline_item(&self) -> Option<EventTimelineItem> {
let latest_event = self.latest_event()?;
EventTimelineItem::from_latest_event(self, latest_event).await
}
}
@@ -82,7 +83,7 @@ mod tests {
let room = SlidingSyncRoom::new(client, room_id, v4::SlidingSyncRoom::new(), Vec::new());
// When we ask for the latest event, it is None
assert!(room.latest_timeline_item().is_none());
assert!(room.latest_timeline_item().await.is_none());
}
#[async_test]
@@ -101,7 +102,7 @@ mod tests {
v4::SlidingSyncRoom::new(),
Vec::new(),
);
let actual = room.latest_timeline_item().unwrap();
let actual = room.latest_timeline_item().await.unwrap();
// Then it is wrapped as an EventTimelineItem
assert_eq!(actual.sender, user_id);