mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Implement set/unset/show for alternative and canonical aliases (#279)
This commit is contained in:
parent
9a1adfb287
commit
4571788678
4 changed files with 277 additions and 2 deletions
20
src/base.rs
20
src/base.rs
|
@ -369,6 +369,15 @@ pub enum RoomField {
|
|||
|
||||
/// The room topic.
|
||||
Topic,
|
||||
|
||||
/// The room's entire list of alternative aliases.
|
||||
Aliases,
|
||||
|
||||
/// A specific alternative alias to the room.
|
||||
Alias(String),
|
||||
|
||||
/// The room's canonical alias.
|
||||
CanonicalAlias,
|
||||
}
|
||||
|
||||
/// An action that operates on a focused room.
|
||||
|
@ -397,6 +406,9 @@ pub enum RoomAction {
|
|||
|
||||
/// Unset a room property.
|
||||
Unset(RoomField),
|
||||
|
||||
/// List the values in a list room property.
|
||||
Show(RoomField),
|
||||
}
|
||||
|
||||
/// An action that sends a message to a room.
|
||||
|
@ -596,6 +608,10 @@ pub enum IambError {
|
|||
#[error("Invalid user identifier: {0}")]
|
||||
InvalidUserId(String),
|
||||
|
||||
/// An invalid user identifier was specified.
|
||||
#[error("Invalid room alias: {0}")]
|
||||
InvalidRoomAlias(String),
|
||||
|
||||
/// An invalid verification identifier was specified.
|
||||
#[error("Invalid verification user/device pair: {0}")]
|
||||
InvalidVerificationId(String),
|
||||
|
@ -659,6 +675,10 @@ pub enum IambError {
|
|||
#[error("Unknown room identifier: {0}")]
|
||||
UnknownRoom(OwnedRoomId),
|
||||
|
||||
/// An invalid room alias id was specified.
|
||||
#[error("Invalid room alias id: {0}")]
|
||||
InvalidRoomAliasId(#[from] matrix_sdk::ruma::IdParseError),
|
||||
|
||||
/// A failure occurred during verification.
|
||||
#[error("Verification request error: {0}")]
|
||||
VerificationRequestError(#[from] matrix_sdk::encryption::identities::RequestVerificationError),
|
||||
|
|
|
@ -454,6 +454,42 @@ fn iamb_room(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
|||
("tag", "unset", Some(s)) => RoomAction::Unset(RoomField::Tag(tag_name(s)?)).into(),
|
||||
("tag", "unset", None) => return Result::Err(CommandError::InvalidArgument),
|
||||
|
||||
// :room aliases show
|
||||
("alias", "show", None) => RoomAction::Show(RoomField::Aliases).into(),
|
||||
("alias", "show", Some(_)) => return Result::Err(CommandError::InvalidArgument),
|
||||
|
||||
// :room aliases unset <alias>
|
||||
("alias", "unset", Some(s)) => RoomAction::Unset(RoomField::Alias(s)).into(),
|
||||
("alias", "unset", None) => return Result::Err(CommandError::InvalidArgument),
|
||||
|
||||
// :room aliases set <alias>
|
||||
("alias", "set", Some(s)) => RoomAction::Set(RoomField::Alias(s), "".into()).into(),
|
||||
("alias", "set", None) => return Result::Err(CommandError::InvalidArgument),
|
||||
|
||||
// :room canonicalalias show
|
||||
("canonicalalias" | "canon", "show", None) => {
|
||||
RoomAction::Show(RoomField::CanonicalAlias).into()
|
||||
},
|
||||
("canonicalalias" | "canon", "show", Some(_)) => {
|
||||
return Result::Err(CommandError::InvalidArgument)
|
||||
},
|
||||
|
||||
// :room canonicalalias set
|
||||
("canonicalalias" | "canon", "set", Some(s)) => {
|
||||
RoomAction::Set(RoomField::CanonicalAlias, s).into()
|
||||
},
|
||||
("canonicalalias" | "canon", "set", None) => {
|
||||
return Result::Err(CommandError::InvalidArgument)
|
||||
},
|
||||
|
||||
// :room canonicalalias unset
|
||||
("canonicalalias" | "canon", "unset", None) => {
|
||||
RoomAction::Unset(RoomField::CanonicalAlias).into()
|
||||
},
|
||||
("canonicalalias" | "canon", "unset", Some(_)) => {
|
||||
return Result::Err(CommandError::InvalidArgument)
|
||||
},
|
||||
|
||||
_ => return Result::Err(CommandError::InvalidArgument),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
//! # Windows for Matrix rooms and spaces
|
||||
use std::collections::HashSet;
|
||||
|
||||
use matrix_sdk::{
|
||||
room::Room as MatrixRoom,
|
||||
ruma::{
|
||||
api::client::{
|
||||
alias::{
|
||||
create_alias::v3::Request as CreateAliasRequest,
|
||||
delete_alias::v3::Request as DeleteAliasRequest,
|
||||
},
|
||||
error::ErrorKind as ClientApiErrorKind,
|
||||
},
|
||||
events::{
|
||||
room::{name::RoomNameEventContent, topic::RoomTopicEventContent},
|
||||
room::{
|
||||
canonical_alias::RoomCanonicalAliasEventContent,
|
||||
name::RoomNameEventContent,
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
tag::{TagInfo, Tags},
|
||||
},
|
||||
OwnedEventId,
|
||||
OwnedRoomAliasId,
|
||||
RoomId,
|
||||
},
|
||||
DisplayName,
|
||||
|
@ -53,6 +67,8 @@ use crate::base::{
|
|||
use self::chat::ChatState;
|
||||
use self::space::{Space, SpaceState};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
mod chat;
|
||||
mod scrollback;
|
||||
mod space;
|
||||
|
@ -182,7 +198,7 @@ impl RoomState {
|
|||
pub async fn room_command(
|
||||
&mut self,
|
||||
act: RoomAction,
|
||||
_: ProgramContext,
|
||||
ctx: ProgramContext,
|
||||
store: &mut ProgramStore,
|
||||
) -> IambResult<Vec<(Action<IambInfo>, ProgramContext)>> {
|
||||
match act {
|
||||
|
@ -280,6 +296,87 @@ impl RoomState {
|
|||
let ev = RoomTopicEventContent::new(value);
|
||||
let _ = room.send_state_event(ev).await.map_err(IambError::from)?;
|
||||
},
|
||||
RoomField::CanonicalAlias => {
|
||||
let client = &mut store.application.worker.client;
|
||||
|
||||
let Ok(orai) = OwnedRoomAliasId::try_from(value.as_str()) else {
|
||||
let err = IambError::InvalidRoomAlias(value);
|
||||
|
||||
return Err(err.into());
|
||||
};
|
||||
|
||||
let mut alt_aliases =
|
||||
room.alt_aliases().into_iter().collect::<HashSet<_>>();
|
||||
let canonical_old = room.canonical_alias();
|
||||
|
||||
// If the room's alias is already that, ignore it
|
||||
if canonical_old.as_ref() == Some(&orai) {
|
||||
let msg = format!("The canonical room alias is already {orai}");
|
||||
|
||||
return Ok(vec![(Action::ShowInfoMessage(msg.into()), ctx)]);
|
||||
}
|
||||
|
||||
// Try creating the room alias on the server.
|
||||
let alias_create_req =
|
||||
CreateAliasRequest::new(orai.clone(), room.room_id().into());
|
||||
if let Err(e) = client.send(alias_create_req, None).await {
|
||||
if let Some(ClientApiErrorKind::Unknown) = e.client_api_error_kind() {
|
||||
// Ignore when it already exists.
|
||||
} else {
|
||||
return Err(IambError::from(e).into());
|
||||
}
|
||||
}
|
||||
|
||||
// Demote the previous one to an alt alias.
|
||||
alt_aliases.extend(canonical_old);
|
||||
|
||||
// At this point the room alias definitely exists, and we can update the
|
||||
// state event.
|
||||
let mut ev = RoomCanonicalAliasEventContent::new();
|
||||
ev.alias = Some(orai);
|
||||
ev.alt_aliases = alt_aliases.into_iter().collect();
|
||||
let _ = room.send_state_event(ev).await.map_err(IambError::from)?;
|
||||
},
|
||||
RoomField::Alias(alias) => {
|
||||
let client = &mut store.application.worker.client;
|
||||
|
||||
let Ok(orai) = OwnedRoomAliasId::try_from(alias.as_str()) else {
|
||||
let err = IambError::InvalidRoomAlias(alias);
|
||||
|
||||
return Err(err.into());
|
||||
};
|
||||
|
||||
let mut alt_aliases =
|
||||
room.alt_aliases().into_iter().collect::<HashSet<_>>();
|
||||
let canonical = room.canonical_alias();
|
||||
|
||||
if alt_aliases.contains(&orai) || canonical.as_ref() == Some(&orai) {
|
||||
let msg = format!("The alias {orai} already maps to this room");
|
||||
|
||||
return Ok(vec![(Action::ShowInfoMessage(msg.into()), ctx)]);
|
||||
} else {
|
||||
alt_aliases.insert(orai.clone());
|
||||
}
|
||||
|
||||
// If the room alias does not exist on the server, create it
|
||||
let alias_create_req = CreateAliasRequest::new(orai, room.room_id().into());
|
||||
if let Err(e) = client.send(alias_create_req, None).await {
|
||||
if let Some(ClientApiErrorKind::Unknown) = e.client_api_error_kind() {
|
||||
// Ignore when it already exists.
|
||||
} else {
|
||||
return Err(IambError::from(e).into());
|
||||
}
|
||||
}
|
||||
|
||||
// And add it to the aliases in the state event.
|
||||
let mut ev = RoomCanonicalAliasEventContent::new();
|
||||
ev.alias = canonical;
|
||||
ev.alt_aliases = alt_aliases.into_iter().collect();
|
||||
let _ = room.send_state_event(ev).await.map_err(IambError::from)?;
|
||||
},
|
||||
RoomField::Aliases => {
|
||||
// This never happens, aliases is only used for showing
|
||||
},
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
|
@ -302,10 +399,120 @@ impl RoomState {
|
|||
let ev = RoomTopicEventContent::new("".into());
|
||||
let _ = room.send_state_event(ev).await.map_err(IambError::from)?;
|
||||
},
|
||||
RoomField::CanonicalAlias => {
|
||||
let Some(alias_to_destroy) = room.canonical_alias() else {
|
||||
let msg = format!("This room has no canonical alias to unset");
|
||||
|
||||
return Ok(vec![(Action::ShowInfoMessage(msg.into()), ctx)]);
|
||||
};
|
||||
|
||||
// Remove the canonical alias from the state event.
|
||||
let mut ev = RoomCanonicalAliasEventContent::new();
|
||||
ev.alias = None;
|
||||
ev.alt_aliases = room.alt_aliases();
|
||||
let _ = room.send_state_event(ev).await.map_err(IambError::from)?;
|
||||
|
||||
// And then unmap it on the server.
|
||||
let del_req = DeleteAliasRequest::new(alias_to_destroy);
|
||||
let _ = store
|
||||
.application
|
||||
.worker
|
||||
.client
|
||||
.send(del_req, None)
|
||||
.await
|
||||
.map_err(IambError::from)?;
|
||||
},
|
||||
RoomField::Alias(alias) => {
|
||||
let Ok(orai) = OwnedRoomAliasId::try_from(alias.as_str()) else {
|
||||
let err = IambError::InvalidRoomAlias(alias);
|
||||
|
||||
return Err(err.into());
|
||||
};
|
||||
|
||||
let alt_aliases = room.alt_aliases();
|
||||
let canonical = room.canonical_alias();
|
||||
|
||||
if !alt_aliases.contains(&orai) && canonical.as_ref() != Some(&orai) {
|
||||
let msg = format!("The alias {orai:?} isn't mapped to this room");
|
||||
|
||||
return Ok(vec![(Action::ShowInfoMessage(msg.into()), ctx)]);
|
||||
}
|
||||
|
||||
// Remove the alias from the state event if it's in it.
|
||||
let mut ev = RoomCanonicalAliasEventContent::new();
|
||||
ev.alias = canonical.filter(|canon| canon != &orai);
|
||||
ev.alt_aliases = alt_aliases;
|
||||
ev.alt_aliases.retain(|in_orai| in_orai != &orai);
|
||||
let _ = room.send_state_event(ev).await.map_err(IambError::from)?;
|
||||
|
||||
// And then unmap it on the server.
|
||||
let del_req = DeleteAliasRequest::new(orai);
|
||||
let _ = store
|
||||
.application
|
||||
.worker
|
||||
.client
|
||||
.send(del_req, None)
|
||||
.await
|
||||
.map_err(IambError::from)?;
|
||||
},
|
||||
RoomField::Aliases => {
|
||||
// This will not happen, you cannot unset all aliases
|
||||
},
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
},
|
||||
RoomAction::Show(field) => {
|
||||
let room = store
|
||||
.application
|
||||
.get_joined_room(self.id())
|
||||
.ok_or(UIError::Application(IambError::NotJoined))?;
|
||||
|
||||
let msg = match field {
|
||||
RoomField::Name => {
|
||||
match room.name() {
|
||||
None => "Room has no name".into(),
|
||||
Some(name) => format!("Room name: {name:?}"),
|
||||
}
|
||||
},
|
||||
RoomField::Topic => {
|
||||
match room.topic() {
|
||||
None => "Room has no topic".into(),
|
||||
Some(topic) => format!("Room topic: {topic:?}"),
|
||||
}
|
||||
},
|
||||
RoomField::Aliases => {
|
||||
let aliases = room
|
||||
.alt_aliases()
|
||||
.iter()
|
||||
.map(OwnedRoomAliasId::to_string)
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
if aliases.is_empty() {
|
||||
"No alternative aliases in room".into()
|
||||
} else {
|
||||
format!("Alternative aliases: {}.", aliases.join(", "))
|
||||
}
|
||||
},
|
||||
RoomField::CanonicalAlias => {
|
||||
match room.canonical_alias() {
|
||||
None => "No canonical alias for room".into(),
|
||||
Some(can) => format!("Canonical alias: {can}"),
|
||||
}
|
||||
},
|
||||
RoomField::Tag(_) => {
|
||||
format!("Cannot currently show value for a tag")
|
||||
},
|
||||
RoomField::Alias(_) => {
|
||||
format!("Cannot show a single alias; use `:room aliases show` instead.")
|
||||
},
|
||||
};
|
||||
|
||||
let msg = InfoMessage::Pager(msg);
|
||||
let act = Action::ShowInfoMessage(msg);
|
||||
|
||||
Ok(vec![(act, ctx)])
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue