dont send read receipts and typing indicators from ignored users
Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
parent
fafe320899
commit
890ee84f71
4 changed files with 88 additions and 40 deletions
|
@ -1011,15 +1011,27 @@ async fn load_joined_room(
|
||||||
.rooms
|
.rooms
|
||||||
.read_receipt
|
.read_receipt
|
||||||
.readreceipts_since(room_id, since)
|
.readreceipts_since(room_id, since)
|
||||||
.map(|(_, _, v)| v)
|
.filter_map(|(read_user, _, v)| async move {
|
||||||
|
(!services
|
||||||
|
.users
|
||||||
|
.user_is_ignored(&read_user, sender_user)
|
||||||
|
.await)
|
||||||
|
.then_some(v)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if services.rooms.typing.last_typing_update(room_id).await? > since {
|
if services.rooms.typing.last_typing_update(room_id).await? > since {
|
||||||
edus.push(
|
edus.push(
|
||||||
serde_json::from_str(
|
serde_json::from_str(
|
||||||
&serde_json::to_string(&services.rooms.typing.typings_all(room_id).await?)
|
&serde_json::to_string(
|
||||||
.expect("event is valid, we just created it"),
|
&services
|
||||||
|
.rooms
|
||||||
|
.typing
|
||||||
|
.typings_all(room_id, sender_user)
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.expect("event is valid, we just created it"),
|
||||||
)
|
)
|
||||||
.expect("event is valid, we just created it"),
|
.expect("event is valid, we just created it"),
|
||||||
);
|
);
|
||||||
|
@ -1583,6 +1595,13 @@ pub(crate) async fn sync_events_v4_route(
|
||||||
.rooms
|
.rooms
|
||||||
.read_receipt
|
.read_receipt
|
||||||
.readreceipts_since(room_id, *roomsince)
|
.readreceipts_since(room_id, *roomsince)
|
||||||
|
.filter_map(|(read_user, ts, v)| async move {
|
||||||
|
(!services
|
||||||
|
.users
|
||||||
|
.user_is_ignored(&read_user, sender_user)
|
||||||
|
.await)
|
||||||
|
.then_some((read_user, ts, v))
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use itertools::Itertools;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
events::{
|
events::{
|
||||||
direct::DirectEvent,
|
direct::DirectEvent,
|
||||||
ignored_user_list::IgnoredUserListEvent,
|
|
||||||
room::{
|
room::{
|
||||||
create::RoomCreateEventContent,
|
create::RoomCreateEventContent,
|
||||||
member::{MembershipState, RoomMemberEventContent},
|
member::{MembershipState, RoomMemberEventContent},
|
||||||
|
@ -197,30 +196,7 @@ impl Service {
|
||||||
},
|
},
|
||||||
MembershipState::Invite => {
|
MembershipState::Invite => {
|
||||||
// We want to know if the sender is ignored by the receiver
|
// We want to know if the sender is ignored by the receiver
|
||||||
let is_ignored = self
|
if self.services.users.user_is_ignored(sender, user_id).await {
|
||||||
.services
|
|
||||||
.account_data
|
|
||||||
.get(
|
|
||||||
None, // Ignored users are in global account data
|
|
||||||
user_id, // Receiver
|
|
||||||
GlobalAccountDataEventType::IgnoredUserList
|
|
||||||
.to_string()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.and_then(|event| {
|
|
||||||
serde_json::from_str::<IgnoredUserListEvent>(event.get())
|
|
||||||
.map_err(|e| err!(Database(warn!("Invalid account data event in db: {e:?}"))))
|
|
||||||
})
|
|
||||||
.map_or(false, |ignored| {
|
|
||||||
ignored
|
|
||||||
.content
|
|
||||||
.ignored_users
|
|
||||||
.iter()
|
|
||||||
.any(|(user, _details)| user == sender)
|
|
||||||
});
|
|
||||||
|
|
||||||
if is_ignored {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
use conduit::{debug_info, trace, utils, Result, Server};
|
use conduit::{
|
||||||
|
debug_info, trace,
|
||||||
|
utils::{self, IterStream},
|
||||||
|
Result, Server,
|
||||||
|
};
|
||||||
|
use futures::StreamExt;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::federation::transactions::edu::{Edu, TypingContent},
|
api::federation::transactions::edu::{Edu, TypingContent},
|
||||||
events::SyncEphemeralRoomEvent,
|
events::SyncEphemeralRoomEvent,
|
||||||
|
@ -8,7 +13,7 @@ use ruma::{
|
||||||
};
|
};
|
||||||
use tokio::sync::{broadcast, RwLock};
|
use tokio::sync::{broadcast, RwLock};
|
||||||
|
|
||||||
use crate::{globals, sending, Dep};
|
use crate::{globals, sending, users, Dep};
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
server: Arc<Server>,
|
server: Arc<Server>,
|
||||||
|
@ -23,6 +28,7 @@ pub struct Service {
|
||||||
struct Services {
|
struct Services {
|
||||||
globals: Dep<globals::Service>,
|
globals: Dep<globals::Service>,
|
||||||
sending: Dep<sending::Service>,
|
sending: Dep<sending::Service>,
|
||||||
|
users: Dep<users::Service>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Service for Service {
|
impl crate::Service for Service {
|
||||||
|
@ -32,6 +38,7 @@ impl crate::Service for Service {
|
||||||
services: Services {
|
services: Services {
|
||||||
globals: args.depend::<globals::Service>("globals"),
|
globals: args.depend::<globals::Service>("globals"),
|
||||||
sending: args.depend::<sending::Service>("sending"),
|
sending: args.depend::<sending::Service>("sending"),
|
||||||
|
users: args.depend::<users::Service>("users"),
|
||||||
},
|
},
|
||||||
typing: RwLock::new(BTreeMap::new()),
|
typing: RwLock::new(BTreeMap::new()),
|
||||||
last_typing_update: RwLock::new(BTreeMap::new()),
|
last_typing_update: RwLock::new(BTreeMap::new()),
|
||||||
|
@ -170,17 +177,35 @@ impl Service {
|
||||||
|
|
||||||
/// Returns a new typing EDU.
|
/// Returns a new typing EDU.
|
||||||
pub async fn typings_all(
|
pub async fn typings_all(
|
||||||
&self, room_id: &RoomId,
|
&self, room_id: &RoomId, sender_user: &UserId,
|
||||||
) -> Result<SyncEphemeralRoomEvent<ruma::events::typing::TypingEventContent>> {
|
) -> Result<SyncEphemeralRoomEvent<ruma::events::typing::TypingEventContent>> {
|
||||||
|
let room_typing_indicators = self.typing.read().await.get(room_id).cloned();
|
||||||
|
|
||||||
|
let Some(typing_indicators) = room_typing_indicators else {
|
||||||
|
return Ok(SyncEphemeralRoomEvent {
|
||||||
|
content: ruma::events::typing::TypingEventContent {
|
||||||
|
user_ids: Vec::new(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_ids: Vec<_> = typing_indicators
|
||||||
|
.into_keys()
|
||||||
|
.stream()
|
||||||
|
.filter_map(|typing_user_id| async move {
|
||||||
|
(!self
|
||||||
|
.services
|
||||||
|
.users
|
||||||
|
.user_is_ignored(&typing_user_id, sender_user)
|
||||||
|
.await)
|
||||||
|
.then_some(typing_user_id)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
.await;
|
||||||
|
|
||||||
Ok(SyncEphemeralRoomEvent {
|
Ok(SyncEphemeralRoomEvent {
|
||||||
content: ruma::events::typing::TypingEventContent {
|
content: ruma::events::typing::TypingEventContent {
|
||||||
user_ids: self
|
user_ids,
|
||||||
.typing
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get(room_id)
|
|
||||||
.map(|m| m.keys().cloned().collect())
|
|
||||||
.unwrap_or_default(),
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ use futures::{pin_mut, FutureExt, Stream, StreamExt, TryFutureExt};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::client::{device::Device, error::ErrorKind, filter::FilterDefinition},
|
api::client::{device::Device, error::ErrorKind, filter::FilterDefinition},
|
||||||
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
|
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
|
||||||
events::{AnyToDeviceEvent, StateEventType},
|
events::{ignored_user_list::IgnoredUserListEvent, AnyToDeviceEvent, GlobalAccountDataEventType, StateEventType},
|
||||||
serde::Raw,
|
serde::Raw,
|
||||||
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedDeviceKeyId,
|
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedDeviceKeyId,
|
||||||
OwnedMxcUri, OwnedUserId, UInt, UserId,
|
OwnedMxcUri, OwnedUserId, UInt, UserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{admin, globals, rooms, Dep};
|
use crate::{account_data, admin, globals, rooms, Dep};
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
services: Services,
|
services: Services,
|
||||||
|
@ -25,6 +25,7 @@ pub struct Service {
|
||||||
|
|
||||||
struct Services {
|
struct Services {
|
||||||
server: Arc<Server>,
|
server: Arc<Server>,
|
||||||
|
account_data: Dep<account_data::Service>,
|
||||||
admin: Dep<admin::Service>,
|
admin: Dep<admin::Service>,
|
||||||
globals: Dep<globals::Service>,
|
globals: Dep<globals::Service>,
|
||||||
state_accessor: Dep<rooms::state_accessor::Service>,
|
state_accessor: Dep<rooms::state_accessor::Service>,
|
||||||
|
@ -58,6 +59,7 @@ impl crate::Service for Service {
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
services: Services {
|
services: Services {
|
||||||
server: args.server.clone(),
|
server: args.server.clone(),
|
||||||
|
account_data: args.depend::<account_data::Service>("account_data"),
|
||||||
admin: args.depend::<admin::Service>("admin"),
|
admin: args.depend::<admin::Service>("admin"),
|
||||||
globals: args.depend::<globals::Service>("globals"),
|
globals: args.depend::<globals::Service>("globals"),
|
||||||
state_accessor: args.depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
|
state_accessor: args.depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
|
||||||
|
@ -91,6 +93,32 @@ impl crate::Service for Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
|
/// Returns true/false based on whether the recipient/receiving user has
|
||||||
|
/// blocked the sender
|
||||||
|
pub async fn user_is_ignored(&self, sender_user: &UserId, recipient_user: &UserId) -> bool {
|
||||||
|
self.services
|
||||||
|
.account_data
|
||||||
|
.get(
|
||||||
|
None,
|
||||||
|
recipient_user,
|
||||||
|
GlobalAccountDataEventType::IgnoredUserList
|
||||||
|
.to_string()
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.and_then(|event| {
|
||||||
|
serde_json::from_str::<IgnoredUserListEvent>(event.get())
|
||||||
|
.map_err(|e| err!(Database(warn!("Invalid account data event in db: {e:?}"))))
|
||||||
|
})
|
||||||
|
.map_or(false, |ignored| {
|
||||||
|
ignored
|
||||||
|
.content
|
||||||
|
.ignored_users
|
||||||
|
.keys()
|
||||||
|
.any(|blocked_user| blocked_user == sender_user)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if a user is an admin
|
/// Check if a user is an admin
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn is_admin(&self, user_id: &UserId) -> bool { self.services.admin.user_is_admin(user_id).await }
|
pub async fn is_admin(&self, user_id: &UserId) -> bool { self.services.admin.user_is_admin(user_id).await }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue