Compare commits
3 Commits
196671d0fb
...
dac20f60e0
| Author | SHA1 | Date | |
|---|---|---|---|
| dac20f60e0 | |||
| 9359dc5be0 | |||
| 849aef9343 |
@@ -11,7 +11,10 @@ use matrix_sdk::deserialized_responses::{TimelineEvent, TimelineEventKind};
|
|||||||
use matrix_sdk::media::MediaEventContent;
|
use matrix_sdk::media::MediaEventContent;
|
||||||
use matrix_sdk::room::MessagesOptions;
|
use matrix_sdk::room::MessagesOptions;
|
||||||
use matrix_sdk::room::edit::EditedContent;
|
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::reaction::ReactionEventContent;
|
||||||
|
use matrix_sdk::ruma::events::receipt::ReceiptThread;
|
||||||
use matrix_sdk::ruma::events::relation::Annotation;
|
use matrix_sdk::ruma::events::relation::Annotation;
|
||||||
use matrix_sdk::ruma::events::room::message::{
|
use matrix_sdk::ruma::events::room::message::{
|
||||||
MessageType, RoomMessageEvent, RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
|
MessageType, RoomMessageEvent, RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
|
||||||
@@ -23,7 +26,7 @@ use serde_json::value::RawValue;
|
|||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct APIEvent {
|
pub struct APIEvent {
|
||||||
id: OwnedEventId,
|
pub id: OwnedEventId,
|
||||||
time: MilliSecondsSinceUnixEpoch,
|
time: MilliSecondsSinceUnixEpoch,
|
||||||
sender: OwnedUserId,
|
sender: OwnedUserId,
|
||||||
data: Box<RawValue>,
|
data: Box<RawValue>,
|
||||||
@@ -61,10 +64,14 @@ pub(super) async fn get_events(
|
|||||||
room: &Room,
|
room: &Room,
|
||||||
limit: u32,
|
limit: u32,
|
||||||
from: Option<&str>,
|
from: Option<&str>,
|
||||||
|
filter: Option<RoomEventFilter>,
|
||||||
) -> anyhow::Result<APIEventsList> {
|
) -> anyhow::Result<APIEventsList> {
|
||||||
let mut msg_opts = MessagesOptions::backward();
|
let mut msg_opts = MessagesOptions::backward();
|
||||||
msg_opts.from = from.map(str::to_string);
|
msg_opts.from = from.map(str::to_string);
|
||||||
msg_opts.limit = UInt::from(limit);
|
msg_opts.limit = UInt::from(limit);
|
||||||
|
if let Some(filter) = filter {
|
||||||
|
msg_opts.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
let messages = room.messages(msg_opts).await?;
|
let messages = room.messages(msg_opts).await?;
|
||||||
Ok(APIEventsList {
|
Ok(APIEventsList {
|
||||||
@@ -97,8 +104,15 @@ pub async fn get_for_room(
|
|||||||
return Ok(HttpResponse::NotFound().json("Room not found!"));
|
return Ok(HttpResponse::NotFound().json("Room not found!"));
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok().json(
|
||||||
.json(get_events(&room, query.limit.unwrap_or(500), query.from.as_deref()).await?))
|
get_events(
|
||||||
|
&room,
|
||||||
|
query.limit.unwrap_or(500),
|
||||||
|
query.from.as_deref(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -266,3 +280,23 @@ pub async fn redact_event(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send receipt for event
|
||||||
|
pub async fn receipt(
|
||||||
|
client: MatrixClientExtractor,
|
||||||
|
path: web::Path<RoomIdInPath>,
|
||||||
|
event_path: web::Path<EventIdInPath>,
|
||||||
|
) -> HttpResult {
|
||||||
|
let Some(room) = client.client.client.get_room(&path.room_id) else {
|
||||||
|
return Ok(HttpResponse::NotFound().json("Room not found"));
|
||||||
|
};
|
||||||
|
|
||||||
|
room.send_single_receipt(
|
||||||
|
ReceiptType::Read,
|
||||||
|
ReceiptThread::Main,
|
||||||
|
event_path.event_id.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Accepted().finish())
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ use matrix_sdk::notification_settings::{
|
|||||||
IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode,
|
IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode,
|
||||||
};
|
};
|
||||||
use matrix_sdk::room::ParentSpace;
|
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};
|
use matrix_sdk::{Room, RoomMemberships};
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
@@ -71,7 +74,11 @@ impl APIRoomInfo {
|
|||||||
parents: parent_spaces,
|
parents: parent_spaces,
|
||||||
number_unread_messages: r.unread_notification_counts().notification_count,
|
number_unread_messages: r.unread_notification_counts().notification_count,
|
||||||
notifications,
|
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
|
matrix_media_controller::serve_mxc_file(req, uri).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
pub struct UserReceipt {
|
||||||
|
user: OwnedUserId,
|
||||||
|
event_id: OwnedEventId,
|
||||||
|
ts: Option<MilliSecondsSinceUnixEpoch>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get room receipts
|
||||||
|
pub async fn receipts(client: MatrixClientExtractor, path: web::Path<RoomIdInPath>) -> 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))
|
||||||
|
}
|
||||||
|
|||||||
@@ -155,6 +155,10 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/api/matrix/room/{room_id}/avatar",
|
"/api/matrix/room/{room_id}/avatar",
|
||||||
web::get().to(matrix_room_controller::room_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
|
// Matrix profile controller
|
||||||
.route(
|
.route(
|
||||||
"/api/matrix/profile/{user_id}",
|
"/api/matrix/profile/{user_id}",
|
||||||
@@ -189,6 +193,10 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/api/matrix/room/{room_id}/event/{event_id}",
|
"/api/matrix/room/{room_id}/event/{event_id}",
|
||||||
web::delete().to(matrix_event_controller::redact_event),
|
web::delete().to(matrix_event_controller::redact_event),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/api/matrix/room/{room_id}/event/{event_id}/receipt",
|
||||||
|
web::post().to(matrix_event_controller::receipt),
|
||||||
|
)
|
||||||
// Matrix media controller
|
// Matrix media controller
|
||||||
.route(
|
.route(
|
||||||
"/api/matrix/media/{mxc}",
|
"/api/matrix/media/{mxc}",
|
||||||
|
|||||||
@@ -140,4 +140,14 @@ export class MatrixApiEvent {
|
|||||||
uri: `/matrix/room/${room.id}/event/${event_id}`,
|
uri: `/matrix/room/${room.id}/event/${event_id}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send event receipt
|
||||||
|
*/
|
||||||
|
static async SendReceipt(room: Room, event_id: string): Promise<void> {
|
||||||
|
await APIClient.exec({
|
||||||
|
method: "POST",
|
||||||
|
uri: `/matrix/room/${room.id}/event/${event_id}/receipt`,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ function _MainMessageWidget(p: {
|
|||||||
p.onRoomsListUpdate((r) => {
|
p.onRoomsListUpdate((r) => {
|
||||||
const n = [...r];
|
const n = [...r];
|
||||||
const idx = r.findIndex((el) => el.id === m.room_id);
|
const idx = r.findIndex((el) => el.id === m.room_id);
|
||||||
if (idx)
|
if (idx && n[idx].notifications === "AllMessages")
|
||||||
n[idx] = {
|
n[idx] = {
|
||||||
...n[idx],
|
...n[idx],
|
||||||
number_unread_messages: n[idx].number_unread_messages + 1,
|
number_unread_messages: n[idx].number_unread_messages + 1,
|
||||||
|
|||||||
@@ -4,14 +4,37 @@ import type { Room } from "../../api/matrix/MatrixApiRoom";
|
|||||||
import { RoomEventsManager } from "../../utils/RoomEventsManager";
|
import { RoomEventsManager } from "../../utils/RoomEventsManager";
|
||||||
import { RoomMessagesList } from "./RoomMessagesList";
|
import { RoomMessagesList } from "./RoomMessagesList";
|
||||||
import { SendMessageForm } from "./SendMessageForm";
|
import { SendMessageForm } from "./SendMessageForm";
|
||||||
|
import { MatrixApiEvent } from "../../api/matrix/MatrixApiEvent";
|
||||||
|
import { useSnackbar } from "../../hooks/contexts_provider/SnackbarProvider";
|
||||||
|
|
||||||
export function RoomWidget(p: {
|
export function RoomWidget(p: {
|
||||||
room: Room;
|
room: Room;
|
||||||
users: UsersMap;
|
users: UsersMap;
|
||||||
manager: RoomEventsManager;
|
manager: RoomEventsManager;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
|
const receiptId = React.useRef<string | undefined>(undefined);
|
||||||
|
|
||||||
|
const handleRoomClick = async () => {
|
||||||
|
if (p.manager.messages.length === 0) return;
|
||||||
|
const latest = p.manager.messages[p.manager.messages.length - 1];
|
||||||
|
if (latest.event_id === receiptId.current) return;
|
||||||
|
|
||||||
|
receiptId.current = latest.event_id;
|
||||||
|
try {
|
||||||
|
await MatrixApiEvent.SendReceipt(p.room, latest.event_id);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to send read receipt!", e);
|
||||||
|
snackbar(`Failed to send read receipt! ${e}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "column", flex: 1 }}>
|
<div
|
||||||
|
style={{ display: "flex", flexDirection: "column", flex: 1 }}
|
||||||
|
onClick={handleRoomClick}
|
||||||
|
>
|
||||||
<RoomMessagesList {...p} />
|
<RoomMessagesList {...p} />
|
||||||
<SendMessageForm {...p} />
|
<SendMessageForm {...p} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user