ruma_client_api/discovery/
get_capabilities.rs1pub mod v3 {
9 use std::{borrow::Cow, collections::BTreeMap};
14
15 use maplit::btreemap;
16 use ruma_common::{
17 RoomVersionId,
18 api::{auth_scheme::AccessToken, request, response},
19 metadata,
20 profile::ProfileFieldName,
21 serde::StringEnum,
22 };
23 use serde::{Deserialize, Serialize};
24 use serde_json::{
25 Value as JsonValue, from_value as from_json_value, to_value as to_json_value,
26 };
27
28 use crate::PrivOwnedStr;
29
30 metadata! {
31 method: GET,
32 rate_limited: true,
33 authentication: AccessToken,
34 history: {
35 1.0 => "/_matrix/client/r0/capabilities",
36 1.1 => "/_matrix/client/v3/capabilities",
37 }
38 }
39
40 #[request]
42 #[derive(Default)]
43 pub struct Request {}
44
45 #[response]
47 pub struct Response {
48 pub capabilities: Capabilities,
50 }
51
52 impl Request {
53 pub fn new() -> Self {
55 Self {}
56 }
57 }
58
59 impl Response {
60 pub fn new(capabilities: Capabilities) -> Self {
62 Self { capabilities }
63 }
64 }
65
66 impl From<Capabilities> for Response {
67 fn from(capabilities: Capabilities) -> Self {
68 Self::new(capabilities)
69 }
70 }
71
72 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
74 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
75 #[allow(deprecated)]
76 pub struct Capabilities {
77 #[serde(
79 rename = "m.change_password",
80 default,
81 skip_serializing_if = "ChangePasswordCapability::is_default"
82 )]
83 pub change_password: ChangePasswordCapability,
84
85 #[serde(
87 rename = "m.room_versions",
88 default,
89 skip_serializing_if = "RoomVersionsCapability::is_default"
90 )]
91 pub room_versions: RoomVersionsCapability,
92
93 #[serde(
95 rename = "m.set_displayname",
96 default,
97 skip_serializing_if = "SetDisplayNameCapability::is_default"
98 )]
99 #[deprecated = "Since Matrix 1.16, prefer profile_fields if it is set."]
100 pub set_displayname: SetDisplayNameCapability,
101
102 #[serde(
104 rename = "m.set_avatar_url",
105 default,
106 skip_serializing_if = "SetAvatarUrlCapability::is_default"
107 )]
108 #[deprecated = "Since Matrix 1.16, prefer profile_fields if it is set."]
109 pub set_avatar_url: SetAvatarUrlCapability,
110
111 #[serde(
114 rename = "m.3pid_changes",
115 default,
116 skip_serializing_if = "ThirdPartyIdChangesCapability::is_default"
117 )]
118 pub thirdparty_id_changes: ThirdPartyIdChangesCapability,
119
120 #[serde(
123 rename = "m.get_login_token",
124 default,
125 skip_serializing_if = "GetLoginTokenCapability::is_default"
126 )]
127 pub get_login_token: GetLoginTokenCapability,
128
129 #[serde(
131 rename = "m.profile_fields",
132 alias = "uk.tcpip.msc4133.profile_fields",
133 skip_serializing_if = "Option::is_none"
134 )]
135 pub profile_fields: Option<ProfileFieldsCapability>,
136
137 #[serde(
139 rename = "m.forget_forced_upon_leave",
140 default,
141 skip_serializing_if = "ForgetForcedUponLeaveCapability::is_default"
142 )]
143 pub forget_forced_upon_leave: ForgetForcedUponLeaveCapability,
144
145 #[serde(
150 rename = "m.account_moderation",
151 default,
152 skip_serializing_if = "AccountModerationCapability::is_default"
153 )]
154 pub account_moderation: AccountModerationCapability,
155
156 #[serde(flatten)]
159 custom_capabilities: BTreeMap<String, JsonValue>,
160 }
161
162 impl Capabilities {
163 pub fn new() -> Self {
165 Default::default()
166 }
167
168 pub fn get(&self, capability: &str) -> Option<Cow<'_, JsonValue>> {
173 fn serialize<T: Serialize>(cap: &T) -> JsonValue {
174 to_json_value(cap).expect("capability serialization to succeed")
175 }
176
177 match capability {
178 "m.change_password" => Some(Cow::Owned(serialize(&self.change_password))),
179 "m.room_versions" => Some(Cow::Owned(serialize(&self.room_versions))),
180 #[allow(deprecated)]
181 "m.set_displayname" => Some(Cow::Owned(serialize(&self.set_displayname))),
182 #[allow(deprecated)]
183 "m.set_avatar_url" => Some(Cow::Owned(serialize(&self.set_avatar_url))),
184 "m.3pid_changes" => Some(Cow::Owned(serialize(&self.thirdparty_id_changes))),
185 "m.get_login_token" => Some(Cow::Owned(serialize(&self.get_login_token))),
186 "m.forget_forced_upon_leave" => {
187 Some(Cow::Owned(serialize(&self.forget_forced_upon_leave)))
188 }
189 "m.account_moderation" => Some(Cow::Owned(serialize(&self.account_moderation))),
190 _ => self.custom_capabilities.get(capability).map(Cow::Borrowed),
191 }
192 }
193
194 pub fn set(&mut self, capability: &str, value: JsonValue) -> serde_json::Result<()> {
200 match capability {
201 "m.change_password" => self.change_password = from_json_value(value)?,
202 "m.room_versions" => self.room_versions = from_json_value(value)?,
203 #[allow(deprecated)]
204 "m.set_displayname" => self.set_displayname = from_json_value(value)?,
205 #[allow(deprecated)]
206 "m.set_avatar_url" => self.set_avatar_url = from_json_value(value)?,
207 "m.3pid_changes" => self.thirdparty_id_changes = from_json_value(value)?,
208 "m.get_login_token" => self.get_login_token = from_json_value(value)?,
209 "m.forget_forced_upon_leave" => {
210 self.forget_forced_upon_leave = from_json_value(value)?;
211 }
212 "m.account_moderation" => {
213 self.account_moderation = from_json_value(value)?;
214 }
215 _ => {
216 self.custom_capabilities.insert(capability.to_owned(), value);
217 }
218 }
219
220 Ok(())
221 }
222 }
223
224 #[derive(Clone, Debug, Serialize, Deserialize)]
226 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
227 pub struct ChangePasswordCapability {
228 pub enabled: bool,
230 }
231
232 impl ChangePasswordCapability {
233 pub fn new(enabled: bool) -> Self {
235 Self { enabled }
236 }
237
238 pub fn is_default(&self) -> bool {
240 self.enabled
241 }
242 }
243
244 impl Default for ChangePasswordCapability {
245 fn default() -> Self {
246 Self { enabled: true }
247 }
248 }
249
250 #[derive(Clone, Debug, Serialize, Deserialize)]
252 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
253 pub struct RoomVersionsCapability {
254 pub default: RoomVersionId,
256
257 pub available: BTreeMap<RoomVersionId, RoomVersionStability>,
259 }
260
261 impl RoomVersionsCapability {
262 pub fn new(
265 default: RoomVersionId,
266 available: BTreeMap<RoomVersionId, RoomVersionStability>,
267 ) -> Self {
268 Self { default, available }
269 }
270
271 pub fn is_default(&self) -> bool {
273 self.default == RoomVersionId::V1
274 && self.available.len() == 1
275 && self
276 .available
277 .get(&RoomVersionId::V1)
278 .map(|stability| *stability == RoomVersionStability::Stable)
279 .unwrap_or(false)
280 }
281 }
282
283 impl Default for RoomVersionsCapability {
284 fn default() -> Self {
285 Self {
286 default: RoomVersionId::V1,
287 available: btreemap! { RoomVersionId::V1 => RoomVersionStability::Stable },
288 }
289 }
290 }
291
292 #[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
294 #[derive(Clone, StringEnum)]
295 #[ruma_enum(rename_all = "lowercase")]
296 #[non_exhaustive]
297 pub enum RoomVersionStability {
298 Stable,
300
301 Unstable,
303
304 #[doc(hidden)]
305 _Custom(PrivOwnedStr),
306 }
307
308 #[derive(Clone, Debug, Serialize, Deserialize)]
310 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
311 #[deprecated = "Since Matrix 1.16, prefer ProfileFieldsCapability instead."]
312 pub struct SetDisplayNameCapability {
313 pub enabled: bool,
315 }
316
317 #[allow(deprecated)]
318 impl SetDisplayNameCapability {
319 pub fn new(enabled: bool) -> Self {
321 Self { enabled }
322 }
323
324 pub fn is_default(&self) -> bool {
326 self.enabled
327 }
328 }
329
330 #[allow(deprecated)]
331 impl Default for SetDisplayNameCapability {
332 fn default() -> Self {
333 Self { enabled: true }
334 }
335 }
336
337 #[derive(Clone, Debug, Serialize, Deserialize)]
339 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
340 #[deprecated = "Since Matrix 1.16, prefer ProfileFieldsCapability instead."]
341 pub struct SetAvatarUrlCapability {
342 pub enabled: bool,
344 }
345
346 #[allow(deprecated)]
347 impl SetAvatarUrlCapability {
348 pub fn new(enabled: bool) -> Self {
350 Self { enabled }
351 }
352
353 pub fn is_default(&self) -> bool {
355 self.enabled
356 }
357 }
358
359 #[allow(deprecated)]
360 impl Default for SetAvatarUrlCapability {
361 fn default() -> Self {
362 Self { enabled: true }
363 }
364 }
365
366 #[derive(Clone, Debug, Serialize, Deserialize)]
368 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
369 pub struct ThirdPartyIdChangesCapability {
370 pub enabled: bool,
373 }
374
375 impl ThirdPartyIdChangesCapability {
376 pub fn new(enabled: bool) -> Self {
378 Self { enabled }
379 }
380
381 pub fn is_default(&self) -> bool {
383 self.enabled
384 }
385 }
386
387 impl Default for ThirdPartyIdChangesCapability {
388 fn default() -> Self {
389 Self { enabled: true }
390 }
391 }
392
393 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
395 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
396 pub struct GetLoginTokenCapability {
397 pub enabled: bool,
399 }
400
401 impl GetLoginTokenCapability {
402 pub fn new(enabled: bool) -> Self {
404 Self { enabled }
405 }
406
407 pub fn is_default(&self) -> bool {
409 !self.enabled
410 }
411 }
412
413 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
415 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
416 pub struct ProfileFieldsCapability {
417 pub enabled: bool,
419
420 #[serde(skip_serializing_if = "Option::is_none")]
422 pub allowed: Option<Vec<ProfileFieldName>>,
423
424 #[serde(skip_serializing_if = "Option::is_none")]
428 pub disallowed: Option<Vec<ProfileFieldName>>,
429 }
430
431 impl ProfileFieldsCapability {
432 pub fn new(enabled: bool) -> Self {
434 Self { enabled, allowed: None, disallowed: None }
435 }
436
437 pub fn can_set_field(&self, field: &ProfileFieldName) -> bool {
439 if !self.enabled {
440 return false;
441 }
442
443 if let Some(allowed) = &self.allowed {
444 allowed.contains(field)
445 } else if let Some(disallowed) = &self.disallowed {
446 !disallowed.contains(field)
447 } else {
448 true
450 }
451 }
452 }
453
454 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
458 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
459 pub struct ForgetForcedUponLeaveCapability {
460 pub enabled: bool,
465 }
466
467 impl ForgetForcedUponLeaveCapability {
468 pub fn new(enabled: bool) -> Self {
470 Self { enabled }
471 }
472
473 pub fn is_default(&self) -> bool {
475 !self.enabled
476 }
477 }
478
479 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
481 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
482 pub struct AccountModerationCapability {
483 #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
485 pub suspend: bool,
486
487 #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
489 pub lock: bool,
490 }
491
492 impl AccountModerationCapability {
493 pub fn new(suspend: bool, lock: bool) -> Self {
496 Self { suspend, lock }
497 }
498
499 pub fn is_default(&self) -> bool {
501 !self.suspend && !self.lock
502 }
503 }
504}