diff --git a/gpodder/src/repository/admin.rs b/gpodder/src/repository/admin.rs index b8b3d7b..c85557a 100644 --- a/gpodder/src/repository/admin.rs +++ b/gpodder/src/repository/admin.rs @@ -14,4 +14,8 @@ impl<'a> AdminRepository<'a> { ) -> Result, AuthErr> { self.store.paginated_users(page, filter) } + + pub fn remove_user(&self, id: i64) -> Result { + self.store.remove_user(id) + } } diff --git a/gpodder/src/store.rs b/gpodder/src/store.rs index dea0449..8741755 100644 --- a/gpodder/src/store.rs +++ b/gpodder/src/store.rs @@ -54,6 +54,9 @@ pub trait GpodderAuthStore { /// Update the user with the included ID with the new values fn update_user(&self, user: User) -> Result; + /// Remove the user with the given ID + fn remove_user(&self, id: i64) -> Result; + /// Create a new session for a user with the given session ID /// /// The `last_seen` timestamp's precision should be at least accurate to the second diff --git a/gpodder_sqlite/src/repository/auth.rs b/gpodder_sqlite/src/repository/auth.rs index 67a1314..0072938 100644 --- a/gpodder_sqlite/src/repository/auth.rs +++ b/gpodder_sqlite/src/repository/auth.rs @@ -81,6 +81,16 @@ impl gpodder::GpodderAuthStore for SqliteRepository { .map_err(DbError::from)?) } + fn remove_user(&self, id: i64) -> Result { + let conn = &mut self.pool.get().map_err(DbError::from)?; + + match diesel::delete(users::table.filter(users::id.eq(id))).execute(conn) { + Ok(0) => Ok(false), + Ok(_) => Ok(true), + Err(err) => Err(DbError::from(err).into()), + } + } + fn get_session(&self, session_id: i64) -> Result, AuthErr> { match sessions::table .inner_join(users::table) diff --git a/otter/src/server/web/users.rs b/otter/src/server/web/users.rs index 9d412e1..c719076 100644 --- a/otter/src/server/web/users.rs +++ b/otter/src/server/web/users.rs @@ -17,6 +17,7 @@ use crate::{ pub fn router(ctx: Context) -> Router { Router::new() .route("/users", get(get_users)) + .route("/users/{id}", delete(delete_user)) .route_layer(axum::middleware::from_fn_with_state( ctx.clone(), super::auth::auth_web_middleware, @@ -70,3 +71,20 @@ async fn get_users( .authenticated(true) .response(&ctx.tera)) } + +async fn delete_user( + State(ctx): State, + Extension(session): Extension, + Path(id): Path, +) -> AppResult<()> { + let deleted = + tokio::task::spawn_blocking(move || ctx.store.admin(&session.user)?.remove_user(id)) + .await + .unwrap()?; + + if deleted { + Ok(()) + } else { + Err(AppError::NotFound) + } +}