2 Commits

Author SHA1 Message Date
d68e3eca3b Simplify route to get room information 2025-02-27 20:18:18 +01:00
3640f72d73 Can get user information 2025-02-27 20:08:13 +01:00
5 changed files with 94 additions and 53 deletions

View File

@@ -57,18 +57,17 @@ async fn main() -> std::io::Result<()> {
.route("/api", web::get().to(api::api_home)) .route("/api", web::get().to(api::api_home))
.route("/api", web::post().to(api::api_home)) .route("/api", web::post().to(api::api_home))
.route("/api/account/whoami", web::get().to(api::account::who_am_i)) .route("/api/account/whoami", web::get().to(api::account::who_am_i))
.route("/api/room/{room_id}/name", web::get().to(api::room::name)) .route("/api/room/{room_id}", web::get().to(api::room::info))
.route(
"/api/room/{room_id}/avatar",
web::get().to(api::room::avatar),
)
.route( .route(
"/api/media/{server_name}/{media_id}/download", "/api/media/{server_name}/{media_id}/download",
web::get().to(api::media::download), web::get().to(api::media::download),
) )
// TODO : handle media thumbnail // TODO : handle media thumbnail
// TODO : handle space // TODO : handle space
// TODO : handle user information .route(
"/api/profile/{user_id}",
web::get().to(api::profile::get_profile),
)
.service(web::resource("/api/ws").route(web::get().to(api::ws::ws))) .service(web::resource("/api/ws").route(web::get().to(api::ws::ws)))
}) })
.workers(4) .workers(4)

View File

@@ -4,6 +4,7 @@ use actix_web::HttpResponse;
pub mod account; pub mod account;
pub mod media; pub mod media;
pub mod profile;
pub mod room; pub mod room;
pub mod ws; pub mod ws;

29
src/server/api/profile.rs Normal file
View File

@@ -0,0 +1,29 @@
use crate::extractors::client_auth::APIClientAuth;
use crate::server::HttpResult;
use crate::utils::matrix_utils::ApiMxcURI;
use actix_web::{web, HttpResponse};
use ruma::api::client::profile;
use ruma::OwnedUserId;
#[derive(serde::Deserialize)]
pub struct UserIDInPath {
user_id: OwnedUserId,
}
#[derive(serde::Serialize)]
struct ProfileResponse {
display_name: Option<String>,
avatar: Option<ApiMxcURI>,
}
/// Get user profile
pub async fn get_profile(auth: APIClientAuth, path: web::Path<UserIDInPath>) -> HttpResult {
let res = auth
.send_request(profile::get_profile::v3::Request::new(path.user_id.clone()))
.await?;
Ok(HttpResponse::Ok().json(ProfileResponse {
display_name: res.displayname,
avatar: res.avatar_url.map(ApiMxcURI),
}))
}

View File

@@ -1,10 +1,11 @@
use crate::extractors::client_auth::APIClientAuth; use crate::extractors::client_auth::APIClientAuth;
use crate::server::HttpResult; use crate::server::{HttpFailure, HttpResult};
use crate::utils::matrix_utils::parse_mxc_url; use crate::utils::matrix_utils::ApiMxcURI;
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use ruma::api::client::state; use ruma::api::client::state;
use ruma::events::StateEventType; use ruma::events::StateEventType;
use ruma::{OwnedRoomId, OwnedServerName}; use ruma::{OwnedMxcUri, OwnedRoomId};
use serde::de::DeserializeOwned;
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct RoomIDInPath { pub struct RoomIDInPath {
@@ -12,50 +13,53 @@ pub struct RoomIDInPath {
} }
#[derive(serde::Serialize)] #[derive(serde::Serialize)]
struct GetRoomNameResponse { struct GetRoomInfoResponse {
name: String, name: Option<String>,
avatar: Option<ApiMxcURI>,
} }
/// Get room name /// Get a room information
pub async fn name(auth: APIClientAuth, path: web::Path<RoomIDInPath>) -> HttpResult { async fn get_room_info<E: DeserializeOwned>(
auth: &APIClientAuth,
room_id: OwnedRoomId,
event_type: StateEventType,
field: &str,
) -> anyhow::Result<Option<E>, HttpFailure> {
let res = auth let res = auth
.send_request(state::get_state_events_for_key::v3::Request::new( .send_request(state::get_state_events_for_key::v3::Request::new(
room_id,
event_type,
String::default(),
))
.await?;
Ok(res.content.get_field(field)?)
}
/// Get room information
pub async fn info(auth: APIClientAuth, path: web::Path<RoomIDInPath>) -> HttpResult {
let room_name: Option<String> = get_room_info(
&auth,
path.room_id.clone(), path.room_id.clone(),
StateEventType::RoomName, StateEventType::RoomName,
String::default(), "name",
)) )
.await?; .await
.ok()
.flatten();
Ok(HttpResponse::Ok().json(GetRoomNameResponse { let room_avatar: Option<OwnedMxcUri> = get_room_info(
name: res.content.get_field("name")?.unwrap_or("").to_string(), &auth,
}))
}
#[derive(serde::Serialize)]
struct GetRoomAvatarResponse {
url: String,
server_name: OwnedServerName,
media_id: String,
}
/// Get room avatar
pub async fn avatar(auth: APIClientAuth, path: web::Path<RoomIDInPath>) -> HttpResult {
let res = auth
.send_request(state::get_state_events_for_key::v3::Request::new(
path.room_id.clone(), path.room_id.clone(),
StateEventType::RoomAvatar, StateEventType::RoomAvatar,
String::default(), "url",
)) )
.await?; .await
.ok()
.flatten();
let avatar_url = res.content.get_field("url")?.unwrap_or("").to_string(); Ok(HttpResponse::Ok().json(GetRoomInfoResponse {
let Some((media_id, server_name)) = parse_mxc_url(&avatar_url) else { name: room_name,
return Ok(HttpResponse::InternalServerError().body("Invalid Matrix resource URL")); avatar: room_avatar.map(ApiMxcURI),
};
Ok(HttpResponse::Ok().json(GetRoomAvatarResponse {
url: avatar_url.to_string(),
server_name,
media_id: media_id.to_string(),
})) }))
} }

View File

@@ -1,10 +1,18 @@
use ruma::OwnedServerName; use ruma::OwnedMxcUri;
use std::str::FromStr; use serde::ser::SerializeMap;
use serde::{Serialize, Serializer};
/// Parse Matrix media URL returning media id and server name pub struct ApiMxcURI(pub OwnedMxcUri);
pub fn parse_mxc_url(url: &str) -> Option<(&str, OwnedServerName)> {
let strip = url.strip_prefix("mxc://")?;
let parts = strip.split_once('/')?;
Some((parts.0, OwnedServerName::from_str(parts.1).ok()?)) impl Serialize for ApiMxcURI {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(3))?;
map.serialize_entry("uri", &self.0)?;
map.serialize_entry("server_name", &self.0.server_name().ok())?;
map.serialize_entry("media_id", &self.0.media_id().ok())?;
map.end()
}
} }