fix(webdav): native COPY honours destination filename (M8)
Threads `new_name: Option<&str>` through FileWritePort::copy_file and FileManagementUseCase::copy_file_with_perms so a same-folder COPY /a.txt → /b.txt picks up the destination name via a single COALESCE($3::text, name) in the CTE. Without it the new row inherits the source's filename and collides on the (folder_id, name, user_id) unique index — the "Already Exists" 500 M8 was hitting. handle_copy in the native WebDAV surface now passes `(file.name != dest_name).then(|| dest_name.into())`, keeping the "same name in a different folder" case at None so existing semantics are preserved.
This commit is contained in:
@@ -255,11 +255,17 @@ pub trait FileManagementUseCase: Send + Sync + 'static {
|
||||
) -> Result<FileDto, DomainError>;
|
||||
|
||||
/// Copies a file, enforcing that `caller_id` is the owner.
|
||||
///
|
||||
/// `new_name`, when `Some(_)`, becomes the copy's filename — without it
|
||||
/// the copy keeps the source's name, which makes "same folder, different
|
||||
/// name" copies (classic WebDAV `COPY /a.txt → /b.txt`) collide on the
|
||||
/// `(folder, name, user)` unique index.
|
||||
async fn copy_file_with_perms(
|
||||
&self,
|
||||
file_id: &str,
|
||||
caller_id: Uuid,
|
||||
target_folder_id: Option<String>,
|
||||
new_name: Option<String>,
|
||||
) -> Result<FileDto, DomainError>;
|
||||
|
||||
/// Renames a file, enforcing that `caller_id` is the owner.
|
||||
|
||||
@@ -314,10 +314,16 @@ pub trait FileWritePort: Send + Sync + 'static {
|
||||
///
|
||||
/// With blob-dedup, this only creates a new metadata row and increments
|
||||
/// the blob reference count — zero disk I/O for the content.
|
||||
///
|
||||
/// `new_name` is honored when `Some(_)` — without it, copying a file to
|
||||
/// the same folder always collides on the source's filename. WebDAV
|
||||
/// COPY uses this for the "same folder, different name" case (the
|
||||
/// classic `COPY /a.txt → /b.txt` pattern).
|
||||
async fn copy_file(
|
||||
&self,
|
||||
file_id: &str,
|
||||
target_folder_id: Option<String>,
|
||||
new_name: Option<&str>,
|
||||
) -> Result<File, DomainError>;
|
||||
|
||||
/// Copies an entire folder subtree atomically using ltree.
|
||||
|
||||
Reference in New Issue
Block a user