use std::fmt::Write as _; use clap::Subcommand; use ruma::{events::room::message::RoomMessageEventContent, RoomAliasId, RoomId}; use crate::{service::admin::escape_html, services, Result}; #[cfg_attr(test, derive(Debug))] #[derive(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, /// The alias localpart to use (`alias`, not `#alias:servername.tld`) room_alias_localpart: String, }, /// - Remove an 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>, }, } pub(crate) async fn process(command: RoomAliasCommand, _body: Vec<&str>) -> Result { match command { RoomAliasCommand::Set { ref room_alias_localpart, .. } | RoomAliasCommand::Remove { ref room_alias_localpart, } | RoomAliasCommand::Which { ref room_alias_localpart, } => { 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))), }; match command { RoomAliasCommand::Set { force, room_id, .. } => match (force, services().rooms.alias.resolve_local_alias(&room_alias)) { (true, Ok(Some(id))) => match services().rooms.alias.set_alias(&room_alias, &room_id) { Ok(()) => Ok(RoomMessageEventContent::text_plain(format!( "Successfully overwrote alias (formerly {})", id ))), Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {}", err))), }, (false, Ok(Some(id))) => Ok(RoomMessageEventContent::text_plain(format!( "Refusing to overwrite in use alias for {}, use -f or --force to overwrite", id ))), (_, Ok(None)) => match services().rooms.alias.set_alias(&room_alias, &room_id) { Ok(()) => Ok(RoomMessageEventContent::text_plain("Successfully set alias")), Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {err}"))), }, (_, Err(err)) => Ok(RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {err}"))), }, RoomAliasCommand::Remove { .. } => match services().rooms.alias.resolve_local_alias(&room_alias) { Ok(Some(id)) => match services().rooms.alias.remove_alias(&room_alias) { Ok(()) => Ok(RoomMessageEventContent::text_plain(format!("Removed alias from {}", id))), Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Failed to remove alias: {}", err))), }, Ok(None) => Ok(RoomMessageEventContent::text_plain("Alias isn't in use.")), Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to lookup alias: {}", err))), }, RoomAliasCommand::Which { .. } => 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))), }, RoomAliasCommand::List { .. } => unreachable!(), } }, RoomAliasCommand::List { room_id, } => { if let Some(room_id) = room_id { let aliases = services() .rooms .alias .local_aliases_for_room(&room_id) .collect::, _>>(); match aliases { Ok(aliases) => { let plain_list = aliases.iter().fold(String::new(), |mut output, alias| { writeln!(output, "- {alias}").unwrap(); output }); let html_list = aliases.iter().fold(String::new(), |mut output, alias| { writeln!(output, "
  • {}
  • ", escape_html(alias.as_ref())).unwrap(); output }); let plain = format!("Aliases for {room_id}:\n{plain_list}"); let html = format!("Aliases for {room_id}:\n
      {html_list}
    "); Ok(RoomMessageEventContent::text_html(plain, html)) }, Err(err) => Ok(RoomMessageEventContent::text_plain(format!("Unable to list aliases: {}", err))), } } else { let aliases = services() .rooms .alias .all_local_aliases() .collect::, _>>(); match aliases { Ok(aliases) => { let server_name = services().globals.server_name(); let plain_list = aliases .iter() .fold(String::new(), |mut output, (alias, id)| { writeln!(output, "- `{alias}` -> #{id}:{server_name}").unwrap(); output }); let html_list = aliases .iter() .fold(String::new(), |mut output, (alias, id)| { writeln!( output, "
  • {} -> #{}:{}
  • ", escape_html(alias.as_ref()), escape_html(id.as_ref()), server_name ) .unwrap(); output }); let plain = format!("Aliases:\n{plain_list}"); let html = format!("Aliases:\n
      {html_list}
    "); Ok(RoomMessageEventContent::text_html(plain, html)) }, Err(e) => Ok(RoomMessageEventContent::text_plain(format!("Unable to list room aliases: {e}"))), } } }, } }