use itertools::Itertools;
use reqwest::Url;
use salvo::prelude::*;
use serde::{Deserialize, Serialize};
use crate::events::{AnyStrippedStateEvent, StateEventType, room::member::RoomMemberEventContent};
use crate::identifiers::*;
use crate::sending::{SendRequest, SendResult};
use crate::{RawJsonValue, UnixMillis, serde::RawJson};
pub fn invite_user_request_v2(
origin: &str,
args: InviteUserReqArgs,
body: InviteUserReqBodyV2,
) -> SendResult<SendRequest> {
let url = Url::parse(&format!(
"{origin}/_matrix/federation/v2/invite/{}/{}",
args.room_id, args.event_id
))?;
crate::sending::put(url).stuff(body)
}
#[derive(ToParameters, Deserialize, Debug)]
pub struct InviteUserReqArgs {
#[salvo(parameter(parameter_in = Path))]
pub room_id: OwnedRoomId,
#[salvo(parameter(parameter_in = Path))]
pub event_id: OwnedEventId,
}
#[derive(ToSchema, Deserialize, Serialize, Debug)]
pub struct InviteUserReqBodyV2 {
pub room_version: RoomVersionId,
#[salvo(schema(value_type = Object, additional_properties = true))]
pub event: Box<RawJsonValue>,
pub invite_room_state: Vec<RawJson<AnyStrippedStateEvent>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "org.matrix.msc4125.via")]
pub via: Option<Vec<OwnedServerName>>,
}
crate::json_body_modifier!(InviteUserReqBodyV2);
#[derive(ToSchema, Deserialize, Debug)]
pub struct InviteUserReqBodyV1 {
pub sender: OwnedUserId,
pub origin: OwnedServerName,
pub origin_server_ts: UnixMillis,
#[serde(rename = "type")]
pub kind: StateEventType,
pub state_key: OwnedUserId,
pub content: RoomMemberEventContent,
#[serde(default, skip_serializing_if = "UnsignedEventContent::is_empty")]
pub unsigned: UnsignedEventContentV1,
}
#[derive(ToSchema, Serialize, Deserialize, Debug)]
pub struct InviteUserResBodyV2 {
#[salvo(schema(value_type = Object))]
pub event: Box<RawJsonValue>,
}
#[derive(ToSchema, Serialize, Debug)]
pub struct InviteUserResBodyV1 {
#[serde(with = "crate::federation::serde::v1_pdu")]
#[salvo(schema(value_type = Object))]
pub event: Box<RawJsonValue>,
}
#[derive(ToSchema, Deserialize, Serialize, Debug)]
#[salvo(schema(value_type = Object))]
pub struct SendJoinReqBody(
pub Box<RawJsonValue>,
);
crate::json_body_modifier!(SendJoinReqBody);
#[derive(ToSchema, Deserialize, Serialize, Debug)]
pub struct SendJoinResBodyV2(
pub RoomStateV2,
);
#[derive(ToSchema, Serialize, Debug)]
pub struct SendJoinResBodyV1(
pub RoomStateV1,
);
impl SendJoinResBodyV1 {
pub fn new(room_state: RoomStateV1) -> Self {
Self(room_state)
}
}
#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
pub struct RoomStateV2 {
#[serde(default, skip_serializing_if = "crate::serde::is_default")]
pub members_omitted: bool,
#[salvo(schema(value_type = Vec<Object>))]
pub auth_chain: Vec<Box<RawJsonValue>>,
#[salvo(schema(value_type = Object))]
pub state: Vec<Box<RawJsonValue>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[salvo(schema(value_type = Object))]
pub event: Option<Box<RawJsonValue>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub servers_in_room: Option<Vec<String>>,
}
impl RoomStateV2 {
pub fn new() -> Self {
Self {
auth_chain: Vec::new(),
state: Vec::new(),
event: None,
members_omitted: false,
servers_in_room: None,
}
}
}
#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
pub struct RoomStateV1 {
#[salvo(schema(value_type = Vec<Object>))]
pub auth_chain: Vec<Box<RawJsonValue>>,
#[salvo(schema(value_type = Vec<Object>))]
pub state: Vec<Box<RawJsonValue>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[salvo(schema(value_type = Vec<Object>))]
pub event: Option<Box<RawJsonValue>>,
}
impl RoomStateV1 {
pub fn new() -> Self {
Self {
auth_chain: Vec::new(),
state: Vec::new(),
event: None,
}
}
}
#[derive(ToSchema, Clone, Debug, Default, Serialize, Deserialize)]
pub struct UnsignedEventContentV1 {
#[serde(skip_serializing_if = "<[_]>::is_empty")]
#[salvo(schema(value_type = Vec<Object>))]
pub invite_room_state: Vec<RawJson<AnyStrippedStateEvent>>,
}
impl UnsignedEventContentV1 {
pub fn new() -> Self {
Default::default()
}
pub fn is_empty(&self) -> bool {
self.invite_room_state.is_empty()
}
}
pub fn make_leave_request(origin: &str, room_id: &RoomId, user_id: &UserId) -> SendResult<SendRequest> {
let url = Url::parse(&format!(
"{origin}/_matrix/federation/v1/make_leave/{room_id}/{user_id}"
))?;
Ok(crate::sending::get(url))
}
#[derive(ToParameters, Deserialize, Debug)]
pub struct MakeLeaveReqArgs {
#[salvo(parameter(parameter_in = Path))]
pub room_id: OwnedRoomId,
#[salvo(parameter(parameter_in = Path))]
pub user_id: OwnedUserId,
}
#[derive(ToSchema, Serialize, Deserialize, Debug)]
pub struct MakeLeaveResBody {
pub room_version: Option<RoomVersionId>,
#[salvo(schema(value_type = Object, additional_properties = true))]
pub event: Box<RawJsonValue>,
}
impl MakeLeaveResBody {
pub fn new(room_version: Option<RoomVersionId>, event: Box<RawJsonValue>) -> Self {
Self { room_version, event }
}
}
pub fn send_leave_request_v2(
origin: &str,
args: SendLeaveReqArgsV2,
body: SendLeaveReqBody,
) -> SendResult<SendRequest> {
let url = Url::parse(&format!(
"{origin}/_matrix/federation/v2/send_leave/{}/{}",
args.room_id, args.event_id
))?;
crate::sending::put(url).stuff(body)
}
#[derive(ToParameters, Deserialize, Serialize, Debug)]
pub struct SendLeaveReqArgsV2 {
#[salvo(parameter(parameter_in = Path))]
pub room_id: OwnedRoomId,
#[salvo(parameter(parameter_in = Path))]
pub event_id: OwnedEventId,
}
#[derive(ToSchema, Deserialize, Serialize, Debug)]
#[salvo(schema(value_type = Object))]
pub struct SendLeaveReqBody(
pub Box<RawJsonValue>,
);
crate::json_body_modifier!(SendLeaveReqBody);
pub fn send_join_request(origin: &str, args: SendJoinArgs, body: SendJoinReqBody) -> SendResult<SendRequest> {
let url = Url::parse(&format!(
"{origin}/_matrix/federation/v2/send_join/{}/{}?omit_members={}",
&args.room_id, &args.event_id, args.omit_members
))?;
crate::sending::put(url).stuff(body)
}
#[derive(ToParameters, Deserialize, Debug)]
pub struct SendJoinArgs {
#[salvo(parameter(parameter_in = Path))]
pub room_id: OwnedRoomId,
#[salvo(parameter(parameter_in = Path))]
pub event_id: OwnedEventId,
#[salvo(parameter(parameter_in = Query))]
#[serde(default, skip_serializing_if = "crate::serde::is_default")]
pub omit_members: bool,
}
pub fn make_join_request(origin: &str, args: MakeJoinReqArgs) -> SendResult<SendRequest> {
let ver = args.ver.iter().map(|v| format!("ver={v}")).join("&");
let ver = if ver.is_empty() { "" } else { &*format!("?{}", ver) };
let url = Url::parse(&format!(
"{origin}/_matrix/federation/v1/make_join/{}/{}{}",
args.room_id, args.user_id, ver
))?;
Ok(crate::sending::get(url))
}
#[derive(ToParameters, Deserialize, Debug)]
pub struct MakeJoinReqArgs {
#[salvo(parameter(parameter_in = Path))]
pub room_id: OwnedRoomId,
#[salvo(parameter(parameter_in = Path))]
pub user_id: OwnedUserId,
#[salvo(parameter(parameter_in = Query))]
#[serde(default = "default_ver", skip_serializing_if = "is_default_ver")]
pub ver: Vec<RoomVersionId>,
}
#[derive(ToSchema, Serialize, Deserialize, Debug)]
pub struct MakeJoinResBody {
#[serde(skip_serializing_if = "Option::is_none")]
pub room_version: Option<RoomVersionId>,
#[salvo(schema(value_type = Object, additional_properties = true))]
pub event: Box<RawJsonValue>,
}
impl MakeJoinResBody {
pub fn new(event: Box<RawJsonValue>) -> Self {
Self {
room_version: None,
event,
}
}
}
fn default_ver() -> Vec<RoomVersionId> {
vec![RoomVersionId::V1]
}
fn is_default_ver(ver: &[RoomVersionId]) -> bool {
*ver == [RoomVersionId::V1]
}