request_builder/async_client: add register endpoint and RegistrationBuilder for making the request
parent
62e959a94d
commit
5abac19b72
|
@ -246,6 +246,7 @@ impl SyncSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use api::r0::account::register;
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
use api::r0::keys::{claim_keys, get_keys, upload_keys, KeyAlgorithm};
|
use api::r0::keys::{claim_keys, get_keys, upload_keys, KeyAlgorithm};
|
||||||
use api::r0::membership::{
|
use api::r0::membership::{
|
||||||
|
@ -447,6 +448,28 @@ impl Client {
|
||||||
Ok(self.base_client.restore_login(session).await?)
|
Ok(self.base_client.restore_login(session).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a user to the server.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `registration` - The easiest way to create this request is using the `RegistrationBuilder`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
#[instrument(skip(registration))]
|
||||||
|
pub async fn register_user<R: Into<register::Request>>(
|
||||||
|
&self,
|
||||||
|
registration: R,
|
||||||
|
) -> Result<register::Response> {
|
||||||
|
info!("Registering to {}", self.homeserver);
|
||||||
|
|
||||||
|
let request = registration.into();
|
||||||
|
|
||||||
|
self.send_uiaa(request).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Join a room by `RoomId`.
|
/// Join a room by `RoomId`.
|
||||||
///
|
///
|
||||||
/// Returns a `join_room_by_id::Response` consisting of the
|
/// Returns a `join_room_by_id::Response` consisting of the
|
||||||
|
@ -976,6 +999,75 @@ impl Client {
|
||||||
Ok(<Request::Response>::try_from(http_response)?)
|
Ok(<Request::Response>::try_from(http_response)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn send_uiaa<
|
||||||
|
Request: Endpoint<ResponseError = api::r0::uiaa::UiaaResponse> + std::fmt::Debug,
|
||||||
|
>(
|
||||||
|
&self,
|
||||||
|
request: Request,
|
||||||
|
) -> Result<Request::Response> {
|
||||||
|
let request: http::Request<Vec<u8>> = request.try_into()?;
|
||||||
|
let url = request.uri();
|
||||||
|
let path_and_query = url.path_and_query().unwrap();
|
||||||
|
let mut url = self.homeserver.clone();
|
||||||
|
|
||||||
|
url.set_path(path_and_query.path());
|
||||||
|
url.set_query(path_and_query.query());
|
||||||
|
|
||||||
|
trace!("Doing request {:?}", url);
|
||||||
|
|
||||||
|
let request_builder = match Request::METADATA.method {
|
||||||
|
HttpMethod::GET => self.http_client.get(url),
|
||||||
|
HttpMethod::POST => {
|
||||||
|
let body = request.body().clone();
|
||||||
|
self.http_client
|
||||||
|
.post(url)
|
||||||
|
.body(body)
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||||
|
}
|
||||||
|
HttpMethod::PUT => {
|
||||||
|
let body = request.body().clone();
|
||||||
|
self.http_client
|
||||||
|
.put(url)
|
||||||
|
.body(body)
|
||||||
|
.header(reqwest::header::CONTENT_TYPE, "application/json")
|
||||||
|
}
|
||||||
|
HttpMethod::DELETE => unimplemented!(),
|
||||||
|
_ => panic!("Unsuported method"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let request_builder = if Request::METADATA.requires_authentication {
|
||||||
|
let session = self.base_client.session().read().await;
|
||||||
|
|
||||||
|
if let Some(session) = session.as_ref() {
|
||||||
|
let header_value = format!("Bearer {}", &session.access_token);
|
||||||
|
request_builder.header(AUTHORIZATION, header_value)
|
||||||
|
} else {
|
||||||
|
return Err(Error::AuthenticationRequired);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request_builder
|
||||||
|
};
|
||||||
|
let mut response = request_builder.send().await?;
|
||||||
|
|
||||||
|
trace!("Got response: {:?}", response);
|
||||||
|
|
||||||
|
let status = response.status();
|
||||||
|
let mut http_builder = HttpResponse::builder().status(status);
|
||||||
|
let headers = http_builder.headers_mut().unwrap();
|
||||||
|
|
||||||
|
for (k, v) in response.headers_mut().drain() {
|
||||||
|
if let Some(key) = k {
|
||||||
|
headers.insert(key, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let body = response.bytes().await?.as_ref().to_owned();
|
||||||
|
let http_response = http_builder.body(body).unwrap();
|
||||||
|
|
||||||
|
let uiaa: Result<_> = <Request::Response>::try_from(http_response).map_err(Into::into);
|
||||||
|
|
||||||
|
Ok(uiaa?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Synchronize the client's state with the latest state on the server.
|
/// Synchronize the client's state with the latest state on the server.
|
||||||
///
|
///
|
||||||
/// If a `StateStore` is provided and this is the initial sync state will
|
/// If a `StateStore` is provided and this is the initial sync state will
|
||||||
|
|
|
@ -20,6 +20,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
use matrix_sdk_base::Error as MatrixError;
|
use matrix_sdk_base::Error as MatrixError;
|
||||||
|
|
||||||
|
use crate::api::r0::uiaa::UiaaResponse as UiaaError;
|
||||||
use crate::api::Error as RumaClientError;
|
use crate::api::Error as RumaClientError;
|
||||||
use crate::FromHttpResponseError as RumaResponseError;
|
use crate::FromHttpResponseError as RumaResponseError;
|
||||||
use crate::IntoHttpError as RumaIntoHttpError;
|
use crate::IntoHttpError as RumaIntoHttpError;
|
||||||
|
@ -53,6 +54,16 @@ pub enum Error {
|
||||||
/// An error occured in the Matrix client library.
|
/// An error occured in the Matrix client library.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
MatrixError(#[from] MatrixError),
|
MatrixError(#[from] MatrixError),
|
||||||
|
|
||||||
|
/// An error occured in the Matrix client library.
|
||||||
|
#[error("can't convert between ruma_client_api and hyper types.")]
|
||||||
|
UiaaError(RumaResponseError<UiaaError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RumaResponseError<UiaaError>> for Error {
|
||||||
|
fn from(error: RumaResponseError<UiaaError>) -> Self {
|
||||||
|
Self::UiaaError(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RumaResponseError<RumaClientError>> for Error {
|
impl From<RumaResponseError<RumaClientError>> for Error {
|
||||||
|
|
|
@ -51,7 +51,7 @@ mod error;
|
||||||
mod request_builder;
|
mod request_builder;
|
||||||
pub use client::{Client, ClientConfig, SyncSettings};
|
pub use client::{Client, ClientConfig, SyncSettings};
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
pub use request_builder::{MessagesRequestBuilder, RoomBuilder};
|
pub use request_builder::{MessagesRequestBuilder, RegistrationBuilder, RoomBuilder};
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::events::room::power_levels::PowerLevelsEventContent;
|
use crate::events::room::power_levels::PowerLevelsEventContent;
|
||||||
use crate::events::EventJson;
|
use crate::events::EventJson;
|
||||||
use crate::identifiers::{RoomId, UserId};
|
use crate::identifiers::{DeviceId, RoomId, UserId};
|
||||||
|
use api::r0::account::register::RegistrationKind;
|
||||||
use api::r0::filter::RoomEventFilter;
|
use api::r0::filter::RoomEventFilter;
|
||||||
use api::r0::membership::Invite3pid;
|
use api::r0::membership::Invite3pid;
|
||||||
use api::r0::message::get_message_events::{self, Direction};
|
use api::r0::message::get_message_events::{self, Direction};
|
||||||
|
@ -9,6 +10,7 @@ use api::r0::room::{
|
||||||
create_room::{self, CreationContent, InitialStateEvent, RoomPreset},
|
create_room::{self, CreationContent, InitialStateEvent, RoomPreset},
|
||||||
Visibility,
|
Visibility,
|
||||||
};
|
};
|
||||||
|
use api::r0::uiaa::AuthData;
|
||||||
|
|
||||||
use crate::js_int::UInt;
|
use crate::js_int::UInt;
|
||||||
|
|
||||||
|
@ -288,6 +290,108 @@ impl Into<get_message_events::Request> for MessagesRequestBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A builder used to register users.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use std::convert::TryFrom;
|
||||||
|
/// # use matrix_sdk::{Client, RegistrationBuilder};
|
||||||
|
/// # use api::r0::account::register::RegistrationKind;
|
||||||
|
/// # use matrix_sdk::identifiers::DeviceId;
|
||||||
|
/// # use url::Url;
|
||||||
|
/// # let homeserver = Url::parse("http://example.com").unwrap();
|
||||||
|
/// # let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
/// # rt.block_on(async {
|
||||||
|
/// let mut builder = RegistrationBuilder::default();
|
||||||
|
/// builder.creation_content(false)
|
||||||
|
/// .initial_state(vec![])
|
||||||
|
/// .visibility(Visibility::Public)
|
||||||
|
/// .name("name")
|
||||||
|
/// .room_version("v1.0");
|
||||||
|
/// let mut client = Client::new(homeserver).unwrap();
|
||||||
|
/// client.register_user(builder).await;
|
||||||
|
/// # })
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct RegistrationBuilder {
|
||||||
|
password: Option<String>,
|
||||||
|
username: Option<String>,
|
||||||
|
device_id: Option<DeviceId>,
|
||||||
|
initial_device_display_name: Option<String>,
|
||||||
|
auth: Option<AuthData>,
|
||||||
|
kind: Option<RegistrationKind>,
|
||||||
|
inhibit_login: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegistrationBuilder {
|
||||||
|
/// Create a `RegistrationBuilder` builder to make a `register::Request`.
|
||||||
|
///
|
||||||
|
/// The `room_id` and `from`` fields **need to be set** to create the request.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The desired password for the account.
|
||||||
|
///
|
||||||
|
/// May be empty for accounts that should not be able to log in again
|
||||||
|
/// with a password, e.g., for guest or application service accounts.
|
||||||
|
pub fn password(&mut self, password: &str) -> &mut Self {
|
||||||
|
self.password = Some(password.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// local part of the desired Matrix ID.
|
||||||
|
///
|
||||||
|
/// If omitted, the homeserver MUST generate a Matrix ID local part.
|
||||||
|
pub fn username(&mut self, username: String) -> &mut Self {
|
||||||
|
self.username = Some(username);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ID of the client device.
|
||||||
|
///
|
||||||
|
/// If this does not correspond to a known client device, a new device will be created.
|
||||||
|
/// The server will auto-generate a device_id if this is not specified.
|
||||||
|
pub fn device_id(&mut self, device_id: String) -> &mut Self {
|
||||||
|
self.device_id = Some(device_id);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A display name to assign to the newly-created device.
|
||||||
|
///
|
||||||
|
/// Ignored if `device_id` corresponds to a known device.
|
||||||
|
pub fn initial_device_display_name(&mut self, initial_device_display_name: &str) -> &mut Self {
|
||||||
|
self.initial_device_display_name = Some(initial_device_display_name.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Additional authentication information for the user-interactive authentication API.
|
||||||
|
///
|
||||||
|
/// Note that this information is not used to define how the registered user should be
|
||||||
|
/// authenticated, but is instead used to authenticate the register call itself.
|
||||||
|
/// It should be left empty, or omitted, unless an earlier call returned an response
|
||||||
|
/// with status code 401.
|
||||||
|
pub fn auth(&mut self, auth: AuthData) -> &mut Self {
|
||||||
|
self.auth = Some(auth);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Kind of account to register
|
||||||
|
///
|
||||||
|
/// Defaults to `User` if omitted.
|
||||||
|
pub fn kind(&mut self, kind: RegistrationKind) -> &mut Self {
|
||||||
|
self.kind = Some(kind);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If `true`, an `access_token` and `device_id` should not be returned
|
||||||
|
/// from this call, therefore preventing an automatic login.
|
||||||
|
pub fn inhibit_login(&mut self, inhibit_login: bool) -> &mut Self {
|
||||||
|
self.inhibit_login = inhibit_login;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
Loading…
Reference in New Issue