Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: event handlers for client API #29

Merged
merged 15 commits into from
Feb 17, 2024
Merged
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ resolver = "1"
[workspace.dependencies]
anyhow = "1.0.75"
axum = { version = "0.7.4", features = ["tokio"] }
chrono = { version = "0.4.34", features = ["serde"] }
dotenv = "0.15.0"
http = "0.2.11"
reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls", "stream", "multipart"] }
mime = "0.3.17"
openssl = { version = "0.10.63", features = ["vendored"] }
openssl-sys = { version = "0.9.99", features = ["vendored"] }
reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls", "multipart"] }
serde = "1.0.192"
serde_json = "1.0.108"
tokio = "1.34.0"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
tracing-subscriber = { version = "0.3.18", features = ["json"] }
uuid = { version = "1.6.1", features = ["v4"] }
url = "2.4.1"
4 changes: 2 additions & 2 deletions crates/core/src/account/model.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use url::Url;

use matrix::admin::resources::user_id::UserId;
use matrix::ruma_common::OwnedUserId;

#[derive(Debug, Clone)]
pub struct Account {
pub user_id: UserId,
pub user_id: OwnedUserId,
pub username: String,
pub email: String,
pub display_name: String,
Expand Down
37 changes: 24 additions & 13 deletions crates/core/src/account/service.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::sync::Arc;

use matrix::{admin::resources::user::UserService, client::resources::session::Session};
use matrix::{
admin::resources::user::UserService, client::resources::session::Session, ruma_common::UserId,
};
use tracing::instrument;
use url::Url;
use uuid::Uuid;
use validator::{Validate, ValidationError};

use matrix::{
admin::resources::{
user::{CreateUserBody, ListUsersQuery, LoginAsUserBody, ThreePid},
user_id::UserId,
},
admin::resources::user::{CreateUserBody, ListUsersQuery, LoginAsUserBody, ThreePid},
Client as MatrixAdminClient,
};

Expand Down Expand Up @@ -117,7 +116,13 @@ impl AccountService {
/// Returs `true` if the given `email address` is NOT registered in the
/// Matrix Server
pub async fn is_email_available(&self, email: &str) -> Result<bool> {
let user_id = UserId::new(email, self.admin.server_name());
let user_id = format!("@{}:{}", email, self.admin.server_name());
let user_id = <&UserId>::try_from(user_id.as_str()).map_err(|err| {
// TODO
tracing::error!(?err, "Failed to parse username");
Error::Unknown
})?;

let exists = UserService::list(
&self.admin,
ListUsersQuery {
Expand Down Expand Up @@ -206,15 +211,21 @@ impl AccountService {
return Err(AccountErrorCode::EmailTaken(dto.email).into());
}

let user_id = UserId::new(dto.username.clone(), self.admin.server_name().to_string());
let user_id = format!("@{}:{}", dto.username, self.admin.server_name());
let user_id = <&UserId>::try_from(user_id.as_str()).map_err(|err| {
// TODO
tracing::error!(?err, "Failed to parse username");
Error::Unknown
})?;

let avatar_url = Url::parse(DEFAULT_AVATAR_URL).map_err(|err| {
tracing::error!(?err, "Failed to parse default avatar url");
Error::Unknown
})?;

UserService::create(
&self.admin,
user_id.clone(),
user_id,
CreateUserBody {
displayname: Some(dto.username),
password: dto.password.to_string(),
Expand All @@ -239,14 +250,14 @@ impl AccountService {
Error::Unknown
})?;

let matrix_account = UserService::query_user_account(&self.admin, user_id.clone())
let matrix_account = UserService::query_user_account(&self.admin, user_id)
.await
.map_err(|err| {
tracing::error!(?err, "Failed to query user account");
Error::Unknown
})?;
let account = Account {
user_id,
user_id: user_id.into(),
username: matrix_account.name,
email: matrix_account
.threepids
Expand All @@ -264,9 +275,9 @@ impl AccountService {
}

/// Creates an access token for the given user
pub async fn issue_user_token(&self, user_id: UserId) -> Result<String> {
pub async fn issue_user_token(&self, user_id: &UserId) -> Result<String> {
let credentials =
UserService::login_as_user(&self.admin, user_id.clone(), LoginAsUserBody::default())
UserService::login_as_user(&self.admin, user_id, LoginAsUserBody::default())
.await
.map_err(|err| {
tracing::error!(?err, ?user_id, "Failed to login as user");
Expand All @@ -283,7 +294,7 @@ impl AccountService {
tracing::error!(?err, "Failed to get session from matrix as client");
Error::Unknown
})?;
let matrix_account = UserService::query_user_account(&self.admin, session.user_id.clone())
let matrix_account = UserService::query_user_account(&self.admin, &session.user_id)
.await
.map_err(|err| {
tracing::error!(?err, "Failed to query user account");
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/room/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use tracing::instrument;

use matrix::{
client::resources::room::{
CreateRoomBody, Room as MatrixRoom, RoomCreationContent, RoomPreset,
CreateRoomBody, RoomCreationContent, RoomPreset, RoomService as MatrixRoomService,
},
Client as MatrixAdminClient,
};
Expand Down Expand Up @@ -36,7 +36,7 @@ impl RoomService {
access_token: &Secret,
dto: CreateRoomDto,
) -> Result<Room> {
match MatrixRoom::create(
match MatrixRoomService::create(
&self.admin,
access_token.to_string(),
CreateRoomBody {
Expand Down
3 changes: 3 additions & 0 deletions crates/matrix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ ruma-macros = "0.12.0"

# Workspace Dependencies
anyhow = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
mime = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
serde = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
url = { workspace = true, features = ["serde"] }
4 changes: 2 additions & 2 deletions crates/matrix/src/admin/resources/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ruma_events::{AnyMessageLikeEvent, AnyStateEvent, AnyTimelineEvent};
use serde::{Deserialize, Serialize};
use tracing::instrument;

use crate::{error::MatrixError, event_filter::RoomEventFilter, http::Client};
use crate::{error::MatrixError, filter::RoomEventFilter, http::Client};

#[derive(Default)]
pub struct RoomService;
Expand Down Expand Up @@ -444,7 +444,7 @@ impl RoomService {
}
}

#[derive(Default, Debug, Serialize)]
#[derive(Debug, Default, Clone, Serialize)]
pub enum Direction {
#[serde(rename = "f")]
#[default]
Expand Down
11 changes: 5 additions & 6 deletions crates/matrix/src/admin/resources/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
//! for a server admin: see Admin API.

use anyhow::Result;
use ruma_common::UserId;
use serde::{Deserialize, Serialize};
use tracing::instrument;
use url::Url;

use crate::{error::MatrixError, http::Client};

use super::user_id::UserId;

#[derive(Default)]
pub struct UserService;

Expand Down Expand Up @@ -149,7 +148,7 @@ impl UserService {
///
/// Refer: https://matrix-org.github.io/synapse/v1.88/admin_api/user_admin_api.html#query-user-account
#[instrument(skip(client))]
pub async fn query_user_account(client: &Client, user_id: UserId) -> Result<User> {
pub async fn query_user_account(client: &Client, user_id: &UserId) -> Result<User> {
let resp = client
.get(format!(
"/_synapse/admin/v2/users/{user_id}",
Expand All @@ -174,7 +173,7 @@ impl UserService {
///
/// Refer: https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#create-or-modify-account
#[instrument(skip(client, body))]
pub async fn create(client: &Client, user_id: UserId, body: CreateUserBody) -> Result<User> {
pub async fn create(client: &Client, user_id: &UserId, body: CreateUserBody) -> Result<User> {
let resp = client
.put_json(
format!("/_synapse/admin/v2/users/{user_id}", user_id = user_id),
Expand Down Expand Up @@ -212,7 +211,7 @@ impl UserService {
///
/// Refer: https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#create-or-modify-account
#[instrument(skip(client))]
pub async fn update(client: &Client, user_id: UserId, body: UpdateUserBody) -> Result<User> {
pub async fn update(client: &Client, user_id: &UserId, body: UpdateUserBody) -> Result<User> {
let resp = client
.put_json(
format!("/_synapse/admin/v2/users/{user_id}", user_id = user_id),
Expand Down Expand Up @@ -246,7 +245,7 @@ impl UserService {
#[instrument(skip(client))]
pub async fn login_as_user(
client: &Client,
user_id: UserId,
user_id: &UserId,
body: LoginAsUserBody,
) -> Result<LoginAsUserResponse> {
let resp = client
Expand Down
73 changes: 54 additions & 19 deletions crates/matrix/src/client/resources/events.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Result;
use ruma_common::{serde::Raw, EventId, OwnedEventId, RoomId, TransactionId};
use ruma_common::{serde::Raw, EventId, OwnedEventId, OwnedTransactionId, RoomId};

use ruma_events::{
relation::RelationType, AnyMessageLikeEvent, AnyStateEvent, AnyStateEventContent,
Expand All @@ -9,25 +9,39 @@ use ruma_events::{
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tracing::instrument;

use crate::{admin::resources::room::Direction, event_filter::RoomEventFilter, Client};
use crate::{admin::resources::room::Direction, error::MatrixError, Client};

pub struct Events;
pub struct EventsService;

#[derive(Debug, Default, Serialize)]
#[derive(Debug, Default, Clone, Serialize)]
pub struct GetMessagesQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
pub dir: Option<Direction>,
pub filter: Option<RoomEventFilter>,

pub dir: Direction,

#[serde(skip_serializing_if = "String::is_empty")]
pub filter: String,
}

#[derive(Debug, Default, Serialize)]
#[derive(Debug, Default, Clone, Serialize)]
pub struct GetRelationsQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub from: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u64>,
pub dir: Option<Direction>,

pub dir: Direction,
}

#[derive(Debug, Deserialize)]
Expand All @@ -40,7 +54,7 @@ pub struct GetMessagesResponse {

#[derive(Debug, Deserialize)]
#[serde(transparent)]
pub struct GetStateResponse(Vec<Raw<AnyStateEvent>>);
pub struct GetStateResponse(pub Vec<Raw<AnyStateEvent>>);

#[derive(Debug, Deserialize)]
pub struct GetRelationsResponse {
Expand Down Expand Up @@ -70,7 +84,7 @@ pub struct SendRedactionResponse {
pub event_id: OwnedEventId,
}

impl Events {
impl EventsService {
#[instrument(skip(client, access_token))]
pub async fn get_event(
client: &Client,
Expand Down Expand Up @@ -103,10 +117,13 @@ impl Events {
tmp.set_token(access_token)?;

let resp = tmp
.get(format!(
"/_matrix/client/v3/rooms/{room_id}/messages",
room_id = room_id,
))
.get_query(
format!(
"/_matrix/client/v3/rooms/{room_id}/messages",
room_id = room_id,
),
&query,
)
.await?;

Ok(resp.json().await?)
Expand Down Expand Up @@ -199,7 +216,7 @@ impl Events {
client: &Client,
access_token: impl Into<String>,
room_id: &RoomId,
txn_id: &TransactionId,
txn_id: OwnedTransactionId,
body: T,
) -> Result<SendMessageResponse> {
let mut tmp = (*client).clone();
Expand All @@ -217,7 +234,13 @@ impl Events {
)
.await?;

Ok(resp.json().await?)
if resp.status().is_success() {
return Ok(resp.json().await?);
}

let error = resp.json::<MatrixError>().await?;

Err(anyhow::anyhow!(error.error))
}

#[instrument(skip(client, access_token, body))]
Expand All @@ -243,7 +266,13 @@ impl Events {

let resp = tmp.put_json(path, &body).await?;

Ok(resp.json().await?)
if resp.status().is_success() {
return Ok(resp.json().await?);
}

let error = resp.json::<MatrixError>().await?;

Err(anyhow::anyhow!(error.error))
}

#[instrument(skip(client, access_token, body))]
Expand All @@ -252,7 +281,7 @@ impl Events {
access_token: impl Into<String>,
room_id: &RoomId,
event_id: &EventId,
txn_id: &TransactionId,
txn_id: OwnedTransactionId,
body: SendRedactionBody,
) -> Result<SendRedactionResponse> {
let mut tmp = (*client).clone();
Expand All @@ -270,6 +299,12 @@ impl Events {
)
.await?;

Ok(resp.json().await?)
if resp.status().is_success() {
return Ok(resp.json().await?);
}

let error = resp.json::<MatrixError>().await?;

Err(anyhow::anyhow!(error.error))
}
}
1 change: 1 addition & 0 deletions crates/matrix/src/client/resources/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod error;
pub mod events;
pub mod login;
pub mod mxc;
pub mod room;
pub mod session;
Loading
Loading