Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.

Commit 3cb8a26

Browse files
committed
"Can request admin" flag on user
1 parent 05e167b commit 3cb8a26

18 files changed

+360
-13
lines changed

crates/data-model/src/users.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct User {
2727
pub primary_user_email_id: Option<Ulid>,
2828
pub created_at: DateTime<Utc>,
2929
pub locked_at: Option<DateTime<Utc>>,
30+
pub can_request_admin: bool,
3031
}
3132

3233
impl User {
@@ -47,6 +48,7 @@ impl User {
4748
primary_user_email_id: None,
4849
created_at: now,
4950
locked_at: None,
51+
can_request_admin: false,
5052
}]
5153
}
5254
}

crates/graphql/src/model/users.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ impl User {
7373
self.0.locked_at
7474
}
7575

76+
/// Whether the user can request admin privileges.
77+
pub async fn can_request_admin(&self) -> bool {
78+
self.0.can_request_admin
79+
}
80+
7681
/// Access to the user's Matrix account information.
7782
async fn matrix(&self, ctx: &Context<'_>) -> Result<MatrixUser, async_graphql::Error> {
7883
let state = ctx.state();

crates/graphql/src/mutations/user.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,37 @@ impl LockUserPayload {
126126
}
127127
}
128128

129+
/// The input for the `setCanRequestAdmin` mutation.
130+
#[derive(InputObject)]
131+
struct SetCanRequestAdminInput {
132+
/// The ID of the user to update.
133+
user_id: ID,
134+
135+
/// Whether the user can request admin.
136+
can_request_admin: bool,
137+
}
138+
139+
/// The payload for the `setCanRequestAdmin` mutation.
140+
#[derive(Description)]
141+
enum SetCanRequestAdminPayload {
142+
/// The user was updated.
143+
Updated(mas_data_model::User),
144+
145+
/// The user was not found.
146+
NotFound,
147+
}
148+
149+
#[Object(use_type_description)]
150+
impl SetCanRequestAdminPayload {
151+
/// The user that was updated.
152+
async fn user(&self) -> Option<User> {
153+
match self {
154+
Self::Updated(user) => Some(User(user.clone())),
155+
Self::NotFound => None,
156+
}
157+
}
158+
}
159+
129160
fn valid_username_character(c: char) -> bool {
130161
c.is_ascii_lowercase()
131162
|| c.is_ascii_digit()
@@ -232,4 +263,37 @@ impl UserMutations {
232263

233264
Ok(LockUserPayload::Locked(user))
234265
}
266+
267+
/// Set whether a user can request admin. This is only available to
268+
/// administrators.
269+
async fn set_can_request_admin(
270+
&self,
271+
ctx: &Context<'_>,
272+
input: SetCanRequestAdminInput,
273+
) -> Result<SetCanRequestAdminPayload, async_graphql::Error> {
274+
let state = ctx.state();
275+
let requester = ctx.requester();
276+
277+
if !requester.is_admin() {
278+
return Err(async_graphql::Error::new("Unauthorized"));
279+
}
280+
281+
let mut repo = state.repository().await?;
282+
283+
let user_id = NodeType::User.extract_ulid(&input.user_id)?;
284+
let user = repo.user().lookup(user_id).await?;
285+
286+
let Some(user) = user else {
287+
return Ok(SetCanRequestAdminPayload::NotFound);
288+
};
289+
290+
let user = repo
291+
.user()
292+
.set_can_request_admin(user, input.can_request_admin)
293+
.await?;
294+
295+
repo.save().await?;
296+
297+
Ok(SetCanRequestAdminPayload::Updated(user))
298+
}
235299
}
Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/storage-pg/.sqlx/query-1dbc50cdab36da307c569891ab7b1ab4aaf128fed6be67ca0f139d697614c63b.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- Copyright 2023 The Matrix.org Foundation C.I.C.
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
-- Adds a `can_request_admin` column to the `users` table
16+
ALTER TABLE users
17+
ADD COLUMN can_request_admin BOOLEAN NOT NULL DEFAULT FALSE;

crates/storage-pg/src/iden.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub enum Users {
3434
PrimaryUserEmailId,
3535
CreatedAt,
3636
LockedAt,
37+
CanRequestAdmin,
3738
}
3839

3940
#[derive(sea_query::Iden)]

crates/storage-pg/src/user/mod.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct UserLookup {
5757
primary_user_email_id: Option<Uuid>,
5858
created_at: DateTime<Utc>,
5959
locked_at: Option<DateTime<Utc>>,
60+
can_request_admin: bool,
6061
}
6162

6263
impl From<UserLookup> for User {
@@ -69,6 +70,7 @@ impl From<UserLookup> for User {
6970
primary_user_email_id: value.primary_user_email_id.map(Into::into),
7071
created_at: value.created_at,
7172
locked_at: value.locked_at,
73+
can_request_admin: value.can_request_admin,
7274
}
7375
}
7476
}
@@ -95,6 +97,7 @@ impl<'c> UserRepository for PgUserRepository<'c> {
9597
, primary_user_email_id
9698
, created_at
9799
, locked_at
100+
, can_request_admin
98101
FROM users
99102
WHERE user_id = $1
100103
"#,
@@ -127,6 +130,7 @@ impl<'c> UserRepository for PgUserRepository<'c> {
127130
, primary_user_email_id
128131
, created_at
129132
, locked_at
133+
, can_request_admin
130134
FROM users
131135
WHERE username = $1
132136
"#,
@@ -186,6 +190,7 @@ impl<'c> UserRepository for PgUserRepository<'c> {
186190
primary_user_email_id: None,
187191
created_at,
188192
locked_at: None,
193+
can_request_admin: false,
189194
})
190195
}
191196

@@ -281,4 +286,39 @@ impl<'c> UserRepository for PgUserRepository<'c> {
281286

282287
Ok(user)
283288
}
289+
290+
#[tracing::instrument(
291+
name = "db.user.set_can_request_admin",
292+
skip_all,
293+
fields(
294+
db.statement,
295+
%user.id,
296+
user.can_request_admin = can_request_admin,
297+
),
298+
err,
299+
)]
300+
async fn set_can_request_admin(
301+
&mut self,
302+
mut user: User,
303+
can_request_admin: bool,
304+
) -> Result<User, Self::Error> {
305+
let res = sqlx::query!(
306+
r#"
307+
UPDATE users
308+
SET can_request_admin = $2
309+
WHERE user_id = $1
310+
"#,
311+
Uuid::from(user.id),
312+
can_request_admin,
313+
)
314+
.traced()
315+
.execute(&mut *self.conn)
316+
.await?;
317+
318+
DatabaseError::ensure_affected_rows(&res, 1)?;
319+
320+
user.can_request_admin = can_request_admin;
321+
322+
Ok(user)
323+
}
284324
}

0 commit comments

Comments
 (0)