Add whether the registration is valid or not in the admin API
This commit is contained in:
@@ -612,6 +612,9 @@ pub struct UserRegistrationToken {
|
||||
/// The token string
|
||||
token: String,
|
||||
|
||||
/// Whether the token is valid
|
||||
valid: bool,
|
||||
|
||||
/// Maximum number of times this token can be used
|
||||
usage_limit: Option<u32>,
|
||||
|
||||
@@ -631,10 +634,11 @@ pub struct UserRegistrationToken {
|
||||
revoked_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl From<mas_data_model::UserRegistrationToken> for UserRegistrationToken {
|
||||
fn from(token: mas_data_model::UserRegistrationToken) -> Self {
|
||||
impl UserRegistrationToken {
|
||||
pub fn new(token: mas_data_model::UserRegistrationToken, now: DateTime<Utc>) -> Self {
|
||||
Self {
|
||||
id: token.id,
|
||||
valid: token.is_valid(now),
|
||||
token: token.token,
|
||||
usage_limit: token.usage_limit,
|
||||
times_used: token.times_used,
|
||||
@@ -662,6 +666,7 @@ impl UserRegistrationToken {
|
||||
Self {
|
||||
id: Ulid::from_bytes([0x01; 16]),
|
||||
token: "abc123def456".to_owned(),
|
||||
valid: true,
|
||||
usage_limit: Some(10),
|
||||
times_used: 5,
|
||||
created_at: DateTime::default(),
|
||||
@@ -672,6 +677,7 @@ impl UserRegistrationToken {
|
||||
Self {
|
||||
id: Ulid::from_bytes([0x02; 16]),
|
||||
token: "xyz789abc012".to_owned(),
|
||||
valid: false,
|
||||
usage_limit: None,
|
||||
times_used: 0,
|
||||
created_at: DateTime::default(),
|
||||
|
||||
@@ -9,7 +9,7 @@ use chrono::{DateTime, Utc};
|
||||
use hyper::StatusCode;
|
||||
use mas_axum_utils::record_error;
|
||||
use mas_storage::BoxRng;
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use rand::distributions::{Alphanumeric, DistString};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -79,13 +79,9 @@ pub async fn handler(
|
||||
Json(params): Json<Request>,
|
||||
) -> Result<(StatusCode, Json<SingleResponse<UserRegistrationToken>>), RouteError> {
|
||||
// Generate a random token if none was provided
|
||||
let token = params.token.unwrap_or_else(|| {
|
||||
(&mut rng)
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(12)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
});
|
||||
let token = params
|
||||
.token
|
||||
.unwrap_or_else(|| Alphanumeric.sample_string(&mut rng, 12));
|
||||
|
||||
let registration_token = repo
|
||||
.user_registration_token()
|
||||
@@ -102,7 +98,10 @@ pub async fn handler(
|
||||
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
Json(SingleResponse::new_canonical(registration_token.into())),
|
||||
Json(SingleResponse::new_canonical(UserRegistrationToken::new(
|
||||
registration_token,
|
||||
clock.now(),
|
||||
))),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -137,6 +136,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "test_token_123",
|
||||
"valid": true,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -178,6 +178,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0QMGC989M0XSFVF2X",
|
||||
"attributes": {
|
||||
"token": "42oTpLoieH5I",
|
||||
"valid": true,
|
||||
"usage_limit": 1,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
|
||||
@@ -63,7 +63,9 @@ pub fn doc(operation: TransformOperation) -> TransformOperation {
|
||||
|
||||
#[tracing::instrument(name = "handler.admin.v1.user_registration_tokens.get", skip_all)]
|
||||
pub async fn handler(
|
||||
CallContext { mut repo, .. }: CallContext,
|
||||
CallContext {
|
||||
mut repo, clock, ..
|
||||
}: CallContext,
|
||||
id: UlidPathParam,
|
||||
) -> Result<Json<SingleResponse<UserRegistrationToken>>, RouteError> {
|
||||
let token = repo
|
||||
@@ -73,7 +75,7 @@ pub async fn handler(
|
||||
.ok_or(RouteError::NotFound(*id))?;
|
||||
|
||||
Ok(Json(SingleResponse::new_canonical(
|
||||
UserRegistrationToken::from(token),
|
||||
UserRegistrationToken::new(token, clock.now()),
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -116,13 +118,14 @@ mod tests {
|
||||
response.assert_status(StatusCode::OK);
|
||||
let body: serde_json::Value = response.json();
|
||||
|
||||
assert_json_snapshot!(body, @r###"
|
||||
assert_json_snapshot!(body, @r#"
|
||||
{
|
||||
"data": {
|
||||
"type": "user-registration_token",
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "test_token_123",
|
||||
"valid": true,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -138,7 +141,7 @@ mod tests {
|
||||
"self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
|
||||
}
|
||||
}
|
||||
"###);
|
||||
"#);
|
||||
}
|
||||
|
||||
#[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")]
|
||||
|
||||
@@ -135,7 +135,8 @@ pub async fn handler(
|
||||
params: FilterParams,
|
||||
) -> Result<Json<PaginatedResponse<UserRegistrationToken>>, RouteError> {
|
||||
let base = format!("{path}{params}", path = UserRegistrationToken::PATH);
|
||||
let mut filter = UserRegistrationTokenFilter::new(clock.now());
|
||||
let now = clock.now();
|
||||
let mut filter = UserRegistrationTokenFilter::new(now);
|
||||
|
||||
if let Some(used) = params.used {
|
||||
filter = filter.with_been_used(used);
|
||||
@@ -160,7 +161,7 @@ pub async fn handler(
|
||||
let count = repo.user_registration_token().count(filter).await?;
|
||||
|
||||
Ok(Json(PaginatedResponse::new(
|
||||
page.map(UserRegistrationToken::from),
|
||||
page.map(|token| UserRegistrationToken::new(token, now)),
|
||||
pagination,
|
||||
count,
|
||||
&base,
|
||||
@@ -288,6 +289,7 @@ mod tests {
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -304,6 +306,7 @@ mod tests {
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -320,6 +323,7 @@ mod tests {
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -336,6 +340,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -352,6 +357,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -399,6 +405,7 @@ mod tests {
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -415,6 +422,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -454,6 +462,7 @@ mod tests {
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -470,6 +479,7 @@ mod tests {
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -486,6 +496,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -533,6 +544,7 @@ mod tests {
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -549,6 +561,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -588,6 +601,7 @@ mod tests {
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -604,6 +618,7 @@ mod tests {
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -620,6 +635,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -667,6 +683,7 @@ mod tests {
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -706,6 +723,7 @@ mod tests {
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -722,6 +740,7 @@ mod tests {
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -738,6 +757,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -754,6 +774,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -801,6 +822,7 @@ mod tests {
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -817,6 +839,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -856,6 +879,7 @@ mod tests {
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -872,6 +896,7 @@ mod tests {
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -888,6 +913,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -937,6 +963,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -984,6 +1011,7 @@ mod tests {
|
||||
"id": "01FSHN9AG064K8BYZXSY5G511Z",
|
||||
"attributes": {
|
||||
"token": "token_expired",
|
||||
"valid": false,
|
||||
"usage_limit": 5,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -1000,6 +1028,7 @@ mod tests {
|
||||
"id": "01FSHN9AG07HNEZXNQM2KNBNF6",
|
||||
"attributes": {
|
||||
"token": "token_used",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -1040,6 +1069,7 @@ mod tests {
|
||||
"id": "01FSHN9AG09AVTNSQFMSR34AJC",
|
||||
"attributes": {
|
||||
"token": "token_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -1056,6 +1086,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0MZAA6S4AF7CTV32E",
|
||||
"attributes": {
|
||||
"token": "token_unused",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 0,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
@@ -1096,6 +1127,7 @@ mod tests {
|
||||
"id": "01FSHN9AG0S3ZJD8CXQ7F11KXN",
|
||||
"attributes": {
|
||||
"token": "token_used_revoked",
|
||||
"valid": false,
|
||||
"usage_limit": 10,
|
||||
"times_used": 1,
|
||||
"created_at": "2022-01-16T14:40:00Z",
|
||||
|
||||
@@ -95,7 +95,7 @@ pub async fn handler(
|
||||
repo.save().await?;
|
||||
|
||||
Ok(Json(SingleResponse::new(
|
||||
UserRegistrationToken::from(token),
|
||||
UserRegistrationToken::new(token, clock.now()),
|
||||
format!("/api/admin/v1/user-registration-tokens/{id}/revoke"),
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -2251,6 +2251,7 @@
|
||||
"id": "01040G2081040G2081040G2081",
|
||||
"attributes": {
|
||||
"token": "abc123def456",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 5,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
@@ -2267,6 +2268,7 @@
|
||||
"id": "02081040G2081040G2081040G2",
|
||||
"attributes": {
|
||||
"token": "xyz789abc012",
|
||||
"valid": false,
|
||||
"usage_limit": null,
|
||||
"times_used": 0,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
@@ -2321,6 +2323,7 @@
|
||||
"id": "01040G2081040G2081040G2081",
|
||||
"attributes": {
|
||||
"token": "abc123def456",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 5,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
@@ -2375,6 +2378,7 @@
|
||||
"id": "01040G2081040G2081040G2081",
|
||||
"attributes": {
|
||||
"token": "abc123def456",
|
||||
"valid": true,
|
||||
"usage_limit": 10,
|
||||
"times_used": 5,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
@@ -2447,6 +2451,7 @@
|
||||
"id": "02081040G2081040G2081040G2",
|
||||
"attributes": {
|
||||
"token": "xyz789abc012",
|
||||
"valid": false,
|
||||
"usage_limit": null,
|
||||
"times_used": 0,
|
||||
"created_at": "1970-01-01T00:00:00Z",
|
||||
@@ -4043,13 +4048,18 @@
|
||||
"required": [
|
||||
"created_at",
|
||||
"times_used",
|
||||
"token"
|
||||
"token",
|
||||
"valid"
|
||||
],
|
||||
"properties": {
|
||||
"token": {
|
||||
"description": "The token string",
|
||||
"type": "string"
|
||||
},
|
||||
"valid": {
|
||||
"description": "Whether the token is valid",
|
||||
"type": "boolean"
|
||||
},
|
||||
"usage_limit": {
|
||||
"description": "Maximum number of times this token can be used",
|
||||
"type": "integer",
|
||||
|
||||
Reference in New Issue
Block a user