sdk: Get push actions of events received via back pagination

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
Kévin Commaille
2023-03-14 12:13:29 +01:00
committed by Jonas Platte
parent aebd5fe4eb
commit cc585974e0
2 changed files with 151 additions and 1 deletions

View File

@@ -28,10 +28,12 @@ use ruma::{
assign,
events::{
direct::DirectEventContent,
push_rules::PushRulesEventContent,
receipt::{Receipt, ReceiptThread, ReceiptType},
room::{
encryption::RoomEncryptionEventContent, history_visibility::HistoryVisibility,
server_acl::RoomServerAclEventContent, MediaSource,
power_levels::RoomPowerLevelsEventContent, server_acl::RoomServerAclEventContent,
MediaSource,
},
tag::{TagInfo, TagName},
AnyRoomAccountDataEvent, AnyStateEvent, AnySyncStateEvent, EmptyStateKey, RedactContent,
@@ -39,6 +41,7 @@ use ruma::{
RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
SyncStateEvent,
},
push::{PushConditionRoomCtx, Ruleset},
serde::Raw,
uint, EventId, MatrixToUri, MatrixUri, OwnedEventId, OwnedServerName, OwnedUserId, RoomId,
UInt, UserId,
@@ -236,6 +239,20 @@ impl Common {
response.chunk.extend(http_response.chunk.into_iter().map(TimelineEvent::new));
}
if let Some(push_context) = self.push_context().await? {
let push_rules = self
.client()
.account()
.account_data::<PushRulesEventContent>()
.await?
.and_then(|r| r.deserialize().ok().map(|r| r.global))
.unwrap_or_else(|| Ruleset::server_default(self.own_user_id()));
for event in &mut response.chunk {
event.push_actions = push_rules.get_actions(&event.event, &push_context).to_owned();
}
}
Ok(response)
}
@@ -1008,6 +1025,43 @@ impl Common {
) -> Result<Vec<(OwnedUserId, Receipt)>> {
self.inner.event_receipts(receipt_type, thread, event_id).await.map_err(Into::into)
}
/// Get the push context for this room.
///
/// Returns `None` if some data couldn't be found. This should only happen
/// in brand new rooms, while we process its state.
async fn push_context(&self) -> Result<Option<PushConditionRoomCtx>> {
let room_id = self.room_id();
let user_id = self.own_user_id();
let room_info = self.clone_info();
let member_count = room_info.active_members_count();
let user_display_name = if let Some(member) = self.get_member_no_sync(user_id).await? {
member.name().to_owned()
} else {
return Ok(None);
};
let room_power_levels = if let Some(event) = self
.get_state_event_static::<RoomPowerLevelsEventContent>()
.await?
.and_then(|e| e.deserialize().ok())
{
event.power_levels()
} else {
return Ok(None);
};
Ok(Some(PushConditionRoomCtx {
user_id: user_id.to_owned(),
room_id: room_id.to_owned(),
member_count: UInt::new(member_count).unwrap_or(UInt::MAX),
user_display_name,
users_power_levels: room_power_levels.users,
default_power_level: room_power_levels.users_default,
notification_power_levels: room_power_levels.notifications,
}))
}
}
/// Options for [`messages`][Common::messages].

View File

@@ -812,3 +812,99 @@ async fn sync_highlighted() {
// `m.room.tombstone` should be highlighted by default.
assert!(remote_event.is_highlighted());
}
#[async_test]
async fn back_pagination_highlighted() {
let room_id = room_id!("!a98sd12bjh:example.org");
let (client, server) = logged_in_client().await;
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
let mut ev_builder = EventBuilder::new();
ev_builder
// We need the member event and power levels locally so the push rules processor works.
.add_joined_room(
JoinedRoomBuilder::new(room_id)
.add_state_event(StateTestEvent::Member)
.add_state_event(StateTestEvent::PowerLevels),
);
mock_sync(&server, ev_builder.build_json_sync_response(), None).await;
let _response = client.sync_once(sync_settings.clone()).await.unwrap();
server.reset().await;
let room = client.get_room(room_id).unwrap();
let timeline = Arc::new(room.timeline().await);
let (_, mut timeline_stream) = timeline.subscribe().await;
let response_json = json!({
"chunk": [
{
"content": {
"body": "hello",
"msgtype": "m.text",
},
"event_id": "$msda7m0df9E9op3",
"origin_server_ts": 152037280,
"sender": "@example:localhost",
"type": "m.room.message",
"room_id": room_id,
},
{
"content": {
"body": "This room has been replaced",
"replacement_room": "!newroom:localhost",
},
"event_id": "$foun39djjod0f",
"origin_server_ts": 152039280,
"sender": "@bob:localhost",
"state_key": "",
"type": "m.room.tombstone",
"room_id": room_id,
},
],
"end": "t47409-4357353_219380_26003_2269",
"start": "t392-516_47314_0_7_1_1_1_11444_1"
});
Mock::given(method("GET"))
.and(path_regex(r"^/_matrix/client/r0/rooms/.*/messages$"))
.and(header("authorization", "Bearer 1234"))
.respond_with(ResponseTemplate::new(200).set_body_json(response_json))
.expect(1)
.named("messages_batch_1")
.mount(&server)
.await;
timeline.paginate_backwards(PaginationOptions::single_request(10)).await.unwrap();
server.reset().await;
let loading = assert_matches!(
timeline_stream.next().await,
Some(VectorDiff::PushFront { value }) => value
);
assert_matches!(loading.as_virtual().unwrap(), VirtualTimelineItem::LoadingIndicator);
let day_divider = assert_matches!(
timeline_stream.next().await,
Some(VectorDiff::Insert { index: 1, value }) => value
);
assert_matches!(day_divider.as_virtual().unwrap(), VirtualTimelineItem::DayDivider(_));
let first = assert_matches!(
timeline_stream.next().await,
Some(VectorDiff::Insert { index: 2, value }) => value
);
let remote_event = first.as_event().unwrap().as_remote().unwrap();
// Own events don't trigger push rules.
assert!(!remote_event.is_highlighted());
let second = assert_matches!(
timeline_stream.next().await,
Some(VectorDiff::Insert { index: 2, value }) => value
);
let remote_event = second.as_event().unwrap().as_remote().unwrap();
// `m.room.tombstone` should be highlighted by default.
assert!(remote_event.is_highlighted());
// Removal of the loading indicator
assert_matches!(timeline_stream.next().await, Some(VectorDiff::PopFront));
}