de-global services from admin

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-07-27 00:11:41 +00:00
parent 7a3cc3941e
commit 7e50db4193
37 changed files with 1131 additions and 1127 deletions

View file

@ -1,12 +1,49 @@
use std::fmt::Write;
use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId};
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId, RoomId};
use super::RoomAliasCommand;
use crate::{escape_html, services, Result};
use crate::{escape_html, Command};
pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
let server_user = &services().globals.server_user;
#[derive(Debug, Subcommand)]
pub(crate) enum RoomAliasCommand {
/// - Make an alias point to a room.
Set {
#[arg(short, long)]
/// Set the alias even if a room is already using it
force: bool,
/// The room id to set the alias on
room_id: Box<RoomId>,
/// The alias localpart to use (`alias`, not `#alias:servername.tld`)
room_alias_localpart: String,
},
/// - Remove a local alias
Remove {
/// The alias localpart to remove (`alias`, not `#alias:servername.tld`)
room_alias_localpart: String,
},
/// - Show which room is using an alias
Which {
/// The alias localpart to look up (`alias`, not
/// `#alias:servername.tld`)
room_alias_localpart: String,
},
/// - List aliases currently being used
List {
/// If set, only list the aliases for this room
room_id: Option<Box<RoomId>>,
},
}
pub(super) async fn process(command: RoomAliasCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
let services = context.services;
let server_user = &services.globals.server_user;
match command {
RoomAliasCommand::Set {
@ -19,7 +56,7 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
| RoomAliasCommand::Which {
ref room_alias_localpart,
} => {
let room_alias_str = format!("#{}:{}", room_alias_localpart, services().globals.server_name());
let room_alias_str = format!("#{}:{}", room_alias_localpart, services.globals.server_name());
let room_alias = match RoomAliasId::parse_box(room_alias_str) {
Ok(alias) => alias,
Err(err) => return Ok(RoomMessageEventContent::text_plain(format!("Failed to parse alias: {err}"))),
@ -29,8 +66,8 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
force,
room_id,
..
} => match (force, services().rooms.alias.resolve_local_alias(&room_alias)) {
(true, Ok(Some(id))) => match services()
} => match (force, services.rooms.alias.resolve_local_alias(&room_alias)) {
(true, Ok(Some(id))) => match services
.rooms
.alias
.set_alias(&room_alias, &room_id, server_user)
@ -43,7 +80,7 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
(false, Ok(Some(id))) => Ok(RoomMessageEventContent::text_plain(format!(
"Refusing to overwrite in use alias for {id}, use -f or --force to overwrite"
))),
(_, Ok(None)) => match services()
(_, Ok(None)) => match services
.rooms
.alias
.set_alias(&room_alias, &room_id, server_user)
@ -55,8 +92,8 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
},
RoomAliasCommand::Remove {
..
} => match services().rooms.alias.resolve_local_alias(&room_alias) {
Ok(Some(id)) => match services()
} => match services.rooms.alias.resolve_local_alias(&room_alias) {
Ok(Some(id)) => match services
.rooms
.alias
.remove_alias(&room_alias, server_user)
@ -70,7 +107,7 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
},
RoomAliasCommand::Which {
..
} => match services().rooms.alias.resolve_local_alias(&room_alias) {
} => match services.rooms.alias.resolve_local_alias(&room_alias) {
Ok(Some(id)) => Ok(RoomMessageEventContent::text_plain(format!("Alias resolves to {id}"))),
Ok(None) => Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {err}"))),
@ -84,7 +121,7 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
room_id,
} => {
if let Some(room_id) = room_id {
let aliases = services()
let aliases = services
.rooms
.alias
.local_aliases_for_room(&room_id)
@ -109,14 +146,14 @@ pub(super) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Resu
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to list aliases: {err}"))),
}
} else {
let aliases = services()
let aliases = services
.rooms
.alias
.all_local_aliases()
.collect::<Result<Vec<_>, _>>();
match aliases {
Ok(aliases) => {
let server_name = services().globals.server_name();
let server_name = services.globals.server_name();
let plain_list = aliases
.iter()
.fold(String::new(), |mut output, (alias, id)| {

View file

@ -1,15 +1,18 @@
use std::fmt::Write;
use conduit::Result;
use ruma::events::room::message::RoomMessageEventContent;
use crate::{escape_html, get_room_info, services, Result, PAGE_SIZE};
use crate::{admin_command, escape_html, get_room_info, PAGE_SIZE};
pub(super) async fn list(
_body: Vec<&str>, page: Option<usize>, exclude_disabled: bool, exclude_banned: bool,
#[admin_command]
pub(super) async fn list_rooms(
&self, page: Option<usize>, exclude_disabled: bool, exclude_banned: bool,
) -> Result<RoomMessageEventContent> {
// TODO: i know there's a way to do this with clap, but i can't seem to find it
let page = page.unwrap_or(1);
let mut rooms = services()
let mut rooms = self
.services
.rooms
.metadata
.iter_ids()
@ -18,7 +21,8 @@ pub(super) async fn list(
.ok()
.filter(|room_id| {
if exclude_disabled
&& services()
&& self
.services
.rooms
.metadata
.is_disabled(room_id)
@ -28,7 +32,8 @@ pub(super) async fn list(
}
if exclude_banned
&& services()
&& self
.services
.rooms
.metadata
.is_banned(room_id)
@ -39,7 +44,7 @@ pub(super) async fn list(
true
})
.map(|room_id| get_room_info(services(), &room_id))
.map(|room_id| get_room_info(self.services, &room_id))
})
.collect::<Vec<_>>();
rooms.sort_by_key(|r| r.1);

View file

@ -1,21 +1,43 @@
use std::fmt::Write;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId};
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomId};
use super::RoomDirectoryCommand;
use crate::{escape_html, get_room_info, services, Result, PAGE_SIZE};
use crate::{escape_html, get_room_info, Command, PAGE_SIZE};
pub(super) async fn process(command: RoomDirectoryCommand, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
#[derive(Debug, Subcommand)]
pub(crate) enum RoomDirectoryCommand {
/// - Publish a room to the room directory
Publish {
/// The room id of the room to publish
room_id: Box<RoomId>,
},
/// - Unpublish a room to the room directory
Unpublish {
/// The room id of the room to unpublish
room_id: Box<RoomId>,
},
/// - List rooms that are published
List {
page: Option<usize>,
},
}
pub(super) async fn process(command: RoomDirectoryCommand, context: &Command<'_>) -> Result<RoomMessageEventContent> {
let services = context.services;
match command {
RoomDirectoryCommand::Publish {
room_id,
} => match services().rooms.directory.set_public(&room_id) {
} => match services.rooms.directory.set_public(&room_id) {
Ok(()) => Ok(RoomMessageEventContent::text_plain("Room published")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to update room: {err}"))),
},
RoomDirectoryCommand::Unpublish {
room_id,
} => match services().rooms.directory.set_not_public(&room_id) {
} => match services.rooms.directory.set_not_public(&room_id) {
Ok(()) => Ok(RoomMessageEventContent::text_plain("Room unpublished")),
Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to update room: {err}"))),
},
@ -24,12 +46,12 @@ pub(super) async fn process(command: RoomDirectoryCommand, _body: Vec<&str>) ->
} => {
// TODO: i know there's a way to do this with clap, but i can't seem to find it
let page = page.unwrap_or(1);
let mut rooms = services()
let mut rooms = services
.rooms
.directory
.public_rooms()
.filter_map(Result::ok)
.map(|id: OwnedRoomId| get_room_info(services(), &id))
.map(|id: OwnedRoomId| get_room_info(services, &id))
.collect::<Vec<_>>();
rooms.sort_by_key(|r| r.1);
rooms.reverse();

View file

@ -1,22 +1,30 @@
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, RoomId};
use service::services;
use super::RoomInfoCommand;
use crate::Result;
use crate::{admin_command, admin_command_dispatch};
pub(super) async fn process(command: RoomInfoCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
RoomInfoCommand::ListJoinedMembers {
room_id,
} => list_joined_members(body, room_id).await,
RoomInfoCommand::ViewRoomTopic {
room_id,
} => view_room_topic(body, room_id).await,
}
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
pub(crate) enum RoomInfoCommand {
/// - List joined members in a room
ListJoinedMembers {
room_id: Box<RoomId>,
},
/// - Displays room topic
///
/// Room topics can be huge, so this is in its
/// own separate command
ViewRoomTopic {
room_id: Box<RoomId>,
},
}
async fn list_joined_members(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
let room_name = services()
#[admin_command]
async fn list_joined_members(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
let room_name = self
.services
.rooms
.state_accessor
.get_name(&room_id)
@ -24,7 +32,8 @@ async fn list_joined_members(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<R
.flatten()
.unwrap_or_else(|| room_id.to_string());
let members = services()
let members = self
.services
.rooms
.state_cache
.room_members(&room_id)
@ -35,7 +44,7 @@ async fn list_joined_members(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<R
.map(|user_id| {
(
user_id.clone(),
services()
self.services
.users
.displayname(&user_id)
.unwrap_or(None)
@ -58,8 +67,14 @@ async fn list_joined_members(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<R
Ok(RoomMessageEventContent::notice_markdown(output_plain))
}
async fn view_room_topic(_body: Vec<&str>, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
let Some(room_topic) = services().rooms.state_accessor.get_room_topic(&room_id)? else {
#[admin_command]
async fn view_room_topic(&self, room_id: Box<RoomId>) -> Result<RoomMessageEventContent> {
let Some(room_topic) = self
.services
.rooms
.state_accessor
.get_room_topic(&room_id)?
else {
return Ok(RoomMessageEventContent::text_plain("Room does not have a room topic set."));
};

View file

@ -1,19 +1,23 @@
mod room_alias_commands;
mod room_commands;
mod room_directory_commands;
mod room_info_commands;
mod room_moderation_commands;
mod alias;
mod commands;
mod directory;
mod info;
mod moderation;
use clap::Subcommand;
use conduit::Result;
use ruma::{events::room::message::RoomMessageEventContent, RoomId, RoomOrAliasId};
use self::room_commands::list;
use self::{
alias::RoomAliasCommand, directory::RoomDirectoryCommand, info::RoomInfoCommand, moderation::RoomModerationCommand,
};
use crate::admin_command_dispatch;
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
pub(super) enum RoomCommand {
/// - List all rooms the server knows about
List {
#[clap(alias = "list")]
ListRooms {
page: Option<usize>,
/// Excludes rooms that we have federation disabled with
@ -41,149 +45,3 @@ pub(super) enum RoomCommand {
/// - Manage the room directory
Directory(RoomDirectoryCommand),
}
#[derive(Debug, Subcommand)]
pub(super) enum RoomInfoCommand {
/// - List joined members in a room
ListJoinedMembers {
room_id: Box<RoomId>,
},
/// - Displays room topic
///
/// Room topics can be huge, so this is in its
/// own separate command
ViewRoomTopic {
room_id: Box<RoomId>,
},
}
#[derive(Debug, Subcommand)]
pub(super) enum RoomAliasCommand {
/// - Make an alias point to a room.
Set {
#[arg(short, long)]
/// Set the alias even if a room is already using it
force: bool,
/// The room id to set the alias on
room_id: Box<RoomId>,
/// The alias localpart to use (`alias`, not `#alias:servername.tld`)
room_alias_localpart: String,
},
/// - Remove a local alias
Remove {
/// The alias localpart to remove (`alias`, not `#alias:servername.tld`)
room_alias_localpart: String,
},
/// - Show which room is using an alias
Which {
/// The alias localpart to look up (`alias`, not
/// `#alias:servername.tld`)
room_alias_localpart: String,
},
/// - List aliases currently being used
List {
/// If set, only list the aliases for this room
room_id: Option<Box<RoomId>>,
},
}
#[derive(Debug, Subcommand)]
pub(super) enum RoomDirectoryCommand {
/// - Publish a room to the room directory
Publish {
/// The room id of the room to publish
room_id: Box<RoomId>,
},
/// - Unpublish a room to the room directory
Unpublish {
/// The room id of the room to unpublish
room_id: Box<RoomId>,
},
/// - List rooms that are published
List {
page: Option<usize>,
},
}
#[derive(Debug, Subcommand)]
pub(super) enum RoomModerationCommand {
/// - Bans a room from local users joining and evicts all our local users
/// from the room. Also blocks any invites (local and remote) for the
/// banned room.
///
/// Server admins (users in the conduwuit admin room) will not be evicted
/// and server admins can still join the room. To evict admins too, use
/// --force (also ignores errors) To disable incoming federation of the
/// room, use --disable-federation
BanRoom {
#[arg(short, long)]
/// Evicts admins out of the room and ignores any potential errors when
/// making our local users leave the room
force: bool,
#[arg(long)]
/// Disables incoming federation of the room after banning and evicting
/// users
disable_federation: bool,
/// The room in the format of `!roomid:example.com` or a room alias in
/// the format of `#roomalias:example.com`
room: Box<RoomOrAliasId>,
},
/// - Bans a list of rooms (room IDs and room aliases) from a newline
/// delimited codeblock similar to `user deactivate-all`
BanListOfRooms {
#[arg(short, long)]
/// Evicts admins out of the room and ignores any potential errors when
/// making our local users leave the room
force: bool,
#[arg(long)]
/// Disables incoming federation of the room after banning and evicting
/// users
disable_federation: bool,
},
/// - Unbans a room to allow local users to join again
///
/// To re-enable incoming federation of the room, use --enable-federation
UnbanRoom {
#[arg(long)]
/// Enables incoming federation of the room after unbanning
enable_federation: bool,
/// The room in the format of `!roomid:example.com` or a room alias in
/// the format of `#roomalias:example.com`
room: Box<RoomOrAliasId>,
},
/// - List of all rooms we have banned
ListBannedRooms,
}
pub(super) async fn process(command: RoomCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
Ok(match command {
RoomCommand::Info(command) => room_info_commands::process(command, body).await?,
RoomCommand::Alias(command) => room_alias_commands::process(command, body).await?,
RoomCommand::Directory(command) => room_directory_commands::process(command, body).await?,
RoomCommand::Moderation(command) => room_moderation_commands::process(command, body).await?,
RoomCommand::List {
page,
exclude_disabled,
exclude_banned,
} => list(body, page, exclude_disabled, exclude_banned).await?,
})
}

View file

@ -1,37 +1,77 @@
use api::client::leave_room;
use clap::Subcommand;
use conduit::{debug, error, info, warn, Result};
use ruma::{events::room::message::RoomMessageEventContent, OwnedRoomId, RoomAliasId, RoomId, RoomOrAliasId};
use super::RoomModerationCommand;
use crate::{get_room_info, services};
use crate::{admin_command, admin_command_dispatch, get_room_info};
pub(super) async fn process(command: RoomModerationCommand, body: Vec<&str>) -> Result<RoomMessageEventContent> {
match command {
RoomModerationCommand::BanRoom {
force,
room,
disable_federation,
} => ban_room(body, force, room, disable_federation).await,
RoomModerationCommand::BanListOfRooms {
force,
disable_federation,
} => ban_list_of_rooms(body, force, disable_federation).await,
RoomModerationCommand::UnbanRoom {
room,
enable_federation,
} => unban_room(body, room, enable_federation).await,
RoomModerationCommand::ListBannedRooms => list_banned_rooms(body).await,
}
#[admin_command_dispatch]
#[derive(Debug, Subcommand)]
pub(crate) enum RoomModerationCommand {
/// - Bans a room from local users joining and evicts all our local users
/// from the room. Also blocks any invites (local and remote) for the
/// banned room.
///
/// Server admins (users in the conduwuit admin room) will not be evicted
/// and server admins can still join the room. To evict admins too, use
/// --force (also ignores errors) To disable incoming federation of the
/// room, use --disable-federation
BanRoom {
#[arg(short, long)]
/// Evicts admins out of the room and ignores any potential errors when
/// making our local users leave the room
force: bool,
#[arg(long)]
/// Disables incoming federation of the room after banning and evicting
/// users
disable_federation: bool,
/// The room in the format of `!roomid:example.com` or a room alias in
/// the format of `#roomalias:example.com`
room: Box<RoomOrAliasId>,
},
/// - Bans a list of rooms (room IDs and room aliases) from a newline
/// delimited codeblock similar to `user deactivate-all`
BanListOfRooms {
#[arg(short, long)]
/// Evicts admins out of the room and ignores any potential errors when
/// making our local users leave the room
force: bool,
#[arg(long)]
/// Disables incoming federation of the room after banning and evicting
/// users
disable_federation: bool,
},
/// - Unbans a room to allow local users to join again
///
/// To re-enable incoming federation of the room, use --enable-federation
UnbanRoom {
#[arg(long)]
/// Enables incoming federation of the room after unbanning
enable_federation: bool,
/// The room in the format of `!roomid:example.com` or a room alias in
/// the format of `#roomalias:example.com`
room: Box<RoomOrAliasId>,
},
/// - List of all rooms we have banned
ListBannedRooms,
}
#[admin_command]
async fn ban_room(
_body: Vec<&str>, force: bool, room: Box<RoomOrAliasId>, disable_federation: bool,
&self, force: bool, disable_federation: bool, room: Box<RoomOrAliasId>,
) -> Result<RoomMessageEventContent> {
debug!("Got room alias or ID: {}", room);
let admin_room_alias = &services().globals.admin_alias;
let admin_room_alias = &self.services.globals.admin_alias;
if let Some(admin_room_id) = services().admin.get_admin_room()? {
if let Some(admin_room_id) = self.services.admin.get_admin_room()? {
if room.to_string().eq(&admin_room_id) || room.to_string().eq(admin_room_alias) {
return Ok(RoomMessageEventContent::text_plain("Not allowed to ban the admin room."));
}
@ -50,7 +90,7 @@ async fn ban_room(
debug!("Room specified is a room ID, banning room ID");
services().rooms.metadata.ban_room(&room_id, true)?;
self.services.rooms.metadata.ban_room(&room_id, true)?;
room_id
} else if room.is_room_alias_id() {
@ -69,12 +109,13 @@ async fn ban_room(
get_alias_helper to fetch room ID remotely"
);
let room_id = if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
let room_id = if let Some(room_id) = self.services.rooms.alias.resolve_local_alias(&room_alias)? {
room_id
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
match services()
match self
.services
.rooms
.alias
.resolve_alias(&room_alias, None)
@ -92,7 +133,7 @@ async fn ban_room(
}
};
services().rooms.metadata.ban_room(&room_id, true)?;
self.services.rooms.metadata.ban_room(&room_id, true)?;
room_id
} else {
@ -104,20 +145,21 @@ async fn ban_room(
debug!("Making all users leave the room {}", &room);
if force {
for local_user in services()
for local_user in self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
services().globals.user_is_local(local_user)
self.services.globals.user_is_local(local_user)
// additional wrapped check here is to avoid adding remote users
// who are in the admin room to the list of local users (would
// fail auth check)
&& (services().globals.user_is_local(local_user)
&& (self.services.globals.user_is_local(local_user)
// since this is a force operation, assume user is an admin
// if somehow this fails
&& services()
&& self.services
.users
.is_admin(local_user)
.unwrap_or(true))
@ -128,30 +170,31 @@ async fn ban_room(
&local_user, &room_id
);
if let Err(e) = leave_room(services(), &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
warn!(%e, "Failed to leave room");
}
}
} else {
for local_user in services()
for local_user in self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
local_user.server_name() == services().globals.server_name()
local_user.server_name() == self.services.globals.server_name()
// additional wrapped check here is to avoid adding remote users
// who are in the admin room to the list of local users (would fail auth check)
&& (local_user.server_name()
== services().globals.server_name()
&& !services()
== self.services.globals.server_name()
&& !self.services
.users
.is_admin(local_user)
.unwrap_or(false))
})
}) {
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
if let Err(e) = leave_room(services(), &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
error!(
"Error attempting to make local user {} leave room {} during room banning: {}",
&local_user, &room_id, e
@ -166,7 +209,7 @@ async fn ban_room(
}
if disable_federation {
services().rooms.metadata.disable_room(&room_id, true)?;
self.services.rooms.metadata.disable_room(&room_id, true)?;
return Ok(RoomMessageEventContent::text_plain(
"Room banned, removed all our local users, and disabled incoming federation with room.",
));
@ -178,19 +221,22 @@ async fn ban_room(
))
}
async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: bool) -> Result<RoomMessageEventContent> {
if body.len() < 2 || !body[0].trim().starts_with("```") || body.last().unwrap_or(&"").trim() != "```" {
#[admin_command]
async fn ban_list_of_rooms(&self, force: bool, disable_federation: bool) -> Result<RoomMessageEventContent> {
if self.body.len() < 2 || !self.body[0].trim().starts_with("```") || self.body.last().unwrap_or(&"").trim() != "```"
{
return Ok(RoomMessageEventContent::text_plain(
"Expected code block in command body. Add --help for details.",
));
}
let rooms_s = body
.clone()
.drain(1..body.len().saturating_sub(1))
let rooms_s = self
.body
.to_vec()
.drain(1..self.body.len().saturating_sub(1))
.collect::<Vec<_>>();
let admin_room_alias = &services().globals.admin_alias;
let admin_room_alias = &self.services.globals.admin_alias;
let mut room_ban_count: usize = 0;
let mut room_ids: Vec<OwnedRoomId> = Vec::new();
@ -198,7 +244,7 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
for &room in &rooms_s {
match <&RoomOrAliasId>::try_from(room) {
Ok(room_alias_or_id) => {
if let Some(admin_room_id) = services().admin.get_admin_room()? {
if let Some(admin_room_id) = self.services.admin.get_admin_room()? {
if room.to_owned().eq(&admin_room_id) || room.to_owned().eq(admin_room_alias) {
info!("User specified admin room in bulk ban list, ignoring");
continue;
@ -231,7 +277,7 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
match RoomAliasId::parse(room_alias_or_id) {
Ok(room_alias) => {
let room_id =
if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
if let Some(room_id) = self.services.rooms.alias.resolve_local_alias(&room_alias)? {
room_id
} else {
debug!(
@ -239,7 +285,8 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
ID over federation"
);
match services()
match self
.services
.rooms
.alias
.resolve_alias(&room_alias, None)
@ -303,28 +350,35 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
}
for room_id in room_ids {
if services().rooms.metadata.ban_room(&room_id, true).is_ok() {
if self
.services
.rooms
.metadata
.ban_room(&room_id, true)
.is_ok()
{
debug!("Banned {room_id} successfully");
room_ban_count = room_ban_count.saturating_add(1);
}
debug!("Making all users leave the room {}", &room_id);
if force {
for local_user in services()
for local_user in self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
local_user.server_name() == services().globals.server_name()
local_user.server_name() == self.services.globals.server_name()
// additional wrapped check here is to avoid adding remote
// users who are in the admin room to the list of local
// users (would fail auth check)
&& (local_user.server_name()
== services().globals.server_name()
== self.services.globals.server_name()
// since this is a force operation, assume user is an
// admin if somehow this fails
&& services()
&& self.services
.users
.is_admin(local_user)
.unwrap_or(true))
@ -334,31 +388,32 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
"Attempting leave for user {} in room {} (forced, ignoring all errors, evicting admins too)",
&local_user, room_id
);
if let Err(e) = leave_room(services(), &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
warn!(%e, "Failed to leave room");
}
}
} else {
for local_user in services()
for local_user in self
.services
.rooms
.state_cache
.room_members(&room_id)
.filter_map(|user| {
user.ok().filter(|local_user| {
local_user.server_name() == services().globals.server_name()
local_user.server_name() == self.services.globals.server_name()
// additional wrapped check here is to avoid adding remote
// users who are in the admin room to the list of local
// users (would fail auth check)
&& (local_user.server_name()
== services().globals.server_name()
&& !services()
== self.services.globals.server_name()
&& !self.services
.users
.is_admin(local_user)
.unwrap_or(false))
})
}) {
debug!("Attempting leave for user {} in room {}", &local_user, &room_id);
if let Err(e) = leave_room(services(), &local_user, &room_id, None).await {
if let Err(e) = leave_room(self.services, &local_user, &room_id, None).await {
error!(
"Error attempting to make local user {} leave room {} during bulk room banning: {}",
&local_user, &room_id, e
@ -374,7 +429,7 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
}
if disable_federation {
services().rooms.metadata.disable_room(&room_id, true)?;
self.services.rooms.metadata.disable_room(&room_id, true)?;
}
}
@ -390,9 +445,8 @@ async fn ban_list_of_rooms(body: Vec<&str>, force: bool, disable_federation: boo
}
}
async fn unban_room(
_body: Vec<&str>, room: Box<RoomOrAliasId>, enable_federation: bool,
) -> Result<RoomMessageEventContent> {
#[admin_command]
async fn unban_room(&self, enable_federation: bool, room: Box<RoomOrAliasId>) -> Result<RoomMessageEventContent> {
let room_id = if room.is_room_id() {
let room_id = match RoomId::parse(&room) {
Ok(room_id) => room_id,
@ -406,7 +460,7 @@ async fn unban_room(
debug!("Room specified is a room ID, unbanning room ID");
services().rooms.metadata.ban_room(&room_id, false)?;
self.services.rooms.metadata.ban_room(&room_id, false)?;
room_id
} else if room.is_room_alias_id() {
@ -425,12 +479,13 @@ async fn unban_room(
get_alias_helper to fetch room ID remotely"
);
let room_id = if let Some(room_id) = services().rooms.alias.resolve_local_alias(&room_alias)? {
let room_id = if let Some(room_id) = self.services.rooms.alias.resolve_local_alias(&room_alias)? {
room_id
} else {
debug!("We don't have this room alias to a room ID locally, attempting to fetch room ID over federation");
match services()
match self
.services
.rooms
.alias
.resolve_alias(&room_alias, None)
@ -448,7 +503,7 @@ async fn unban_room(
}
};
services().rooms.metadata.ban_room(&room_id, false)?;
self.services.rooms.metadata.ban_room(&room_id, false)?;
room_id
} else {
@ -459,7 +514,7 @@ async fn unban_room(
};
if enable_federation {
services().rooms.metadata.disable_room(&room_id, false)?;
self.services.rooms.metadata.disable_room(&room_id, false)?;
return Ok(RoomMessageEventContent::text_plain("Room unbanned."));
}
@ -469,8 +524,10 @@ async fn unban_room(
))
}
async fn list_banned_rooms(_body: Vec<&str>) -> Result<RoomMessageEventContent> {
let rooms = services()
#[admin_command]
async fn list_banned_rooms(&self) -> Result<RoomMessageEventContent> {
let rooms = self
.services
.rooms
.metadata
.list_banned_rooms()
@ -484,7 +541,7 @@ async fn list_banned_rooms(_body: Vec<&str>) -> Result<RoomMessageEventContent>
let mut rooms = room_ids
.into_iter()
.map(|room_id| get_room_info(services(), &room_id))
.map(|room_id| get_room_info(self.services, &room_id))
.collect::<Vec<_>>();
rooms.sort_by_key(|r| r.1);
rooms.reverse();