Files
continuwuity/src/api/client/state.rs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

186 lines
5.2 KiB
Rust
Raw Normal View History

#[cfg(test)]
mod tests;
2024-07-16 08:05:25 +00:00
use axum::extract::State;
use conduwuit::{
Err, Result, err,
2026-04-10 11:47:01 -04:00
matrix::{Event, pdu::PartialPdu},
};
use conduwuit_service::Services;
2025-04-26 08:23:57 +00:00
use futures::{FutureExt, TryStreamExt};
2020-07-30 18:14:47 +02:00
use ruma::{
RoomId,
2026-04-11 19:35:38 -04:00
api::client::state::{
get_state_event_for_key::{self, v3::StateEventFormat},
get_state_events, send_state_event,
},
2020-07-30 18:14:47 +02:00
};
2026-04-11 19:35:38 -04:00
use serde_json::{json, value::to_raw_value};
2020-07-30 18:14:47 +02:00
use crate::{Ruma, RumaResponse, client_ip::ClientIp};
2024-03-05 19:48:54 -05:00
2024-03-27 20:06:56 -04:00
/// # `PUT /_matrix/client/*/rooms/{roomId}/state/{eventType}/{stateKey}`
2021-08-31 19:14:37 +02:00
///
/// Sends a state event into the room.
2024-04-22 23:48:57 -04:00
pub(crate) async fn send_state_event_for_key_route(
State(services): State<crate::State>,
ClientIp(ip): ClientIp, // NOTE: Required for updating device metadata
body: Ruma<send_state_event::v3::Request>,
2022-02-18 15:33:14 +01:00
) -> Result<send_state_event::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
services
.users
.update_device_last_seen(sender_user, body.identity.sender_device(), ip)
.await;
2020-07-30 18:14:47 +02:00
if services.users.is_suspended(sender_user).await? {
return Err!(Request(UserSuspended("You cannot perform this action while suspended.")));
}
let state_lock = services
.rooms
.state
.mutex
.lock::<RoomId>(&body.room_id)
.await;
let event_id = services
.rooms
.timeline
.send_state_event_for_key(
sender_user,
&body.room_id,
&state_lock,
&body.event_type,
&body.body.body,
&body.state_key,
if body.identity.is_appservice() {
body.timestamp
} else {
None
},
)
.boxed()
.await?;
2026-04-11 19:35:38 -04:00
Ok(send_state_event::v3::Response::new(event_id))
2020-07-30 18:14:47 +02:00
}
2024-03-27 20:06:56 -04:00
/// # `PUT /_matrix/client/*/rooms/{roomId}/state/{eventType}`
2021-08-31 19:14:37 +02:00
///
/// Sends a state event into the room.
2024-04-22 23:48:57 -04:00
pub(crate) async fn send_state_event_for_empty_key_route(
State(services): State<crate::State>,
ClientIp(ip): ClientIp, // NOTE: Required for updating device metadata
body: Ruma<send_state_event::v3::Request>,
2022-02-18 15:33:14 +01:00
) -> Result<RumaResponse<send_state_event::v3::Response>> {
2026-04-23 20:02:48 +01:00
send_state_event_for_key_route(State(services), ClientIp(ip), body)
2025-04-26 08:23:57 +00:00
.boxed()
2024-07-16 08:05:25 +00:00
.await
.map(RumaResponse)
2020-07-30 18:14:47 +02:00
}
2024-03-16 13:22:15 -04:00
/// # `GET /_matrix/client/v3/rooms/{roomid}/state`
2021-08-31 19:14:37 +02:00
///
/// Get all state events for a room.
///
/// - If not joined: Only works if current room history visibility is world
/// readable
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_state_events_route(
State(services): State<crate::State>,
body: Ruma<get_state_events::v3::Request>,
2022-02-18 15:33:14 +01:00
) -> Result<get_state_events::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
2020-07-30 18:14:47 +02:00
2024-07-16 08:05:25 +00:00
if !services
2024-03-25 17:05:11 -04:00
.rooms
.state_accessor
2024-08-08 17:18:30 +00:00
.user_can_see_state_events(sender_user, &body.room_id)
.await
2024-03-25 17:05:11 -04:00
{
2024-08-08 17:18:30 +00:00
return Err!(Request(Forbidden("You don't have permission to view the room state.")));
2020-07-30 18:14:47 +02:00
}
2026-04-11 19:35:38 -04:00
let room_state = services
.rooms
.state_accessor
.room_state_full_pdus(&body.room_id)
.map_ok(Event::into_format)
.try_collect()
.await?;
Ok(get_state_events::v3::Response::new(room_state))
2020-07-30 18:14:47 +02:00
}
/// # `GET /_matrix/client/v3/rooms/{roomid}/state/{eventType}/{stateKey}`
2021-08-31 19:14:37 +02:00
///
/// Get single state event of a room with the specified state key.
/// The optional query parameter `?format=event|content` allows returning the
/// full room state event or just the state event's content (default behaviour)
2021-08-31 19:14:37 +02:00
///
/// - If not joined: Only works if current room history visibility is world
/// readable
2026-04-11 19:35:38 -04:00
pub(crate) async fn get_state_event_for_key_route(
State(services): State<crate::State>,
2026-04-11 19:35:38 -04:00
body: Ruma<get_state_event_for_key::v3::Request>,
) -> Result<get_state_event_for_key::v3::Response> {
let sender_user = body.identity.expect_sender_user()?;
2020-07-30 18:14:47 +02:00
2024-07-16 08:05:25 +00:00
if !services
2024-03-25 17:05:11 -04:00
.rooms
.state_accessor
2024-08-08 17:18:30 +00:00
.user_can_see_state_events(sender_user, &body.room_id)
.await
2024-03-25 17:05:11 -04:00
{
2025-03-09 13:44:57 -04:00
return Err!(Request(NotFound(debug_warn!(
"You don't have permission to view the room state."
))));
2020-07-30 18:14:47 +02:00
}
2024-07-16 08:05:25 +00:00
let event = services
2024-03-25 17:05:11 -04:00
.rooms
.state_accessor
2024-08-08 17:18:30 +00:00
.room_state_get(&body.room_id, &body.event_type, &body.state_key)
.await
.map_err(|_| {
2024-10-02 01:47:19 -04:00
err!(Request(NotFound(debug_warn!(
2026-01-04 03:04:37 +00:00
room_id = %body.room_id,
event_type = %body.event_type,
2024-08-08 17:18:30 +00:00
"State event not found in room.",
))))
2024-03-25 17:05:11 -04:00
})?;
2024-08-08 17:18:30 +00:00
2026-04-11 19:35:38 -04:00
let content = match body.format {
| StateEventFormat::Content => event.content,
| StateEventFormat::Event => to_raw_value(&json!({
"content": event.content(),
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"room_id": event.room_id_or_hash(),
"sender": event.sender(),
"state_key": event.state_key(),
"type": event.kind(),
"unsigned": event.unsigned(),
}))
.unwrap(),
| _ => return Err!(Request(InvalidParam("Unknown response format"))),
};
2026-04-11 19:35:38 -04:00
Ok(get_state_event_for_key::v3::Response::new(content))
2020-07-30 18:14:47 +02:00
}
/// # `GET /_matrix/client/v3/rooms/{roomid}/state/{eventType}`
2021-08-31 19:14:37 +02:00
///
/// Get single state event of a room.
/// The optional query parameter `?format=event|content` allows returning the
/// full room state event or just the state event's content (default behaviour)
2021-08-31 19:14:37 +02:00
///
/// - If not joined: Only works if current room history visibility is world
/// readable
2024-04-22 23:48:57 -04:00
pub(crate) async fn get_state_events_for_empty_key_route(
State(services): State<crate::State>,
2026-04-11 19:35:38 -04:00
body: Ruma<get_state_event_for_key::v3::Request>,
) -> Result<RumaResponse<get_state_event_for_key::v3::Response>> {
get_state_event_for_key_route(State(services), body)
2024-07-16 08:05:25 +00:00
.await
.map(RumaResponse)
2020-07-30 18:14:47 +02:00
}