feat: Run visibility checks on bundled relations

This commit is contained in:
Jade Ellis
2025-12-21 17:12:35 +00:00
parent 11012a9ce1
commit 8586d747d1
3 changed files with 27 additions and 13 deletions
-2
View File
@@ -31,8 +31,6 @@ pub(crate) async fn get_threads_route(
.transpose()? .transpose()?
.unwrap_or_else(PduCount::max); .unwrap_or_else(PduCount::max);
// TODO: user_can_see_event and set_unsigned should be at the same level /
// function, so unsigned is only set for seen events.
let threads: Vec<(PduCount, PduEvent)> = services let threads: Vec<(PduCount, PduEvent)> = services
.rooms .rooms
.threads .threads
@@ -41,9 +41,6 @@ impl super::Service {
// The relations database code still handles the basic unsigned data // The relations database code still handles the basic unsigned data
// We don't want to recursively fetch relations // We don't want to recursively fetch relations
// TODO: Event visibility check
// TODO: ignored users?
if relations.is_empty() { if relations.is_empty() {
return Ok(None); return Ok(None);
} }
@@ -84,8 +81,17 @@ impl super::Service {
// Handle m.replace relations - find the most recent valid one (lazy load // Handle m.replace relations - find the most recent valid one (lazy load
// original event) // original event)
if !replace_events.is_empty() { if !replace_events.is_empty() {
if let Some(replacement) = if let Some(replacement) = Self::find_most_recent_valid_replacement(
Self::find_most_recent_valid_replacement(pdu, &replace_events).await? pdu,
&replace_events,
async |pdu: &PduEvent| {
self.services
.state_accessor
.user_can_see_event(user_id, &pdu.room_id_or_hash(), &pdu.event_id())
.await
},
)
.await?
{ {
bundled.replace = Some(Self::serialize_replacement(replacement)?); bundled.replace = Some(Self::serialize_replacement(replacement)?);
} }
@@ -124,6 +130,7 @@ impl super::Service {
async fn find_most_recent_valid_replacement<'a>( async fn find_most_recent_valid_replacement<'a>(
original_event: &PduEvent, original_event: &PduEvent,
replacement_events: &[&'a PdusIterItem], replacement_events: &[&'a PdusIterItem],
visible: impl AsyncFn(&PduEvent) -> bool,
) -> Result<Option<&'a PduEvent>> { ) -> Result<Option<&'a PduEvent>> {
// Filter valid replacements and find the maximum in a single pass // Filter valid replacements and find the maximum in a single pass
let mut result: Option<&PduEvent> = None; let mut result: Option<&PduEvent> = None;
@@ -136,17 +143,23 @@ impl super::Service {
continue; continue;
} }
result = Some(match result { let next = match result {
| None => pdu, | None => Some(pdu),
| Some(current) => { | Some(current) => {
// Compare by origin_server_ts first, then event_id lexicographically // Compare by origin_server_ts first, then event_id lexicographically
match pdu.origin_server_ts().cmp(&current.origin_server_ts()) { match pdu.origin_server_ts().cmp(&current.origin_server_ts()) {
| std::cmp::Ordering::Greater => pdu, | std::cmp::Ordering::Greater => Some(pdu),
| std::cmp::Ordering::Equal if pdu.event_id() > current.event_id() => pdu, | std::cmp::Ordering::Equal if pdu.event_id() > current.event_id() =>
| _ => current, Some(pdu),
| _ => None,
} }
}, },
}); };
if let Some(pdu) = next
&& visible(pdu).await
{
result = Some(pdu);
}
} }
Ok(result) Ok(result)
+3
View File
@@ -20,6 +20,7 @@ pub struct Service {
struct Services { struct Services {
short: Dep<rooms::short::Service>, short: Dep<rooms::short::Service>,
timeline: Dep<rooms::timeline::Service>, timeline: Dep<rooms::timeline::Service>,
state_accessor: Dep<rooms::state_accessor::Service>,
} }
impl crate::Service for Service { impl crate::Service for Service {
@@ -28,6 +29,8 @@ impl crate::Service for Service {
services: Services { services: Services {
short: args.depend::<rooms::short::Service>("rooms::short"), short: args.depend::<rooms::short::Service>("rooms::short"),
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"), timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
state_accessor: args
.depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
}, },
db: Data::new(&args), db: Data::new(&args),
})) }))