@@ -25,6 +25,9 @@ use crate::{
2525#[ derive( Debug , thiserror:: Error , OperationIo ) ]
2626#[ aide( output_with = "Json<ErrorResponse>" ) ]
2727pub enum RouteError {
28+ #[ error( "A registration token with the same token already exists" ) ]
29+ Conflict ( mas_data_model:: UserRegistrationToken ) ,
30+
2831 #[ error( transparent) ]
2932 Internal ( Box < dyn std:: error:: Error + Send + Sync + ' static > ) ,
3033}
@@ -36,6 +39,7 @@ impl IntoResponse for RouteError {
3639 let error = ErrorResponse :: from_error ( & self ) ;
3740 let sentry_event_id = record_error ! ( self , Self :: Internal ( _) ) ;
3841 let status = match self {
42+ Self :: Conflict ( _) => StatusCode :: CONFLICT ,
3943 Self :: Internal ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
4044 } ;
4145 ( status, sentry_event_id, Json ( error) ) . into_response ( )
@@ -83,6 +87,12 @@ pub async fn handler(
8387 . token
8488 . unwrap_or_else ( || Alphanumeric . sample_string ( & mut rng, 12 ) ) ;
8589
90+ // See if we have an existing token with the same token
91+ let existing_token = repo. user_registration_token ( ) . find_by_token ( & token) . await ?;
92+ if let Some ( existing_token) = existing_token {
93+ return Err ( RouteError :: Conflict ( existing_token) ) ;
94+ }
95+
8696 let registration_token = repo
8797 . user_registration_token ( )
8898 . add (
@@ -196,4 +206,56 @@ mod tests {
196206 }
197207 "# ) ;
198208 }
209+
210+ #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
211+ async fn test_create_conflict ( pool : PgPool ) {
212+ setup ( ) ;
213+ let mut state = TestState :: from_pool ( pool) . await . unwrap ( ) ;
214+ let token = state. token_with_scope ( "urn:mas:admin" ) . await ;
215+
216+ let request = Request :: post ( "/api/admin/v1/user-registration-tokens" )
217+ . bearer ( & token)
218+ . json ( serde_json:: json!( {
219+ "token" : "test_token_123" ,
220+ "usage_limit" : 5
221+ } ) ) ;
222+ let response = state. request ( request) . await ;
223+ response. assert_status ( StatusCode :: CREATED ) ;
224+
225+ let body: serde_json:: Value = response. json ( ) ;
226+
227+ assert_json_snapshot ! ( body, @r#"
228+ {
229+ "data": {
230+ "type": "user-registration_token",
231+ "id": "01FSHN9AG0MZAA6S4AF7CTV32E",
232+ "attributes": {
233+ "token": "test_token_123",
234+ "valid": true,
235+ "usage_limit": 5,
236+ "times_used": 0,
237+ "created_at": "2022-01-16T14:40:00Z",
238+ "last_used_at": null,
239+ "expires_at": null,
240+ "revoked_at": null
241+ },
242+ "links": {
243+ "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
244+ }
245+ },
246+ "links": {
247+ "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E"
248+ }
249+ }
250+ "# ) ;
251+
252+ let request = Request :: post ( "/api/admin/v1/user-registration-tokens" )
253+ . bearer ( & token)
254+ . json ( serde_json:: json!( {
255+ "token" : "test_token_123" ,
256+ "usage_limit" : 5
257+ } ) ) ;
258+ let response = state. request ( request) . await ;
259+ response. assert_status ( StatusCode :: CONFLICT ) ;
260+ }
199261}
0 commit comments