ruma_client_api/presence/get_presence.rs
1//! `GET /_matrix/client/*/presence/{userId}/status`
2//!
3//! Get presence status for this user.
4
5pub mod v3 {
6 //! `/v3/` ([spec])
7 //!
8 //! [spec]: https://spec.matrix.org/v1.19/client-server-api/#get_matrixclientv3presenceuseridstatus
9
10 use std::time::Duration;
11
12 #[cfg(feature = "unstable-msc4532")]
13 use ruma_common::presence::PresenceStatus;
14 use ruma_common::{
15 OwnedUserId,
16 api::{auth_scheme::AccessToken, request, response},
17 metadata,
18 presence::PresenceState,
19 };
20 use serde::{Deserialize, Deserializer, Serialize, Serializer};
21
22 metadata! {
23 method: GET,
24 rate_limited: false,
25 authentication: AccessToken,
26 history: {
27 1.0 => "/_matrix/client/r0/presence/{user_id}/status",
28 1.1 => "/_matrix/client/v3/presence/{user_id}/status",
29 }
30 }
31
32 /// Request type for the `get_presence` endpoint.
33 #[request]
34 pub struct Request {
35 /// The user whose presence state will be retrieved.
36 #[ruma_api(path)]
37 pub user_id: OwnedUserId,
38
39 /// Whether to use [MSC4532]'s revised presence states in responses (if the server supports
40 /// them).
41 ///
42 /// Defaults to `true`.
43 ///
44 /// This uses the unstable prefix defined in [MSC4532].
45 ///
46 /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
47 #[cfg(feature = "unstable-msc4532")]
48 #[serde(
49 default,
50 skip_serializing_if = "ruma_common::serde::is_default",
51 rename = "org.continuwuity.presence_v2.msc4532.revised_presence"
52 )]
53 #[ruma_api(query)]
54 pub revised_presence: bool,
55 }
56
57 /// Response type for the `get_presence` endpoint.
58 #[response]
59 #[ruma_api(manual_body_serde)]
60 pub struct Response {
61 /// The state message for this user if one was set.
62 ///
63 /// If the `unstable-msc4532` feature is enabled, this field will always have the same
64 /// value as `status.msg` after deserialization.
65 #[cfg_attr(
66 feature = "unstable-msc4532",
67 deprecated(note = "Deprecated when MSC4532 is enabled, use `status` instead")
68 )]
69 // required to prevent dead code warnings for the deprecated field on `ResponseBody`
70 #[allow(dead_code)]
71 pub status_msg: Option<String>,
72
73 /// The status information for this user's presence.
74 ///
75 /// This field uses the unstable prefix defined in [MSC4532].
76 ///
77 /// If this field is not present at deserialization, the value of `status_msg`
78 /// will be used instead.
79 ///
80 /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
81 #[cfg(feature = "unstable-msc4532")]
82 pub status: PresenceStatus,
83
84 /// Whether the user is currently active or not.
85 ///
86 /// If the `unstable-msc4532` feature is enabled and `presence` is a [MSC4532]
87 /// presence state, this field will be ignored and will always have the same value
88 /// as [`PresenceState::currently_active`] after deserialization.
89 ///
90 /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
91 #[cfg_attr(
92 feature = "unstable-msc4532",
93 deprecated(
94 note = "Deprecated when MSC4532 is enabled, use `PresenceState::currently_active` instead"
95 )
96 )]
97 pub currently_active: Option<bool>,
98
99 /// The length of time in milliseconds since an action was performed by the user.
100 pub last_active_ago: Option<Duration>,
101
102 /// The user's presence state.
103 pub presence: PresenceState,
104 }
105
106 impl Request {
107 /// Creates a new `Request` with the given user ID.
108 pub fn new(user_id: OwnedUserId) -> Self {
109 Self {
110 user_id,
111 #[cfg(feature = "unstable-msc4532")]
112 revised_presence: true,
113 }
114 }
115 }
116
117 impl Response {
118 /// Creates a new `Response` with the given presence state.
119 pub fn new(presence: PresenceState) -> Self {
120 #[allow(deprecated)]
121 Self {
122 presence,
123 status_msg: None,
124 #[cfg(feature = "unstable-msc4532")]
125 status: PresenceStatus::default(),
126 currently_active: None,
127 last_active_ago: None,
128 }
129 }
130 }
131
132 #[derive(Serialize, Deserialize)]
133 struct ResponseBodyRepr {
134 /// The state message for this user if one was set.
135 #[serde(skip_serializing_if = "Option::is_none")]
136 status_msg: Option<String>,
137
138 /// The status information for this user's presence.
139 ///
140 /// This field uses the unstable prefix defined in [MSC4532].
141 ///
142 /// If this field is not present at deserialization, the value of `status_msg`
143 /// will be used instead.
144 ///
145 /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
146 #[serde(
147 skip_serializing_if = "ruma_common::serde::is_default",
148 rename = "org.continuwuity.presence_v2.msc4532.status",
149 default
150 )]
151 #[cfg(feature = "unstable-msc4532")]
152 status: PresenceStatus,
153
154 /// Whether the user is currently active or not.
155 #[serde(skip_serializing_if = "Option::is_none")]
156 currently_active: Option<bool>,
157
158 /// The length of time in milliseconds since an action was performed by the user.
159 #[serde(
160 with = "ruma_common::serde::duration::opt_ms",
161 default,
162 skip_serializing_if = "Option::is_none"
163 )]
164 last_active_ago: Option<Duration>,
165
166 /// The user's presence state.
167 presence: PresenceState,
168 }
169
170 impl<'de> Deserialize<'de> for ResponseBody {
171 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
172 where
173 D: Deserializer<'de>,
174 {
175 #[allow(deprecated)]
176 let ResponseBodyRepr {
177 status_msg,
178 #[cfg(feature = "unstable-msc4532")]
179 status,
180 currently_active,
181 last_active_ago,
182 presence,
183 } = ResponseBodyRepr::deserialize(deserializer)?;
184
185 #[cfg(feature = "unstable-msc4532")]
186 let status = if status == PresenceStatus::default() {
187 PresenceStatus::new(status_msg)
188 } else {
189 status
190 };
191
192 #[cfg(feature = "unstable-msc4532")]
193 let status_msg = status.msg.clone();
194
195 #[cfg(feature = "unstable-msc4532")]
196 let currently_active = if presence.is_msc4532_state() {
197 // ignore the provided currently_active value and use the proposal's definition
198 Some(presence.currently_active())
199 } else {
200 currently_active
201 };
202
203 #[allow(deprecated)]
204 Ok(Self {
205 #[cfg(feature = "unstable-msc4532")]
206 status,
207 status_msg,
208 currently_active,
209 last_active_ago,
210 presence,
211 })
212 }
213 }
214
215 // Servers serialize the data as-is, clients are expected to handle old fields as needed.
216 impl Serialize for ResponseBody {
217 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
218 where
219 S: Serializer,
220 {
221 #[allow(deprecated)]
222 let ResponseBody {
223 status_msg,
224 #[cfg(feature = "unstable-msc4532")]
225 status,
226 currently_active,
227 last_active_ago,
228 presence,
229 } = self.clone();
230
231 ResponseBodyRepr {
232 status_msg,
233 #[cfg(feature = "unstable-msc4532")]
234 status,
235 currently_active,
236 last_active_ago,
237 presence,
238 }
239 .serialize(serializer)
240 }
241 }
242}