diff --git a/server/src/database/model/user.rs b/server/src/database/model/user.rs index 1b27b89..14594ed 100644 --- a/server/src/database/model/user.rs +++ b/server/src/database/model/user.rs @@ -157,4 +157,31 @@ impl UserMember { Ok(members) } + + pub async fn remove_many( + transaction: &mut sqlx::Transaction<'_, Postgres>, + user_ids: &[uuid::Uuid], + member_ids: &[String], + ) -> Result<(), sqlx::Error> { + let deleted_count = sqlx::query_scalar!( + " + WITH deleted AS ( + DELETE FROM users_members + WHERE user_id = ANY($1) AND member_id = ANY($2) + RETURNING 1 + ) + SELECT COUNT(*) FROM deleted + ", + &user_ids[..], + &member_ids[..] + ) + .fetch_one(&mut **transaction) + .await?; + + if !deleted_count.is_some_and(|c| c >= 1) { + return Err(sqlx::Error::RowNotFound); + } + + Ok(()) + } } diff --git a/server/src/routes/user.rs b/server/src/routes/user.rs index a1b0d32..d1a073d 100644 --- a/server/src/routes/user.rs +++ b/server/src/routes/user.rs @@ -1,7 +1,7 @@ use axum::{ extract::{Path, State}, http::HeaderMap, - routing::{get, post}, + routing::{delete, get, post}, Json, Router, }; @@ -17,6 +17,7 @@ pub fn routes() -> Router { Router::new() .route("/user", get(get_current_user)) .route("/user/{user_id}/members", post(members_insert)) + .route("/user/{user_id}/members", delete(members_remove)) } pub async fn get_current_user( @@ -52,3 +53,23 @@ pub async fn members_insert( Ok(Json(convert_vec(members))) } + +pub async fn members_remove( + State(state): State, + Path(user_id): Path, + headers: HeaderMap, + Json(member_ids): Json>, +) -> Result<(), crate::Error> { + let user = get_user_from_header(&state.pool, &headers).await?; + user.authorize(&state.pool, Some(Roles::ADMIN), Some(user_id)) + .await?; + + let mut transaction = state.pool.begin().await?; + + // Link the user to the members + DbUserMember::remove_many(&mut transaction, &[user.id], &member_ids).await?; + + transaction.commit().await?; + + Ok(()) +}