use crate::controllers::HttpResult; use crate::controllers::matrix::matrix_event_controller::{APIEvent, get_events}; use crate::controllers::matrix::matrix_media_controller; use crate::extractors::matrix_client_extractor::MatrixClientExtractor; use actix_web::{HttpRequest, HttpResponse, web}; use futures_util::{StreamExt, stream}; use matrix_sdk::room::ParentSpace; use matrix_sdk::ruma::{OwnedMxcUri, OwnedRoomId, OwnedUserId}; use matrix_sdk::{Room, RoomMemberships}; #[derive(serde::Serialize)] pub struct APIRoomInfo { id: OwnedRoomId, name: Option, members: Vec, avatar: Option, is_space: bool, parents: Vec, number_unread_messages: u64, latest_event: Option, } impl APIRoomInfo { async fn from_room(r: &Room) -> anyhow::Result { // Get parent spaces let parent_spaces = r .parent_spaces() .await? .collect::>() .await .into_iter() .collect::, _>>()? .into_iter() .filter_map(|d| match d { ParentSpace::Reciprocal(r) | ParentSpace::WithPowerlevel(r) => { Some(r.room_id().to_owned()) } _ => None, }) .collect::>(); Ok(Self { id: r.room_id().to_owned(), name: r.name(), members: r .members(RoomMemberships::ACTIVE) .await? .into_iter() .map(|r| r.user_id().to_owned()) .collect::>(), avatar: r.avatar_url(), is_space: r.is_space(), parents: parent_spaces, number_unread_messages: r.unread_notification_counts().notification_count, latest_event: get_events(r, 1, None).await?.messages.into_iter().next(), }) } } /// Get the list of joined rooms of the user pub async fn joined_rooms(client: MatrixClientExtractor) -> HttpResult { let list = stream::iter(client.client.client.joined_rooms()) .then(async |room| APIRoomInfo::from_room(&room).await) .collect::>() .await .into_iter() .collect::, _>>()?; Ok(HttpResponse::Ok().json(list)) } /// Get joined spaces rooms of user pub async fn get_joined_spaces(client: MatrixClientExtractor) -> HttpResult { let list = stream::iter(client.client.client.joined_space_rooms()) .then(async |room| APIRoomInfo::from_room(&room).await) .collect::>() .await .into_iter() .collect::, _>>()?; Ok(HttpResponse::Ok().json(list)) } #[derive(serde::Deserialize)] pub struct RoomIdInPath { pub(crate) room_id: OwnedRoomId, } /// Get the list of joined rooms of the user pub async fn single_room_info( client: MatrixClientExtractor, path: web::Path, ) -> HttpResult { Ok(match client.client.client.get_room(&path.room_id) { None => HttpResponse::NotFound().json("Room not found"), Some(r) => HttpResponse::Ok().json(APIRoomInfo::from_room(&r).await?), }) } /// Get room avatar pub async fn room_avatar( req: HttpRequest, client: MatrixClientExtractor, path: web::Path, ) -> HttpResult { let Some(room) = client.client.client.get_room(&path.room_id) else { return Ok(HttpResponse::NotFound().json("Room not found")); }; let Some(uri) = room.avatar_url() else { return Ok(HttpResponse::NotFound().json("Room has no avatar")); }; matrix_media_controller::serve_media(req, uri).await }