palpo_core/push/
push_gateway.rs

1//! `GET /_matrix/client/*/notifications`
2//!
3//! Paginate through the list of events that the user has been, or would have been notified about.
4//! `/v3/` ([spec])
5//!
6//! [spec]: https://spec.matrix.org/latest/client-server-api/#get_matrixclientv3notifications
7use salvo::prelude::*;
8use serde::{Deserialize, Serialize};
9
10use crate::events::TimelineEventType;
11use crate::identifiers::*;
12use crate::push::{PusherData, Tweak};
13use crate::serde::StringEnum;
14use crate::{PrivOwnedStr, RawJsonValue, UnixSeconds};
15
16// const METADATA: Metadata = metadata! {
17//     method: POST,
18//     rate_limited: false,
19//     authentication: None,
20//     history: {
21//         1.0 => "/_matrix/push/v1/notify",
22//     }
23// };
24
25#[derive(ToSchema, Serialize, Debug)]
26pub struct SendEventNotificationReqBody {
27    /// Information about the push notification
28    pub notification: Notification,
29}
30crate::json_body_modifier!(SendEventNotificationReqBody);
31impl SendEventNotificationReqBody {
32    pub fn new(notification: Notification) -> Self {
33        Self { notification }
34    }
35}
36
37/// Response type for the `send_event_notification` endpoint.
38#[derive(ToSchema, Serialize, Debug)]
39pub struct SendEventNotificationResBody {
40    /// A list of all pushkeys given in the notification request that are not valid.
41    ///
42    /// These could have been rejected by an upstream gateway because they have expired or have
43    /// never been valid. Homeservers must cease sending notification requests for these
44    /// pushkeys and remove the associated pushers. It may not necessarily be the notification
45    /// in the request that failed: it could be that a previous notification to the same
46    /// pushkey failed. May be empty.
47    pub rejected: Vec<String>,
48}
49impl SendEventNotificationResBody {
50    /// Creates a new `Response` with the given list of rejected pushkeys.
51    pub fn new(rejected: Vec<String>) -> Self {
52        Self { rejected }
53    }
54}
55
56/// Represents a notification.
57#[derive(ToSchema, Default, Deserialize, Serialize, Clone, Debug)]
58pub struct Notification {
59    /// The Matrix event ID of the event being notified about.
60    ///
61    /// Required if the notification is about a particular Matrix event. May be omitted for
62    /// notifications that only contain updated badge counts. This ID can and should be used to
63    /// detect duplicate notification requests.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub event_id: Option<OwnedEventId>,
66
67    /// The ID of the room in which this event occurred.
68    ///
69    /// Required if the notification relates to a specific Matrix event.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub room_id: Option<OwnedRoomId>,
72
73    /// The type of the event as in the event's `type` field.
74    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
75    pub event_type: Option<TimelineEventType>,
76
77    /// The sender of the event as in the corresponding event field.
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub sender: Option<OwnedUserId>,
80
81    /// The current display name of the sender in the room in which the event occurred.
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub sender_display_name: Option<String>,
84
85    /// The name of the room in which the event occurred.
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub room_name: Option<String>,
88
89    /// An alias to display for the room in which the event occurred.
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub room_alias: Option<OwnedRoomAliasId>,
92
93    /// Whether the user receiving the notification is the subject of a member event (i.e. the
94    /// `state_key` of the member event is equal to the user's Matrix ID).
95    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
96    pub user_is_target: bool,
97
98    /// The priority of the notification.
99    ///
100    /// If omitted, `high` is assumed. This may be used by push gateways to deliver less
101    /// time-sensitive notifications in a way that will preserve battery power on mobile
102    /// devices.
103    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
104    pub prio: NotificationPriority,
105
106    /// The `content` field from the event, if present.
107    ///
108    /// The pusher may omit this if the event had no content or for any other reason.
109    #[serde(skip_serializing_if = "Option::is_none")]
110    #[salvo(schema(value_type = Object))]
111    pub content: Option<Box<RawJsonValue>>,
112
113    /// Current number of unacknowledged communications for the recipient user.
114    ///
115    /// Counts whose value is zero should be omitted.
116    #[serde(default, skip_serializing_if = "NotificationCounts::is_default")]
117    pub counts: NotificationCounts,
118
119    /// An array of devices that the notification should be sent to.
120    pub devices: Vec<Device>,
121}
122impl Notification {
123    /// Create a new notification for the given devices.
124    pub fn new(devices: Vec<Device>) -> Self {
125        Notification {
126            devices,
127            ..Default::default()
128        }
129    }
130}
131
132/// Type for passing information about notification priority.
133///
134/// This may be used by push gateways to deliver less time-sensitive
135/// notifications in a way that will preserve battery power on mobile devices.
136///
137/// This type can hold an arbitrary string. To build this with a custom value, convert it from a
138/// string with `::from()` / `.into()`. To check for values that are not available as a
139/// documented variant here, use its string representation, obtained through `.as_str()`.
140#[derive(ToSchema, Clone, Default, PartialEq, Eq, StringEnum)]
141#[palpo_enum(rename_all = "snake_case")]
142#[non_exhaustive]
143pub enum NotificationPriority {
144    /// A high priority notification
145    #[default]
146    High,
147
148    /// A low priority notification
149    Low,
150
151    #[doc(hidden)]
152    #[salvo(schema(skip))]
153    _Custom(PrivOwnedStr),
154}
155
156/// Type for passing information about notification counts.
157#[derive(ToSchema, Deserialize, Serialize, Default, Clone, Debug)]
158pub struct NotificationCounts {
159    /// The number of unread messages a user has across all of the rooms they
160    /// are a member of.
161    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
162    pub unread: usize,
163
164    /// The number of unacknowledged missed calls a user has across all rooms of
165    /// which they are a member.
166    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
167    pub missed_calls: usize,
168}
169
170impl NotificationCounts {
171    /// Create new notification counts from the given unread and missed call
172    /// counts.
173    pub fn new(unread: usize, missed_calls: usize) -> Self {
174        NotificationCounts { unread, missed_calls }
175    }
176
177    fn is_default(&self) -> bool {
178        self.unread == 0 && self.missed_calls == 0
179    }
180}
181
182/// Type for passing information about devices.
183#[derive(ToSchema, Clone, Debug, Deserialize, Serialize)]
184pub struct Device {
185    /// The `app_id` given when the pusher was created.
186    ///
187    /// Max length: 64 chars.
188    pub app_id: String,
189
190    /// The `pushkey` given when the pusher was created.
191    ///
192    /// Max length: 512 bytes.
193    pub pushkey: String,
194
195    /// The unix timestamp (in seconds) when the pushkey was last updated.
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub pushkey_ts: Option<UnixSeconds>,
198
199    /// A dictionary of additional pusher-specific data.
200    #[serde(default, skip_serializing_if = "PusherData::is_empty")]
201    pub data: PusherData,
202
203    /// A dictionary of customisations made to the way this notification is to be presented.
204    ///
205    /// These are added by push rules.
206    #[serde(skip_serializing_if = "Vec::is_empty")]
207    pub tweaks: Vec<Tweak>,
208}
209
210impl Device {
211    /// Create a new device with the given app id and pushkey
212    pub fn new(app_id: String, pushkey: String) -> Self {
213        Device {
214            app_id,
215            pushkey,
216            pushkey_ts: None,
217            data: PusherData::new(),
218            tweaks: Vec::new(),
219        }
220    }
221}