From e0d8218a418c229d2467e7b7e6415c026ba7f034 Mon Sep 17 00:00:00 2001 From: Emmie Maeda Date: Wed, 12 Jun 2024 07:21:42 -0400 Subject: [PATCH] [WIP] Start division between new and edit file uploads. --- deepwell/src/services/blob/service.rs | 3 + deepwell/src/services/file/service.rs | 123 ++++++++++++++++++-------- deepwell/src/services/file/structs.rs | 29 +++++- 3 files changed, 115 insertions(+), 40 deletions(-) diff --git a/deepwell/src/services/blob/service.rs b/deepwell/src/services/blob/service.rs index e30e01fc799..e43e8a55b53 100644 --- a/deepwell/src/services/blob/service.rs +++ b/deepwell/src/services/blob/service.rs @@ -134,6 +134,9 @@ impl BlobService { } }; + debug!("Deleting pending blob"); + BlobPending::delete_by_id(pending_blob_id).exec(txn).await?; + // Special handling for empty blobs if data.is_empty() { debug!("File being created is empty, special case"); diff --git a/deepwell/src/services/file/service.rs b/deepwell/src/services/file/service.rs index 27b1914dfd0..a00c97f3e48 100644 --- a/deepwell/src/services/file/service.rs +++ b/deepwell/src/services/file/service.rs @@ -36,13 +36,15 @@ use crate::services::{BlobService, FileRevisionService, FilterService}; pub struct FileService; impl FileService { + /// Creates a new file. + /// /// Starts a file upload and tracks it as a distinct file entity. /// /// In the background, this stores the blob via content addressing, /// meaning that duplicates are not uploaded twice. - pub async fn start_upload( + pub async fn start_new_upload( ctx: &ServiceContext<'_>, - UploadFile { + UploadNewFile { site_id, page_id, name, @@ -50,9 +52,10 @@ impl FileService { user_id, licensing, bypass_filter, - }: UploadFile, + }: UploadNewFile, ) -> Result { info!("Creating file with name '{}'", name); + let txn = ctx.transaction(); // Ensure row consistency Self::check_conflicts(ctx, page_id, &name, "create").await?; @@ -74,10 +77,9 @@ impl FileService { ..Default::default() }; - let txn = ctx.transaction(); let file = model.insert(txn).await?; - // Add new file revision (with dummy data) + // Add file revision (with dummy file data) let revision_output = FileRevisionService::create_first( ctx, CreateFirstFileRevision { @@ -98,17 +100,17 @@ impl FileService { Ok(revision_output) } - pub async fn finish_upload( + pub async fn finish_new_upload( ctx: &ServiceContext<'_>, - FinishUploadFile { + FinishUploadNewFile { site_id, page_id, file_id, pending_blob_id, - }: FinishUploadFile, + }: FinishUploadNewFile, ) -> Result { info!( - "Finishing file upload with site ID {} page ID {} file ID {} pending ID {}", + "Finishing new file upload with site ID {} page ID {} file ID {} pending ID {}", site_id, page_id, file_id, pending_blob_id, ); @@ -157,8 +159,6 @@ impl FileService { }; model.update(txn).await?; - File::delete_by_id(pending_blob_id).exec(txn).await?; - // Update file revision to add the uploaded data let FinalizeBlobUploadOutput { hash, @@ -176,7 +176,82 @@ impl FileService { Ok(FinishUploadFileOutput { created }) } - /// Edits a file, including the ability to upload a new version. + /// Edits a file, uploading a new file version. + pub async fn start_edit_upload( + ctx: &ServiceContext<'_>, + UploadFileEdit { + site_id, + page_id, + file_id, + user_id, + revision_comments, + }: UploadFileEdit, + ) -> Result<_UploadFileEditOutput> { + info!("Uploading new version to file ID {file_id}"); + + let txn = ctx.transaction(); + let last_revision = + FileRevisionService::get_latest(ctx, site_id, page_id, file_id).await?; + + // Add pending file + let pending = BlobService::create_upload(ctx).await?; + + // Add file revision (with dummy file data) + let revision_output = FileRevisionService::create( + ctx, + CreateFileRevision { + site_id, + page_id, + file_id, + user_id, + comments: revision_comments, + body: CreateFileRevisionBody { + blob: FileBlob { + s3_hash: EMPTY_BLOB_HASH, + mime_hint: str!(EMPTY_BLOB_MIME), + size_hint: 0, + }, + ..Default::default() + }, + }, + last_revision, + ) + .await?; + + Ok(revision_output) + } + + pub async fn finish_edit_upload( + ctx: &ServiceContext<'_>, + FinishUploadFileEdit { + site_id, + page_id, + file_id, + pending_blob_id, + }: FinishUploadFileEdit, + ) -> Result<_> { + info!( + "Finishing file edit upload with site ID {} page ID {} file ID {} pending ID {}", + site_id, page_id, file_id, pending_blob_id, + ); + + // Get latest file revision + // TODO + + // Update file metadata + let model = file::ActiveModel { + file_id: Set(file_id), + updated_at: Set(Some(now())), + ..Default::default() + }; + model.update(txn).await?; + + todo!() + } + + /// Edits a file, creating a new revision. + /// + /// Cannot be used to upload a new file version. pub async fn edit( ctx: &ServiceContext<'_>, EditFile { @@ -209,29 +284,6 @@ impl FileService { } } - // Upload to S3, get derived metadata - // FIXME upload new file revision - /* - let blob = match data { - ProvidedValue::Unset => ProvidedValue::Unset, - ProvidedValue::Set(bytes) => { - let FinalizeBlobUploadOutput { - hash, - mime, - size, - created: _, - } = BlobService::finalize_upload(ctx, &bytes).await?; - - ProvidedValue::Set(FileBlob { - s3_hash: hash, - size_hint: size, - mime_hint: mime, - }) - } - }; - */ - let blob = ProvidedValue::Unset; - // Update file metadata let model = file::ActiveModel { file_id: Set(file_id), @@ -251,7 +303,6 @@ impl FileService { comments: revision_comments, body: CreateFileRevisionBody { name, - blob, licensing, ..Default::default() }, diff --git a/deepwell/src/services/file/structs.rs b/deepwell/src/services/file/structs.rs index 9af4a8cd50c..4b88d4c80ee 100644 --- a/deepwell/src/services/file/structs.rs +++ b/deepwell/src/services/file/structs.rs @@ -27,7 +27,7 @@ use serde_json::Value as JsonValue; use time::OffsetDateTime; #[derive(Deserialize, Debug, Clone)] -pub struct UploadFile { +pub struct UploadNewFile { pub site_id: i64, pub page_id: i64, pub name: String, @@ -39,10 +39,11 @@ pub struct UploadFile { pub bypass_filter: bool, } -pub type UploadFileOutput = CreateFirstFileRevisionOutput; +// TODO +pub type UploadNewFileOutput = CreateFirstFileRevisionOutput; #[derive(Deserialize, Debug, Clone)] -pub struct FinishUploadFile { +pub struct FinishUploadNewFile { pub site_id: i64, pub page_id: i64, pub file_id: i64, @@ -50,10 +51,30 @@ pub struct FinishUploadFile { } #[derive(Serialize, Debug, Copy, Clone)] -pub struct FinishUploadFileOutput { +pub struct FinishUploadNewFileOutput { pub created: bool, } +#[derive(Deserialize, Debug, Clone)] +pub struct UploadFileEdit { + pub site_id: i64, + pub page_id: i64, + pub file_id: i64, + pub user_id: i64, + pub revision_comments: String, +} + +pub type UploadFileEditOutput = CreateFileRevisionOutput; + +#[derive(Deserialize, Debug, Clone)] +pub struct FinishUploadFileEdit { +} + +#[derive(Serialize, Debug, Clone)] +pub struct FinishUploadFileEditOutput { + // TODO +} + #[derive(Deserialize, Debug, Clone)] pub struct GetFile<'a> { pub site_id: i64,