admin command to get rooms a remote user is in, remove unnecessary dedupe+sort

imagine this SQL query but in conduwuit:

select * from users_in_public_rooms where user_id like '%user_id%';

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-04-27 01:06:43 -04:00 committed by June
parent 450f15df4f
commit 61f813c187
3 changed files with 76 additions and 7 deletions

View file

@ -1,8 +1,13 @@
use std::fmt::Write as _; use std::fmt::Write as _;
use ruma::{events::room::message::RoomMessageEventContent, RoomId, ServerName}; use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId, ServerName, UserId};
use crate::{services, utils::HtmlEscape, Result}; use crate::{
service::admin::{escape_html, get_room_info},
services,
utils::HtmlEscape,
Result,
};
pub(crate) async fn disable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> { pub(crate) async fn disable_room(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
services().rooms.metadata.disable_room(&room_id, true)?; services().rooms.metadata.disable_room(&room_id, true)?;
@ -70,3 +75,60 @@ pub(crate) async fn fetch_support_well_known(
), ),
)) ))
} }
pub(crate) async fn remote_user_in_rooms(_body: Vec<&str>, user_id: Box<UserId>) -> Result<RoomMessageEventContent> {
if user_id.server_name() == services().globals.config.server_name {
return Ok(RoomMessageEventContent::text_plain(
"User belongs to our server, please use `list-joined-rooms` user admin command instead.",
));
}
if !services().users.exists(&user_id)? {
return Ok(RoomMessageEventContent::text_plain(
"Remote user does not exist in our database.",
));
}
let mut rooms: Vec<(OwnedRoomId, u64, String)> = services()
.rooms
.state_cache
.rooms_joined(&user_id)
.filter_map(Result::ok)
.map(|room_id| get_room_info(&room_id))
.collect();
if rooms.is_empty() {
return Ok(RoomMessageEventContent::text_plain("User is not in any rooms."));
}
rooms.sort_by_key(|r| r.1);
rooms.reverse();
let output_plain = format!(
"Rooms {user_id} shares with us:\n{}",
rooms
.iter()
.map(|(id, members, name)| format!("{id}\tMembers: {members}\tName: {name}"))
.collect::<Vec<_>>()
.join("\n")
);
let output_html = format!(
"<table><caption>Rooms {user_id} shares with \
us</caption>\n<tr><th>id</th>\t<th>members</th>\t<th>name</th></tr>\n{}</table>",
rooms
.iter()
.fold(String::new(), |mut output, (id, members, name)| {
writeln!(
output,
"<tr><td>{}</td>\t<td>{}</td>\t<td>{}</td></tr>",
escape_html(id.as_ref()),
members,
escape_html(name)
)
.unwrap();
output
})
);
Ok(RoomMessageEventContent::text_html(output_plain, output_html))
}

View file

@ -1,7 +1,9 @@
use clap::Subcommand; use clap::Subcommand;
use ruma::{events::room::message::RoomMessageEventContent, RoomId, ServerName}; use ruma::{events::room::message::RoomMessageEventContent, RoomId, ServerName, UserId};
use self::federation_commands::{disable_room, enable_room, fetch_support_well_known, incoming_federeation}; use self::federation_commands::{
disable_room, enable_room, fetch_support_well_known, incoming_federeation, remote_user_in_rooms,
};
use crate::Result; use crate::Result;
pub(crate) mod federation_commands; pub(crate) mod federation_commands;
@ -34,6 +36,11 @@ pub(crate) enum FederationCommand {
FetchSupportWellKnown { FetchSupportWellKnown {
server_name: Box<ServerName>, server_name: Box<ServerName>,
}, },
/// - Lists all the rooms we share/track with the specified *remote* user
RemoteUserInRooms {
user_id: Box<UserId>,
},
} }
pub(crate) async fn process(command: FederationCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> { pub(crate) async fn process(command: FederationCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
@ -48,5 +55,8 @@ pub(crate) async fn process(command: FederationCommand, body: Vec<&str>) -> Resu
FederationCommand::FetchSupportWellKnown { FederationCommand::FetchSupportWellKnown {
server_name, server_name,
} => fetch_support_well_known(body, server_name).await?, } => fetch_support_well_known(body, server_name).await?,
FederationCommand::RemoteUserInRooms {
user_id,
} => remote_user_in_rooms(body, user_id).await?,
}) })
} }

View file

@ -1,6 +1,5 @@
use std::{fmt::Write as _, sync::Arc}; use std::{fmt::Write as _, sync::Arc};
use itertools::Itertools;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, UserId}; use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, UserId};
use tracing::{error, info, warn}; use tracing::{error, info, warn};
@ -318,8 +317,6 @@ pub(crate) async fn list_joined_rooms(_body: Vec<&str>, user_id: String) -> Resu
.rooms_joined(&user_id) .rooms_joined(&user_id)
.filter_map(Result::ok) .filter_map(Result::ok)
.map(|room_id| get_room_info(&room_id)) .map(|room_id| get_room_info(&room_id))
.sorted_unstable()
.dedup()
.collect(); .collect();
if rooms.is_empty() { if rooms.is_empty() {