mas_handlers/graphql/mutations/
compat_session.rs1use anyhow::Context as _;
8use async_graphql::{Context, Enum, ID, InputObject, Object};
9use mas_storage::{
10 RepositoryAccess,
11 compat::CompatSessionRepository,
12 queue::{QueueJobRepositoryExt as _, SyncDevicesJob},
13};
14
15use crate::graphql::{
16 model::{CompatSession, NodeType},
17 state::ContextExt,
18};
19
20#[derive(Default)]
21pub struct CompatSessionMutations {
22 _private: (),
23}
24
25#[derive(InputObject)]
27pub struct EndCompatSessionInput {
28 compat_session_id: ID,
30}
31
32pub enum EndCompatSessionPayload {
34 NotFound,
35 Ended(Box<mas_data_model::CompatSession>),
36}
37
38#[derive(Enum, Copy, Clone, PartialEq, Eq, Debug)]
40enum EndCompatSessionStatus {
41 Ended,
43
44 NotFound,
46}
47
48#[Object]
49impl EndCompatSessionPayload {
50 async fn status(&self) -> EndCompatSessionStatus {
52 match self {
53 Self::Ended(_) => EndCompatSessionStatus::Ended,
54 Self::NotFound => EndCompatSessionStatus::NotFound,
55 }
56 }
57
58 async fn compat_session(&self) -> Option<CompatSession> {
60 match self {
61 Self::Ended(session) => Some(CompatSession::new(*session.clone())),
62 Self::NotFound => None,
63 }
64 }
65}
66
67#[derive(InputObject)]
69pub struct SetCompatSessionNameInput {
70 compat_session_id: ID,
72
73 human_name: String,
75}
76
77pub enum SetCompatSessionNamePayload {
79 NotFound,
81
82 Updated(mas_data_model::CompatSession),
84}
85
86#[derive(Enum, Copy, Clone, PartialEq, Eq, Debug)]
88enum SetCompatSessionNameStatus {
89 Updated,
91
92 NotFound,
94}
95
96#[Object]
97impl SetCompatSessionNamePayload {
98 async fn status(&self) -> SetCompatSessionNameStatus {
100 match self {
101 Self::Updated(_) => SetCompatSessionNameStatus::Updated,
102 Self::NotFound => SetCompatSessionNameStatus::NotFound,
103 }
104 }
105
106 async fn oauth2_session(&self) -> Option<CompatSession> {
108 match self {
109 Self::Updated(session) => Some(CompatSession::new(session.clone())),
110 Self::NotFound => None,
111 }
112 }
113}
114
115#[Object]
116impl CompatSessionMutations {
117 async fn end_compat_session(
118 &self,
119 ctx: &Context<'_>,
120 input: EndCompatSessionInput,
121 ) -> Result<EndCompatSessionPayload, async_graphql::Error> {
122 let state = ctx.state();
123 let mut rng = state.rng();
124 let compat_session_id = NodeType::CompatSession.extract_ulid(&input.compat_session_id)?;
125 let requester = ctx.requester();
126
127 let mut repo = state.repository().await?;
128 let clock = state.clock();
129
130 let session = repo.compat_session().lookup(compat_session_id).await?;
131 let Some(session) = session else {
132 return Ok(EndCompatSessionPayload::NotFound);
133 };
134
135 if !requester.is_owner_or_admin(&session) {
136 return Ok(EndCompatSessionPayload::NotFound);
137 }
138
139 let user = repo
140 .user()
141 .lookup(session.user_id)
142 .await?
143 .context("Could not load user")?;
144
145 repo.queue_job()
147 .schedule_job(&mut rng, &clock, SyncDevicesJob::new(&user))
148 .await?;
149
150 let session = repo.compat_session().finish(&clock, session).await?;
151
152 repo.save().await?;
153
154 Ok(EndCompatSessionPayload::Ended(Box::new(session)))
155 }
156
157 async fn set_compat_session_name(
158 &self,
159 ctx: &Context<'_>,
160 input: SetCompatSessionNameInput,
161 ) -> Result<SetCompatSessionNamePayload, async_graphql::Error> {
162 let state = ctx.state();
163 let compat_session_id = NodeType::CompatSession.extract_ulid(&input.compat_session_id)?;
164 let requester = ctx.requester();
165
166 let mut repo = state.repository().await?;
167 let homeserver = state.homeserver_connection();
168
169 let session = repo.compat_session().lookup(compat_session_id).await?;
170 let Some(session) = session else {
171 return Ok(SetCompatSessionNamePayload::NotFound);
172 };
173
174 if !requester.is_owner_or_admin(&session) {
175 return Ok(SetCompatSessionNamePayload::NotFound);
176 }
177
178 let user = repo
179 .user()
180 .lookup(session.user_id)
181 .await?
182 .context("User not found")?;
183
184 let session = repo
185 .compat_session()
186 .set_human_name(session, Some(input.human_name.clone()))
187 .await?;
188
189 let mxid = homeserver.mxid(&user.username);
191 if let Some(device) = session.device.as_ref() {
192 homeserver
193 .update_device_display_name(&mxid, device.as_str(), &input.human_name)
194 .await
195 .context("Failed to provision device")?;
196 }
197
198 repo.save().await?;
199
200 Ok(SetCompatSessionNamePayload::Updated(session))
201 }
202}