@@ -12,8 +12,6 @@ use mas_storage::{
1212 BoxRng ,
1313 queue:: { DeactivateUserJob , QueueJobRepositoryExt as _} ,
1414} ;
15- use schemars:: JsonSchema ;
16- use serde:: Deserialize ;
1715use tracing:: info;
1816use ulid:: Ulid ;
1917
@@ -51,36 +49,21 @@ impl IntoResponse for RouteError {
5149 }
5250}
5351
54- /// # JSON payload for the `POST /api/admin/v1/users/:id/deactivate` endpoint
55- #[ derive( Default , Deserialize , JsonSchema ) ]
56- #[ serde( rename = "DeactivateUserRequest" ) ]
57- pub struct Request {
58- /// Whether to skip locking the user before deactivation.
59- #[ serde( default ) ]
60- skip_lock : bool ,
61- }
62-
63- pub fn doc ( mut operation : TransformOperation ) -> TransformOperation {
64- operation
65- . inner_mut ( )
66- . request_body
67- . as_mut ( )
68- . unwrap ( )
69- . as_item_mut ( )
70- . unwrap ( )
71- . required = false ;
72-
52+ pub fn doc ( operation : TransformOperation ) -> TransformOperation {
7353 operation
7454 . id ( "deactivateUser" )
7555 . summary ( "Deactivate a user" )
76- . description ( "Calling this endpoint will lock and deactivate the user, preventing them from doing any action.
77- This invalidates any existing session, and will ask the homeserver to make them leave all rooms." )
56+ . description (
57+ "Calling this endpoint will deactivate the user, preventing them from doing any action.
58+ This invalidates any existing session, and will ask the homeserver to make them leave all rooms." ,
59+ )
7860 . tag ( "user" )
7961 . response_with :: < 200 , Json < SingleResponse < User > > , _ > ( |t| {
8062 // In the samples, the third user is the one locked
8163 let [ _alice, _bob, charlie, ..] = User :: samples ( ) ;
8264 let id = charlie. id ( ) ;
83- let response = SingleResponse :: new ( charlie, format ! ( "/api/admin/v1/users/{id}/deactivate" ) ) ;
65+ let response =
66+ SingleResponse :: new ( charlie, format ! ( "/api/admin/v1/users/{id}/deactivate" ) ) ;
8467 t. description ( "User was deactivated" ) . example ( response)
8568 } )
8669 . response_with :: < 404 , RouteError , _ > ( |t| {
@@ -96,19 +79,15 @@ pub async fn handler(
9679 } : CallContext ,
9780 NoApi ( mut rng) : NoApi < BoxRng > ,
9881 id : UlidPathParam ,
99- body : Option < Json < Request > > ,
10082) -> Result < Json < SingleResponse < User > > , RouteError > {
101- let Json ( params) = body. unwrap_or_default ( ) ;
10283 let id = * id;
103- let mut user = repo
84+ let user = repo
10485 . user ( )
10586 . lookup ( id)
10687 . await ?
10788 . ok_or ( RouteError :: NotFound ( id) ) ?;
10889
109- if !params. skip_lock && user. locked_at . is_none ( ) {
110- user = repo. user ( ) . lock ( & clock, user) . await ?;
111- }
90+ let user = repo. user ( ) . deactivate ( & clock, user) . await ?;
11291
11392 info ! ( %user. id, "Scheduling deactivation of user" ) ;
11493 repo. queue_job ( )
@@ -127,13 +106,14 @@ pub async fn handler(
127106mod tests {
128107 use chrono:: Duration ;
129108 use hyper:: { Request , StatusCode } ;
130- use insta:: { allow_duplicates , assert_json_snapshot} ;
109+ use insta:: assert_json_snapshot;
131110 use mas_storage:: { Clock , RepositoryAccess , user:: UserRepository } ;
132111 use sqlx:: PgPool ;
133112
134113 use crate :: test_utils:: { RequestBuilderExt , ResponseExt , TestState , setup} ;
135114
136- async fn test_deactivate_user_helper ( pool : PgPool , skip_lock : Option < bool > ) {
115+ #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
116+ async fn test_deactivate_user ( pool : PgPool ) {
137117 setup ( ) ;
138118 let mut state = TestState :: from_pool ( pool. clone ( ) ) . await . unwrap ( ) ;
139119 let token = state. token_with_scope ( "urn:mas:admin" ) . await ;
@@ -146,27 +126,23 @@ mod tests {
146126 . unwrap ( ) ;
147127 repo. save ( ) . await . unwrap ( ) ;
148128
149- let request =
150- Request :: post ( format ! ( "/api/admin/v1/users/{}/deactivate" , user. id) ) . bearer ( & token) ;
151- let request = match skip_lock {
152- None => request. empty ( ) ,
153- Some ( skip_lock) => request. json ( serde_json:: json!( {
154- "skip_lock" : skip_lock,
155- } ) ) ,
156- } ;
129+ let request = Request :: post ( format ! ( "/api/admin/v1/users/{}/deactivate" , user. id) )
130+ . bearer ( & token)
131+ . empty ( ) ;
157132 let response = state. request ( request) . await ;
158133 response. assert_status ( StatusCode :: OK ) ;
159134 let body: serde_json:: Value = response. json ( ) ;
160135
161- // The locked_at timestamp should be the same as the current time, or null if
162- // not locked
136+ // The deactivated_at timestamp should be the same as the current time
137+ assert_eq ! (
138+ body[ "data" ] [ "attributes" ] [ "deactivated_at" ] ,
139+ serde_json:: json!( state. clock. now( ) )
140+ ) ;
141+
142+ // Deactivating the user should not lock it
163143 assert_eq ! (
164144 body[ "data" ] [ "attributes" ] [ "locked_at" ] ,
165- if skip_lock. unwrap_or( false ) {
166- serde_json:: Value :: Null
167- } else {
168- serde_json:: json!( state. clock. now( ) )
169- }
145+ serde_json:: Value :: Null
170146 ) ;
171147
172148 // Make sure to run the jobs in the queue
@@ -179,15 +155,15 @@ mod tests {
179155 response. assert_status ( StatusCode :: OK ) ;
180156 let body: serde_json:: Value = response. json ( ) ;
181157
182- allow_duplicates ! ( assert_json_snapshot!( body, @r#"
158+ assert_json_snapshot ! ( body, @r#"
183159 {
184160 "data": {
185161 "type": "user",
186162 "id": "01FSHN9AG0MZAA6S4AF7CTV32E",
187163 "attributes": {
188164 "username": "alice",
189165 "created_at": "2022-01-16T14:40:00Z",
190- "locked_at": "2022-01-16T14:40:00Z" ,
166+ "locked_at": null ,
191167 "deactivated_at": "2022-01-16T14:40:00Z",
192168 "admin": false
193169 },
@@ -199,17 +175,7 @@ mod tests {
199175 "self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E"
200176 }
201177 }
202- "# ) ) ;
203- }
204-
205- #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
206- async fn test_deactivate_user ( pool : PgPool ) {
207- test_deactivate_user_helper ( pool, Option :: None ) . await ;
208- }
209-
210- #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
211- async fn test_deactivate_user_skip_lock ( pool : PgPool ) {
212- test_deactivate_user_helper ( pool, Option :: Some ( true ) ) . await ;
178+ "# ) ;
213179 }
214180
215181 #[ sqlx:: test( migrator = "mas_storage_pg::MIGRATOR" ) ]
@@ -237,14 +203,16 @@ mod tests {
237203 response. assert_status ( StatusCode :: OK ) ;
238204 let body: serde_json:: Value = response. json ( ) ;
239205
240- // The locked_at timestamp should be different from the current time
241- assert_ne ! (
242- body[ "data" ] [ "attributes" ] [ "locked_at " ] ,
206+ // The deactivated_at timestamp should be the same as the current time
207+ assert_eq ! (
208+ body[ "data" ] [ "attributes" ] [ "deactivated_at " ] ,
243209 serde_json:: json!( state. clock. now( ) )
244210 ) ;
211+
212+ // The deactivated_at timestamp should be different from the locked_at timestamp
245213 assert_ne ! (
214+ body[ "data" ] [ "attributes" ] [ "deactivated_at" ] ,
246215 body[ "data" ] [ "attributes" ] [ "locked_at" ] ,
247- serde_json:: Value :: Null
248216 ) ;
249217
250218 // Make sure to run the jobs in the queue
0 commit comments