diff --git a/src/components/file_drop.rs b/src/components/file_drop.rs index 66f72d7..3774c99 100644 --- a/src/components/file_drop.rs +++ b/src/components/file_drop.rs @@ -1,4 +1,4 @@ -use crate::pages::api::files::upload_file; +use crate::pages::api::files::{DeleteFile, upload_file}; use leptos::html::{Input, Label}; use leptos::logging::debug_log; use leptos::prelude::*; @@ -23,7 +23,10 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im async move { upload_file(form_data.into()).await } }); + let delete_action = ServerAction::::new(); + let uploading = upload_action.pending(); + let deleting = delete_action.pending(); let upload_files = Callback::new(move |files: Vec| { let form_data = FormData::new().unwrap(); @@ -86,6 +89,19 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im upload_files.run(files); }; + let on_click_file_delete = move |file_name: String| { + let access_token = auth + .try_with(|a| a.authenticated().map(|a| a.access_token())) + .flatten(); + + delete_action.dispatch(DeleteFile { + form_id: form_id.get_value(), + input_name: name.get_value(), + access_token: access_token.unwrap_or_default(), + file_name, + }) + }; + // Add file names to the list when upload_action is successful. Effect::new(move || { if let Some(Ok(uploaded_file_name)) = upload_action.value().get() { @@ -95,9 +111,14 @@ pub fn FileDrop(#[prop(into)] name: String, #[prop(into)] form_id: String) -> im } }); - // let on_click_file_delete = move |file_name, form_id| { - // - // }; + // Remove file name from the list when delete_action is successful. + Effect::new(move || { + if let Some(Ok(deleted_file_name)) = delete_action.value().get() { + file_name_list.update(|list| { + list.retain(|f| *f != deleted_file_name); + }); + } + }); view! { - -
-
{file}
-
- -
-
-
+ +
{file.get_value()}
+
+ +
+ + } + } + /> } } diff --git a/src/pages/api/files.rs b/src/pages/api/files.rs index a46b9ae..22f3bb9 100644 --- a/src/pages/api/files.rs +++ b/src/pages/api/files.rs @@ -87,7 +87,7 @@ pub async fn upload_file(data: MultipartData) -> Result { ) .item( "SK".to_string(), - AttributeValue::S(format!("FILE#{form_id}#{input_name}")), + AttributeValue::S(format!("FILE#{form_id}#{input_name}#{file_name}")), ) .item( "file_name".to_string(), @@ -128,25 +128,62 @@ pub async fn upload_file(data: MultipartData) -> Result { pub async fn delete_file( access_token: String, form_id: String, + input_name: String, file_name: String, -) -> Result<(), ServerFnError> { - use super::S3_BUCKET_NAME; +) -> Result { + use super::{MAIN_TABLE_NAME, S3_BUCKET_NAME}; use crate::pages::api::tokens::validate_and_get_token_info; use crate::utils::server::create_aws_config; + use aws_sdk_dynamodb::types::{AttributeValue, ReturnValue}; let user_claims = validate_and_get_token_info(access_token).await?; let subject = user_claims.subject; - let key = format!("{form_id}/{subject}/{file_name}"); + let entry_hk = format!("STUDENT#{subject}"); + let entry_sk = format!("FILE#{form_id}#{input_name}#{file_name}"); - let client = aws_sdk_s3::Client::new(&create_aws_config().await); + let key = format!("{form_id}/{subject}/{input_name}/{file_name}"); - client + let config = create_aws_config().await; + let s3_client = aws_sdk_s3::Client::new(&config); + let dynamo_client = aws_sdk_dynamodb::Client::new(&config); + + let previous_values = dynamo_client + .delete_item() + .table_name(MAIN_TABLE_NAME) + .key("HK".to_string(), AttributeValue::S(entry_hk)) + .key("SK".to_string(), AttributeValue::S(entry_sk)) + .return_values(ReturnValue::AllOld) + .send() + .await? + .attributes + .unwrap_or_default(); + + let s3_result = s3_client .delete_object() .bucket(S3_BUCKET_NAME) .key(key) .send() .await - .map(|_| ()) - .map_err(ServerFnError::from) + .map_err(ServerFnError::from); + + if let Err(err) = s3_result { + // Add the key back to Dynamo and return an error. + dynamo_client + .put_item() + .table_name(MAIN_TABLE_NAME) + .set_item(Some(previous_values)) + .send() + .await + .map_err(|err| { + ServerFnError::new(format!( + "Couldn't roll back Dynamo operation: {}", + err.to_string() + )) + })?; + + return Err(err); + } + + Ok(file_name) }