diff --git a/services/backup/src/database/mod.rs b/services/backup/src/database/mod.rs --- a/services/backup/src/database/mod.rs +++ b/services/backup/src/database/mod.rs @@ -306,6 +306,24 @@ // general functions impl DatabaseClient { + pub async fn delete_user_data( + &self, + user_id: &str, + blob_client: &BlobServiceClient, + ) -> Result<(), Error> { + // query the index to avoid unnecessarily querying backup data + let items = self.query_ordered_backups_index(user_id, None).await?; + + for item in items { + trace!("Removing backup item: {item:?}"); + self + .remove_backup_item(user_id, &item.backup_id, blob_client) + .await?; + } + + Ok(()) + } + async fn query_ordered_backups_index( &self, user_id: &str, diff --git a/services/backup/src/http/handlers/user_data.rs b/services/backup/src/http/handlers/user_data.rs new file mode 100644 --- /dev/null +++ b/services/backup/src/http/handlers/user_data.rs @@ -0,0 +1,38 @@ +use actix_web::{ + error::ErrorForbidden, + web::{self}, + HttpResponse, +}; +use comm_lib::{ + auth::AuthorizationCredential, blob::client::BlobServiceClient, + http::auth_service::Authenticated, +}; +use tracing::{info, instrument}; + +use crate::{database::DatabaseClient, error::BackupError}; + +#[instrument(skip_all, fields(backup_id = %path))] +pub async fn delete_user_data( + requesting_identity: AuthorizationCredential, + path: web::Path, + db_client: web::Data, + blob_client: Authenticated, +) -> actix_web::Result { + match requesting_identity { + AuthorizationCredential::ServicesToken(_) => (), + _ => { + return Err(ErrorForbidden( + "This endpoint can only be called by other services", + )); + } + }; + + info!("Delete user data request"); + let user_id = path.into_inner(); + db_client + .delete_user_data(&user_id, &blob_client) + .await + .map_err(BackupError::from)?; + + Ok(HttpResponse::NoContent().finish()) +} diff --git a/services/backup/src/http/mod.rs b/services/backup/src/http/mod.rs --- a/services/backup/src/http/mod.rs +++ b/services/backup/src/http/mod.rs @@ -11,6 +11,7 @@ mod handlers { pub(super) mod backup; pub(super) mod log; + pub(super) mod user_data; } pub async fn run_http_server( @@ -67,6 +68,14 @@ web::scope("/logs") .service(web::resource("").route(web::get().to(handle_ws))), ) + .service( + web::scope("/user_data") + .wrap(get_comm_authentication_middleware()) + .service( + web::resource("{user_id}") + .route(web::delete().to(handlers::user_data::delete_user_data)), + ), + ) }) .bind(("0.0.0.0", CONFIG.http_port))? .run()