diff --git a/crates/matrix/Cargo.toml b/crates/matrix/Cargo.toml index 98c8fbb..574fd64 100644 --- a/crates/matrix/Cargo.toml +++ b/crates/matrix/Cargo.toml @@ -11,6 +11,9 @@ hmac = "0.12.1" serde_path_to_error = "0.1.14" serde_qs = "0.12.0" sha1 = "0.10.6" +ruma-events = { version = "0.27.11", features = ["html", "markdown"] } +ruma-common = { version = "0.12.1", features = ["rand"] } +ruma-macros = "0.12.0" # Workspace Dependencies anyhow = { workspace = true } diff --git a/crates/matrix/src/client/resources/room.rs b/crates/matrix/src/client/resources/room.rs index b732718..5752b34 100644 --- a/crates/matrix/src/client/resources/room.rs +++ b/crates/matrix/src/client/resources/room.rs @@ -1,10 +1,10 @@ use anyhow::Result; +use ruma_common::{serde::Raw, OwnedUserId, RoomOrAliasId, RoomId}; +use ruma_events::{AnyInitialStateEvent, room::power_levels::RoomPowerLevelsEventContent}; use serde::{Deserialize, Serialize}; use tracing::instrument; -use crate::admin::resources::user_id::UserId; - -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum RoomPreset { PrivateChat, @@ -12,38 +12,73 @@ pub enum RoomPreset { TrustedPrivateChat, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CreateRoomCreationContent { +#[derive(Clone, Debug, Default, Serialize)] +pub struct RoomCreationContent { #[serde(rename = "m.federate")] - pub m_federate: bool, + pub federate: bool, +} + +#[derive(Clone, Debug, Default, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum RoomVisibility { + Public, + #[default] + Private, +} + +#[derive(Clone, Debug, Default, Serialize)] +pub struct CreateRoomBody { + pub initial_state: Vec>, + pub creation_content: Option, + pub invite: Vec, + pub is_direct: bool, + pub name: Option, + pub power_override: Option, + pub preset: Option, + pub room_alias_name: Option, + pub topic: Option, + pub visibility: Option, +} + +#[derive(Clone, Debug, Serialize)] +pub struct JoinRoomBody { + pub reason: Option, +} + +#[derive(Clone, Debug, Serialize)] +pub struct ForgetRoomBody { + pub reason: Option, +} + +#[derive(Clone, Debug, Serialize)] +pub struct LeaveRoomBody { + pub reason: Option, + pub user_id: OwnedUserId, +} + +#[derive(Clone, Debug, Serialize)] +pub struct RoomKickOrBanBody { + pub reason: Option, + pub user_id: OwnedUserId, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CreateRoomRequestBody { - pub creation_content: CreateRoomCreationContent, - pub name: String, - pub preset: RoomPreset, - pub room_alias_name: String, - pub topic: String, +#[derive(Clone, Debug, Deserialize)] +pub struct CreateRoomResponse { + pub room_id: String, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CreateRoomResponseBody { +#[derive(Clone, Debug, Deserialize)] +pub struct JoinRoomResponse { pub room_id: String, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Deserialize)] pub struct RoomApiError { pub errcode: String, pub error: String, } -#[derive(Debug, Serialize, Deserialize)] -pub struct Room { - pub device_id: String, - pub is_guest: bool, - pub user_id: UserId, -} +pub struct Room; impl Room { /// Create a new room with various configuration options. @@ -53,13 +88,194 @@ impl Room { pub async fn create( client: &crate::http::Client, access_token: impl Into, - creation_content: CreateRoomRequestBody, - ) -> Result { + body: CreateRoomBody, + ) -> Result { + let mut tmp = (*client).clone(); + tmp.set_token(access_token)?; + + let resp = tmp + .post_json("/_matrix/client/v3/createRoom", &body) + .await?; + + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) + } + + /// Join a particular room, if we are allowed to participate. + /// + /// Refer: https://spec.matrix.org/v1.9/client-server-api/#joining-rooms + #[instrument(skip(client, access_token))] + pub async fn join( + client: &crate::http::Client, + access_token: impl Into, + alias_or_id: &RoomOrAliasId, + body: JoinRoomBody, + ) -> Result { + let mut tmp = (*client).clone(); + tmp.set_token(access_token)?; + + let resp = tmp + .post_json( + format!("/_matrix/client/v3/join/{alias_or_id}"), + &body, + ) + .await?; + + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) + } + + /// Forget a particular room. + /// This will prevent the user from accessing the history of the room. + /// + /// Refer: https://spec.matrix.org/v1.9/client-server-api/#leaving-rooms + #[instrument(skip(client, access_token))] + pub async fn forget( + client: &crate::http::Client, + access_token: impl Into, + room_id: &RoomId, + body: ForgetRoomBody, + ) -> Result<()> { + let mut tmp = (*client).clone(); + tmp.set_token(access_token)?; + + let resp = tmp + .post_json( + format!("/_matrix/client/v3/rooms/{room_id}/forget"), + &body, + ) + .await?; + + if resp.status().is_success() { + return Ok(()); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) + } + + /// Leave a particular room. + /// They are still allowed to retrieve the history which they were previously allowed to see. + /// + /// Refer: https://spec.matrix.org/v1.9/client-server-api/#leaving-rooms + #[instrument(skip(client, access_token))] + pub async fn leave( + client: &crate::http::Client, + access_token: impl Into, + room_id: &RoomId, + body: LeaveRoomBody, + ) -> Result<()> { + let mut tmp = (*client).clone(); + tmp.set_token(access_token)?; + + let resp = tmp + .post_json( + format!("/_matrix/client/v3/rooms/{room_id}/leave"), + &body, + ) + .await?; + + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) + } + + /// Kick a user from a particular room. + /// The caller must have the required power level in order to perform this operation. + /// + /// Refer: https://spec.matrix.org/v1.9/client-server-api/#leaving-rooms + #[instrument(skip(client, access_token))] + pub async fn kick( + client: &crate::http::Client, + access_token: impl Into, + room_id: &RoomId, + body: RoomKickOrBanBody, + ) -> Result<()> { + let mut tmp = (*client).clone(); + tmp.set_token(access_token)?; + + let resp = tmp + .post_json( + format!("/_matrix/client/v3/rooms/{room_id}/kick"), + &body, + ) + .await?; + + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) + } + + /// Ban a user from a particular room. + /// This will kick them too if they are still a member. + /// The caller must have the required power level in order to perform this operation. + /// + /// Refer: https://spec.matrix.org/v1.9/client-server-api/#leaving-rooms + #[instrument(skip(client, access_token))] + pub async fn ban( + client: &crate::http::Client, + access_token: impl Into, + room_id: &RoomId, + body: RoomKickOrBanBody, + ) -> Result<()> { + let mut tmp = (*client).clone(); + tmp.set_token(access_token)?; + + let resp = tmp + .post_json( + format!("/_matrix/client/v3/rooms/{room_id}/ban"), + &body, + ) + .await?; + + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) + } + + /// Unban a user from a particular room. + /// This will allow them to re-join or be re-invited. + /// The caller must have the required power level in order to perform this operation. + /// + /// Refer: https://spec.matrix.org/v1.9/client-server-api/#banning-users-in-a-room + #[instrument(skip(client, access_token))] + pub async fn unban( + client: &crate::http::Client, + access_token: impl Into, + room_id: &RoomId, + body: RoomKickOrBanBody, + ) -> Result<()> { let mut tmp = (*client).clone(); tmp.set_token(access_token)?; let resp = tmp - .post_json("/_matrix/client/v3/createRoom", &creation_content) + .post_json( + format!("/_matrix/client/v3/rooms/{room_id}/unban"), + &body, + ) .await?; if resp.status().is_success() { diff --git a/crates/test/src/matrix/mod.rs b/crates/test/src/matrix/mod.rs index 9e56f51..8767c31 100644 --- a/crates/test/src/matrix/mod.rs +++ b/crates/test/src/matrix/mod.rs @@ -1 +1,2 @@ mod shared_token_registration; +mod room;