diff --git a/matrixgw_backend/src/controllers/matrix/matrix_event_controller.rs b/matrixgw_backend/src/controllers/matrix/matrix_event_controller.rs index 94e4eb1..93baf63 100644 --- a/matrixgw_backend/src/controllers/matrix/matrix_event_controller.rs +++ b/matrixgw_backend/src/controllers/matrix/matrix_event_controller.rs @@ -11,6 +11,7 @@ use matrix_sdk::deserialized_responses::{TimelineEvent, TimelineEventKind}; use matrix_sdk::media::MediaEventContent; use matrix_sdk::room::MessagesOptions; use matrix_sdk::room::edit::EditedContent; +use matrix_sdk::ruma::api::client::filter::RoomEventFilter; use matrix_sdk::ruma::api::client::receipt::create_receipt::v3::ReceiptType; use matrix_sdk::ruma::events::reaction::ReactionEventContent; use matrix_sdk::ruma::events::receipt::ReceiptThread; @@ -25,7 +26,7 @@ use serde_json::value::RawValue; #[derive(Serialize)] pub struct APIEvent { - id: OwnedEventId, + pub id: OwnedEventId, time: MilliSecondsSinceUnixEpoch, sender: OwnedUserId, data: Box, @@ -63,10 +64,14 @@ pub(super) async fn get_events( room: &Room, limit: u32, from: Option<&str>, + filter: Option, ) -> anyhow::Result { let mut msg_opts = MessagesOptions::backward(); msg_opts.from = from.map(str::to_string); msg_opts.limit = UInt::from(limit); + if let Some(filter) = filter { + msg_opts.filter = filter; + } let messages = room.messages(msg_opts).await?; Ok(APIEventsList { @@ -99,8 +104,15 @@ pub async fn get_for_room( return Ok(HttpResponse::NotFound().json("Room not found!")); }; - Ok(HttpResponse::Ok() - .json(get_events(&room, query.limit.unwrap_or(500), query.from.as_deref()).await?)) + Ok(HttpResponse::Ok().json( + get_events( + &room, + query.limit.unwrap_or(500), + query.from.as_deref(), + None, + ) + .await?, + )) } #[derive(Deserialize)] @@ -281,7 +293,7 @@ pub async fn receipt( room.send_single_receipt( ReceiptType::Read, - ReceiptThread::default(), + ReceiptThread::Main, event_path.event_id.clone(), ) .await?; diff --git a/matrixgw_backend/src/controllers/matrix/matrix_room_controller.rs b/matrixgw_backend/src/controllers/matrix/matrix_room_controller.rs index c106eca..cd63c9b 100644 --- a/matrixgw_backend/src/controllers/matrix/matrix_room_controller.rs +++ b/matrixgw_backend/src/controllers/matrix/matrix_room_controller.rs @@ -8,7 +8,10 @@ use matrix_sdk::notification_settings::{ IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode, }; use matrix_sdk::room::ParentSpace; -use matrix_sdk::ruma::{OwnedMxcUri, OwnedRoomId, OwnedUserId}; +use matrix_sdk::ruma::events::receipt::{ReceiptThread, ReceiptType}; +use matrix_sdk::ruma::{ + MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedUserId, +}; use matrix_sdk::{Room, RoomMemberships}; #[derive(serde::Serialize)] @@ -71,7 +74,11 @@ impl APIRoomInfo { parents: parent_spaces, number_unread_messages: r.unread_notification_counts().notification_count, notifications, - latest_event: get_events(r, 1, None).await?.events.into_iter().next(), + latest_event: get_events(r, 1, None, None) + .await? + .events + .into_iter() + .next(), }) } } @@ -137,3 +144,37 @@ pub async fn room_avatar( matrix_media_controller::serve_mxc_file(req, uri).await } + +#[derive(serde::Serialize)] +pub struct UserReceipt { + user: OwnedUserId, + event_id: OwnedEventId, + ts: Option, +} + +/// Get room receipts +pub async fn receipts(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 members = room.members(RoomMemberships::ACTIVE).await?; + + let mut receipts = Vec::new(); + for m in members { + let Some((event_id, receipt)) = room + .load_user_receipt(ReceiptType::Read, ReceiptThread::Main, m.user_id()) + .await? + else { + continue; + }; + + receipts.push(UserReceipt { + user: m.user_id().to_owned(), + event_id, + ts: receipt.ts, + }) + } + + Ok(HttpResponse::Ok().json(receipts)) +} diff --git a/matrixgw_backend/src/main.rs b/matrixgw_backend/src/main.rs index 1713864..6137319 100644 --- a/matrixgw_backend/src/main.rs +++ b/matrixgw_backend/src/main.rs @@ -155,6 +155,10 @@ async fn main() -> std::io::Result<()> { "/api/matrix/room/{room_id}/avatar", web::get().to(matrix_room_controller::room_avatar), ) + .route( + "/api/matrix/room/{room_id}/receipts", + web::get().to(matrix_room_controller::receipts), + ) // Matrix profile controller .route( "/api/matrix/profile/{user_id}", @@ -189,7 +193,7 @@ async fn main() -> std::io::Result<()> { "/api/matrix/room/{room_id}/event/{event_id}", web::delete().to(matrix_event_controller::redact_event), ) - .route( + .route( "/api/matrix/room/{room_id}/event/{event_id}/receipt", web::post().to(matrix_event_controller::receipt), )