mas_handlers/graphql/mutations/
matrix.rs1use anyhow::Context as _;
8use async_graphql::{Context, Description, Enum, ID, InputObject, Object};
9
10use crate::graphql::{
11 UserId,
12 model::{NodeType, User},
13 state::ContextExt,
14};
15
16#[derive(Default)]
17pub struct MatrixMutations {
18 _private: (),
19}
20
21#[derive(InputObject)]
23struct SetDisplayNameInput {
24 user_id: ID,
26
27 display_name: Option<String>,
29}
30
31#[derive(Enum, Copy, Clone, Eq, PartialEq)]
33pub enum SetDisplayNameStatus {
34 Set,
36 Invalid,
38}
39
40#[derive(Description)]
42enum SetDisplayNamePayload {
43 Set(User),
44 Invalid,
45}
46
47#[Object(use_type_description)]
48impl SetDisplayNamePayload {
49 async fn status(&self) -> SetDisplayNameStatus {
51 match self {
52 SetDisplayNamePayload::Set(_) => SetDisplayNameStatus::Set,
53 SetDisplayNamePayload::Invalid => SetDisplayNameStatus::Invalid,
54 }
55 }
56
57 async fn user(&self) -> Option<&User> {
59 match self {
60 SetDisplayNamePayload::Set(user) => Some(user),
61 SetDisplayNamePayload::Invalid => None,
62 }
63 }
64}
65
66#[Object]
67impl MatrixMutations {
68 async fn set_display_name(
70 &self,
71 ctx: &Context<'_>,
72 input: SetDisplayNameInput,
73 ) -> Result<SetDisplayNamePayload, async_graphql::Error> {
74 let state = ctx.state();
75 let id = NodeType::User.extract_ulid(&input.user_id)?;
76 let requester = ctx.requester();
77
78 if !requester.is_owner_or_admin(&UserId(id)) {
79 return Err(async_graphql::Error::new("Unauthorized"));
80 }
81
82 if !requester.is_admin() && !state.site_config().displayname_change_allowed {
84 return Err(async_graphql::Error::new("Unauthorized"));
85 }
86
87 let mut repo = state.repository().await?;
88 let user = repo
89 .user()
90 .lookup(id)
91 .await?
92 .context("Failed to lookup user")?;
93 repo.cancel().await?;
94
95 let conn = state.homeserver_connection();
96 let mxid = conn.mxid(&user.username);
97
98 if let Some(display_name) = &input.display_name {
99 if display_name.len() > 256 {
101 return Ok(SetDisplayNamePayload::Invalid);
102 }
103
104 if display_name.is_empty() {
105 return Ok(SetDisplayNamePayload::Invalid);
106 }
107
108 conn.set_displayname(&mxid, display_name)
109 .await
110 .context("Failed to set display name")?;
111 } else {
112 conn.unset_displayname(&mxid)
113 .await
114 .context("Failed to unset display name")?;
115 }
116
117 Ok(SetDisplayNamePayload::Set(User(user.clone())))
118 }
119}