async_client: impl kick, join, leave, invite, create for

This commit is contained in:
Devin R 2020-04-10 16:32:28 -04:00
parent 7c20c79f32
commit c69d54e2d4
3 changed files with 372 additions and 1 deletions

View file

@ -37,7 +37,7 @@ use ruma_api::{Endpoint, Outgoing};
use ruma_events::room::message::MessageEventContent;
use ruma_events::EventResult;
pub use ruma_events::EventType;
use ruma_identifiers::RoomId;
use ruma_identifiers::{RoomId, RoomIdOrAliasId, UserId};
#[cfg(feature = "encryption")]
use ruma_identifiers::{DeviceId, UserId};
@ -181,7 +181,16 @@ impl SyncSettings {
use api::r0::client_exchange::send_event_to_device;
#[cfg(feature = "encryption")]
use api::r0::keys::{claim_keys, get_keys, upload_keys, KeyAlgorithm};
use api::r0::membership::join_room_by_id;
use api::r0::membership::join_room_by_id_or_alias;
use api::r0::membership::kick_user;
use api::r0::membership::leave_room;
use api::r0::membership::{
invite_user::{self, InvitationRecipient},
Invite3pid,
};
use api::r0::message::create_message_event;
use api::r0::room::create_room;
use api::r0::session::login;
use api::r0::sync::sync_events;
@ -333,6 +342,162 @@ impl AsyncClient {
Ok(response)
}
/// Join a room by `RoomId`.
///
/// Returns a `join_room_by_id::Response` consisting of the
/// joined rooms `RoomId`.
///
/// # Arguments
///
/// * room_id - A valid RoomId otherwise sending will fail.
///
pub async fn join_room_by_id(&mut self, room_id: &RoomId) -> Result<join_room_by_id::Response> {
let request = join_room_by_id::Request {
room_id: room_id.clone(),
third_party_signed: None,
};
self.send(request).await
}
/// Join a room by `RoomId`.
///
/// Returns a `join_room_by_id_or_alias::Response` consisting of the
/// joined rooms `RoomId`.
///
/// # Arguments
///
/// * alias - A valid `RoomIdOrAliasId` otherwise sending will fail.
///
pub async fn join_room_by_id_or_alias(
&mut self,
alias: &RoomIdOrAliasId,
) -> Result<join_room_by_id_or_alias::Response> {
let request = join_room_by_id_or_alias::Request {
room_id_or_alias: alias.clone(),
third_party_signed: None,
};
self.send(request).await
}
/// Kick a user out of the specified room.
///
/// Returns a `kick_user::Response`, an empty response.
///
/// # Arguments
///
/// * room_id - A valid `RoomId` otherwise sending will fail.
///
/// * user_id - A valid `UserId`.
///
/// * reason - Optional reason why the room member is being kicked out.
///
pub async fn kick_user(
&mut self,
room_id: &RoomId,
user_id: &UserId,
reason: Option<String>,
) -> Result<kick_user::Response> {
let request = kick_user::Request {
reason,
room_id: room_id.clone(),
user_id: user_id.clone(),
};
self.send(request).await
}
/// Leave the specified room.
///
/// Returns a `leave_room::Response`, an empty response.
///
/// # Arguments
///
/// * room_id - A valid `RoomId`.
///
pub async fn leave_room(&mut self, room_id: &RoomId) -> Result<leave_room::Response> {
let request = leave_room::Request {
room_id: room_id.clone(),
};
self.send(request).await
}
/// Invite the specified user by `UserId` to the given room.
///
/// Returns a `invite_user::Response`, an empty response.
///
/// # Arguments
///
/// * room_id - A valid `RoomId`.
///
/// * user_id - A valid `UserId`.
///
pub async fn invite_user_by_id(
&mut self,
room_id: &RoomId,
user_id: &UserId,
) -> Result<invite_user::Response> {
let request = invite_user::Request {
room_id: room_id.clone(),
recipient: InvitationRecipient::UserId {
user_id: user_id.clone(),
},
};
self.send(request).await
}
/// Invite the specified user by third party id to the given room.
///
/// Returns a `invite_user::Response`, an empty response.
///
/// # Arguments
///
/// * room_id - A valid `RoomId`.
///
/// * invite_id - A valid `UserId`.
///
pub async fn invite_user_by_3pid(
&mut self,
room_id: &RoomId,
invite_id: &Invite3pid,
) -> Result<invite_user::Response> {
let request = invite_user::Request {
room_id: room_id.clone(),
recipient: InvitationRecipient::ThirdPartyId(invite_id.clone()),
};
self.send(request).await
}
/// A builder to create a room and send the request.
///
/// Returns a `create_room::Response`, an empty response.
///
/// # Arguments
///
/// * room - the easiest way to create this request is using `RoomBuilder` struct.
///
/// # Examples
/// ```ignore
/// use matrix_sdk::{AsyncClient, RoomBuilder};
///
/// let mut bldr = RoomBuilder::default();
/// bldr.creation_content(false)
/// .initial_state(vec![])
/// .visibility(Visibility::Public)
/// .name("name")
/// .room_version("v1.0");
///
/// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap();
///
/// assert!(cli.create_room(bldr).await.is_ok());
/// ```
///
pub async fn create_room<R: Into<create_room::Request>>(
&mut self,
room: R,
) -> Result<create_room::Response> {
let request = room.into();
self.send(request).await
}
/// Synchronize the client's state with the latest state on the server.
///
/// # Arguments

View file

@ -38,6 +38,7 @@ mod base_client;
mod error;
mod event_emitter;
mod models;
mod request_builder;
mod session;
#[cfg(test)]
@ -50,5 +51,6 @@ pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings};
pub use base_client::Client;
pub use event_emitter::EventEmitter;
pub use models::Room;
pub use request_builder::RoomBuilder;
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");

204
src/request_builder.rs Normal file
View file

@ -0,0 +1,204 @@
use crate::events::room::power_levels::PowerLevelsEventContent;
use crate::identifiers::UserId;
use crate::api;
use api::r0::membership::Invite3pid;
use api::r0::room::{
create_room::{self, CreationContent, InitialStateEvent, RoomPreset},
Visibility,
};
/// A builder used to create rooms.
///
/// # Examples
/// ```
///
/// ```
#[derive(Default)]
pub struct RoomBuilder {
/// Extra keys to be added to the content of the `m.room.create`.
creation_content: Option<CreationContent>,
/// List of state events to send to the new room.
///
/// Takes precedence over events set by preset, but gets overriden by
/// name and topic keys.
initial_state: Vec<InitialStateEvent>,
/// A list of user IDs to invite to the room.
///
/// This will tell the server to invite everyone in the list to the newly created room.
invite: Vec<UserId>,
/// List of third party IDs of users to invite.
invite_3pid: Vec<Invite3pid>,
/// If set, this sets the `is_direct` flag on room invites.
is_direct: Option<bool>,
/// If this is included, an `m.room.name` event will be sent into the room to indicate
/// the name of the room.
name: Option<String>,
/// Power level content to override in the default power level event.
power_level_content_override: Option<PowerLevelsEventContent>,
/// Convenience parameter for setting various default state events based on a preset.
preset: Option<RoomPreset>,
/// The desired room alias local part.
room_alias_name: Option<String>,
/// Room version to set for the room. Defaults to homeserver's default if not specified.
room_version: Option<String>,
/// If this is included, an `m.room.topic` event will be sent into the room to indicate
/// the topic for the room.
topic: Option<String>,
/// A public visibility indicates that the room will be shown in the published room
/// list. A private visibility will hide the room from the published room list. Rooms
/// default to private visibility if this key is not included.
visibility: Option<Visibility>,
}
impl RoomBuilder {
/// Returns an empty `RoomBuilder` for creating rooms.
pub fn new() -> Self {
Self::default()
}
/// Set the `CreationContent`.
///
/// Weather users on other servers can join this room.
pub fn creation_content(&mut self, federate: bool) -> &mut Self {
let federate = Some(federate);
self.creation_content = Some(CreationContent { federate });
self
}
/// Set the `InitialStateEvent` vector.
///
pub fn initial_state(&mut self, state: Vec<InitialStateEvent>) -> &mut Self {
self.initial_state = state;
self
}
/// Set the vec of `UserId`s.
///
pub fn invite(&mut self, invite: Vec<UserId>) -> &mut Self {
self.invite = invite;
self
}
/// Set the vec of `Invite3pid`s.
///
pub fn invite_3pid(&mut self, invite: Vec<Invite3pid>) -> &mut Self {
self.invite_3pid = invite;
self
}
/// Set the vec of `Invite3pid`s.
///
pub fn is_direct(&mut self, direct: bool) -> &mut Self {
self.is_direct = Some(direct);
self
}
/// Set the room name. A `m.room.name` event will be sent to the room.
///
pub fn name<S: Into<String>>(&mut self, name: S) -> &mut Self {
self.name = Some(name.into());
self
}
/// Set the room's power levels.
///
pub fn power_level_override(&mut self, power: PowerLevelsEventContent) -> &mut Self {
self.power_level_content_override = Some(power);
self
}
/// Convenience for setting various default state events based on a preset.
///
pub fn preset(&mut self, preset: RoomPreset) -> &mut Self {
self.preset = Some(preset);
self
}
/// The local part of a room alias.
///
pub fn room_alias_name<S: Into<String>>(&mut self, alias: S) -> &mut Self {
self.room_alias_name = Some(alias.into());
self
}
/// Room version, defaults to homeserver's version if left unspecified.
///
pub fn room_version<S: Into<String>>(&mut self, version: S) -> &mut Self {
self.room_version = Some(version.into());
self
}
/// If included, a `m.room.topic` event will be sent to the room.
///
pub fn topic<S: Into<String>>(&mut self, topic: S) -> &mut Self {
self.topic = Some(topic.into());
self
}
/// A public visibility indicates that the room will be shown in the published
/// room list. A private visibility will hide the room from the published room list.
/// Rooms default to private visibility if this key is not included.
///
pub fn visibility(&mut self, vis: Visibility) -> &mut Self {
self.visibility = Some(vis);
self
}
}
impl Into<create_room::Request> for RoomBuilder {
fn into(self) -> create_room::Request {
create_room::Request {
creation_content: self.creation_content,
initial_state: self.initial_state,
invite: self.invite,
invite_3pid: self.invite_3pid,
is_direct: self.is_direct,
name: self.name,
power_level_content_override: self.power_level_content_override,
preset: self.preset,
room_alias_name: self.room_alias_name,
room_version: self.room_version,
topic: self.topic,
visibility: self.visibility,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{AsyncClient, Session};
use mockito::mock;
use url::Url;
use std::convert::TryFrom;
#[tokio::test]
async fn create_room_builder() {
let homeserver = Url::parse(&mockito::server_url()).unwrap();
let _m = mock("POST", "/_matrix/client/r0/createRoom")
.with_status(200)
.with_body_from_file("./tests/data/room_id.json")
.create();
let session = Session {
access_token: "1234".to_owned(),
user_id: UserId::try_from("@example:localhost").unwrap(),
device_id: "DEVICEID".to_owned(),
};
let mut bldr = RoomBuilder::default();
bldr.creation_content(false)
.initial_state(vec![])
.visibility(Visibility::Public)
.name("name")
.room_version("v1.0");
let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap();
assert!(cli.create_room(bldr).await.is_ok());
}
}