From bf1e7d687b36674a436d9761c6b97d0d70e7317e Mon Sep 17 00:00:00 2001 From: Thomas Churchman Date: Fri, 29 Dec 2023 18:40:24 +0100 Subject: [PATCH] Add endpoint to delete media --- astroplant-api/src/authorization/mod.rs | 3 +- astroplant-api/src/bin/astroplant-api.rs | 1 + astroplant-api/src/controllers/media/mod.rs | 67 ++++++++++++++++++++- astroplant-api/src/models/kit.rs | 4 +- openapi.yaml | 27 +++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) diff --git a/astroplant-api/src/authorization/mod.rs b/astroplant-api/src/authorization/mod.rs index 410975b..3bde2c8 100644 --- a/astroplant-api/src/authorization/mod.rs +++ b/astroplant-api/src/authorization/mod.rs @@ -40,6 +40,7 @@ pub enum KitAction { View, SubscribeRealTimeMeasurements, Delete, + DeleteMedia, ResetPassword, EditDetails, EditConfiguration, @@ -71,7 +72,7 @@ impl Permission for KitAction { }, UserWithMembership(_user, membership) => match self { View | SubscribeRealTimeMeasurements => true, - EditDetails | EditConfiguration => membership.access_configure, + EditDetails | EditConfiguration | DeleteMedia => membership.access_configure, Delete | ResetPassword | EditMembers | SetSuperMember => membership.access_super, RpcVersion | RpcUptime | RpcPeripheralCommand | RpcPeripheralCommandLock => { membership.access_super diff --git a/astroplant-api/src/bin/astroplant-api.rs b/astroplant-api/src/bin/astroplant-api.rs index 1584edd..51ac4ab 100644 --- a/astroplant-api/src/bin/astroplant-api.rs +++ b/astroplant-api/src/bin/astroplant-api.rs @@ -58,6 +58,7 @@ async fn main() -> anyhow::Result<()> { "/media/:media_id/content", get(media::download_media).layer(Extension(object_store)), ) + .route("/media/:media_id", delete(media::delete_media)) .route("/kits", get(kit::kits)) .route("/kits", post(kit::create_kit)) .route("/kits/:kit_serial", get(kit::kit_by_serial)) diff --git a/astroplant-api/src/controllers/media/mod.rs b/astroplant-api/src/controllers/media/mod.rs index 567462b..f5fb9b6 100644 --- a/astroplant-api/src/controllers/media/mod.rs +++ b/astroplant-api/src/controllers/media/mod.rs @@ -70,7 +70,72 @@ pub async fn kit_media( Ok(response.body(body)) } -/// Handles the `GET` /media/{mediaId}/content` route. +/// Handles the `DELETE /media/{mediaId}` route. +pub async fn delete_media( + Extension(pg): Extension, + user_id: Option, + Path(media_id): Path, +) -> Result { + use crate::schema::media; + use diesel::prelude::*; + let media_id = models::MediaId(media_id); + + // Check user authorization and make sure the configuration has never been activated. + let conn = pg.clone().get().await?; + + { + let kit = conn + .interact_flatten_err(move |conn| { + let kit = media::table + .inner_join(crate::schema::kits::table) + .filter(crate::schema::media::id.eq(media_id.id())) + .select(crate::models::Kit::as_select()) + .first(conn) + .optional()? + .ok_or(NOT_FOUND)?; + + Ok::<_, Problem>(kit) + }) + .await?; + + // FIXME: this unnecessarily queries for the kit: we already have it. + helpers::fut_kit_permission_or_forbidden( + pg, + user_id, + kit.serial.to_owned(), + authorization::KitAction::DeleteMedia, + ) + .await?; + } + + conn.interact_flatten_err(move |conn| { + use crate::schema::queue_media_pending_deletion; + + conn.transaction(|conn| { + let selected_media = media::dsl::media.find(media_id.id()); + + // 1. Add this media to the pending deletion queue. + selected_media + .select((media::id, media::datetime, media::size)) + .insert_into(queue_media_pending_deletion::table) + .into_columns(( + queue_media_pending_deletion::media_id, + queue_media_pending_deletion::media_datetime, + queue_media_pending_deletion::media_size, + )) + .execute(conn)?; + + // 2. Delete this media from the media table. + diesel::delete(selected_media).execute(conn)?; + + Ok::<_, diesel::result::Error>(()) + })?; + + Ok::<_, Problem>(ResponseBuilder::ok().empty()) + }) + .await +} + /// Handles the `GET /media/{mediaId}/content` route. pub async fn download_media( Extension(pg): Extension, diff --git a/astroplant-api/src/models/kit.rs b/astroplant-api/src/models/kit.rs index 4cb19dc..5e95b54 100644 --- a/astroplant-api/src/models/kit.rs +++ b/astroplant-api/src/models/kit.rs @@ -3,14 +3,14 @@ use crate::schema::kits; use bigdecimal::BigDecimal; use diesel::pg::PgConnection; use diesel::prelude::*; -use diesel::{Identifiable, QueryResult, Queryable}; +use diesel::{Identifiable, QueryResult, Queryable, Selectable}; use validator::Validate; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Identifiable)] #[diesel(table_name = kits)] pub struct KitId(#[diesel(column_name = id)] pub i32); -#[derive(Clone, Debug, PartialEq, Eq, Queryable, Identifiable)] +#[derive(Clone, Debug, PartialEq, Eq, Queryable, Identifiable, Selectable)] #[diesel(table_name = kits)] pub struct Kit { pub id: i32, diff --git a/openapi.yaml b/openapi.yaml index ae22413..2d78984 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -959,6 +959,33 @@ paths: $ref: "#/components/responses/ErrorRateLimit" '500': $ref: "#/components/responses/ErrorInternalServer" + "/media/{mediaId}": + delete: + summary: Delete media. + operationId: deleteMedia + security: + - bearerAuth: [] + tags: + - kits + parameters: + - name: mediaId + in: path + required: true + description: The id of the media to delete. + schema: + type: string + format: uuid + responses: + '200': + description: The media was successfully deleted. + content: + "*": {} + '401': + $ref: "#/components/responses/ErrorUnauthorized" + '429': + $ref: "#/components/responses/ErrorRateLimit" + '500': + $ref: "#/components/responses/ErrorInternalServer" "/media/{mediaId}/content": get: summary: Download media content.