1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! `/v1/` ([spec])
//!
//! [spec]: https://spec.matrix.org/latest/server-server-api/#put_matrixfederationv1inviteroomideventid

use ruma_common::{
    api::{request, response, Metadata},
    metadata,
    serde::Raw,
    MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId,
};
use ruma_events::{room::member::RoomMemberEventContent, AnyStrippedStateEvent, StateEventType};
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue;

const METADATA: Metadata = metadata! {
    method: PUT,
    rate_limited: false,
    authentication: ServerSignatures,
    history: {
        1.0 => "/_matrix/federation/v1/invite/:room_id/:event_id",
    }
};

/// Request type for the `create_invite` endpoint.
#[request]
pub struct Request {
    /// The room ID that the user is being invited to.
    #[ruma_api(path)]
    pub room_id: OwnedRoomId,

    /// The event ID for the invite event, generated by the inviting server.
    #[ruma_api(path)]
    pub event_id: OwnedEventId,

    /// The matrix ID of the user who sent the original `m.room.third_party_invite`.
    pub sender: OwnedUserId,

    /// The name of the inviting homeserver.
    pub origin: OwnedServerName,

    /// A timestamp added by the inviting homeserver.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// The value `m.room.member`.
    #[serde(rename = "type")]
    pub kind: StateEventType,

    /// The user ID of the invited member.
    pub state_key: OwnedUserId,

    /// The content of the event.
    pub content: RoomMemberEventContent,

    /// Information included alongside the event that is not signed.
    #[serde(default, skip_serializing_if = "UnsignedEventContent::is_empty")]
    pub unsigned: UnsignedEventContent,
}

/// Response type for the `create_invite` endpoint.
#[response]
pub struct Response {
    /// The signed invite event.
    #[ruma_api(body)]
    #[serde(with = "crate::serde::v1_pdu")]
    pub event: Box<RawJsonValue>,
}

/// Information included alongside an event that is not signed.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct UnsignedEventContent {
    /// An optional list of simplified events to help the receiver of the invite identify the room.
    /// The recommended events to include are the join rules, canonical alias, avatar, and name of
    /// the room.
    #[serde(skip_serializing_if = "<[_]>::is_empty")]
    pub invite_room_state: Vec<Raw<AnyStrippedStateEvent>>,
}

impl UnsignedEventContent {
    /// Creates an empty `UnsignedEventContent`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Checks whether all of the fields are empty.
    pub fn is_empty(&self) -> bool {
        self.invite_room_state.is_empty()
    }
}

/// Initial set of fields of `Request`.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct RequestInit {
    /// The room ID that the user is being invited to.
    pub room_id: OwnedRoomId,

    /// The event ID for the invite event, generated by the inviting server.
    pub event_id: OwnedEventId,

    /// The matrix ID of the user who sent the original `m.room.third_party_invite`.
    pub sender: OwnedUserId,

    /// The name of the inviting homeserver.
    pub origin: OwnedServerName,

    /// A timestamp added by the inviting homeserver.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    /// The user ID of the invited member.
    pub state_key: OwnedUserId,

    /// The content of the event.
    pub content: RoomMemberEventContent,

    /// Information included alongside the event that is not signed.
    pub unsigned: UnsignedEventContent,
}

impl From<RequestInit> for Request {
    /// Creates a new `Request` from `RequestInit`.
    fn from(init: RequestInit) -> Self {
        Self {
            room_id: init.room_id,
            event_id: init.event_id,
            sender: init.sender,
            origin: init.origin,
            origin_server_ts: init.origin_server_ts,
            kind: StateEventType::RoomMember,
            state_key: init.state_key,
            content: init.content,
            unsigned: init.unsigned,
        }
    }
}

impl Response {
    /// Creates a new `Response` with the given invite event.
    pub fn new(event: Box<RawJsonValue>) -> Self {
        Self { event }
    }
}