Add a registrationToken GraphQL query for anonymous token lookup

The registration form needs to know, before the user submits anything, whether
the code they were handed is usable and which identity it pins. The query only
returns whether the token is valid and the username and email it was issued
for, never the admin-only details.
This commit is contained in:
Quentin Gliech committed 2026-09-10 18:53:59 +02:00
1 parent 40f8828a77
commit f02c3fe293
2 files changed
+70

No files matched your search

+41
View File
@@ -28,6 +28,18 @@ enum UsernameUnavailableReason {
Invalid,
}
/// Public information about a registration token, returned by anonymous lookup.
/// Does not expose admin details like usage counts or expiration.
#[derive(SimpleObject)]
struct RegistrationTokenInfo {
/// Whether the token is currently valid for registration.
valid: bool,
/// A username imposed by this token, if any.
username: Option<String>,
/// An email imposed by this token, if any.
email: Option<String>,
}
/// The result of a username availability check.
#[derive(SimpleObject)]
struct UsernameAvailability {
@@ -168,6 +180,35 @@ impl UserQuery {
})
}
/// Look up a registration token by its string value.
///
/// Returns public information about the token (validity, imposed
/// username/email). Returns `null` if the token does not exist.
///
/// This query is accessible to anonymous users, as it is used during
/// the registration flow.
async fn registration_token(
&self,
ctx: &Context<'_>,
token: String,
) -> Result<Option<RegistrationTokenInfo>, async_graphql::Error> {
let state = ctx.state();
let mut repo = state.repository().await?;
let registration_token = repo.user_registration_token().find_by_token(&token).await?;
repo.cancel().await?;
let Some(registration_token) = registration_token else {
return Ok(None);
};
Ok(Some(RegistrationTokenInfo {
valid: registration_token.is_valid(state.clock().now()),
username: registration_token.username,
email: registration_token.email,
}))
}
/// Fetch a user by its username.
async fn user_by_username(
&self,
+29
View File
@@ -1194,6 +1194,16 @@ type Query {
"""
usernameAvailable(username: String!): UsernameAvailability!
"""
Look up a registration token by its string value.
Returns public information about the token (validity, imposed
username/email). Returns `null` if the token does not exist.
This query is accessible to anonymous users, as it is used during
the registration flow.
"""
registrationToken(token: String!): RegistrationTokenInfo
"""
Fetch a user by its username.
"""
userByUsername(username: String!): User
@@ -1271,6 +1281,25 @@ type Query {
viewerSession: ViewerSession!
}
"""
Public information about a registration token, returned by anonymous lookup.
Does not expose admin details like usage counts or expiration.
"""
type RegistrationTokenInfo {
"""
Whether the token is currently valid for registration.
"""
valid: Boolean!
"""
A username imposed by this token, if any.
"""
username: String
"""
An email imposed by this token, if any.
"""
email: String
}
"""
The input for the `removeEmail` mutation
"""