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:
Edouard Vanbelle
2026-06-17 01:43:13 +02:00
parent bacd5806d3
commit f9de7ac596
9 changed files with 83 additions and 26 deletions
@@ -397,10 +397,12 @@ impl FileWritePort for FileBlobWriteRepository {
&self,
file_id: &str,
target_folder_id: Option<String>,
new_name: Option<&str>,
) -> Result<File, DomainError> {
// Atomic CTE: read source file → insert new row with same blob_hash → increment ref_count.
// Single round-trip; blob content is NOT copied (dedup makes this zero-copy).
let target_fid = target_folder_id.clone();
let rename_to = new_name.map(|s| s.to_string());
let row = retry_on_deadlock("files.copy", || {
sqlx::query_as::<
@@ -424,7 +426,7 @@ impl FileWritePort for FileBlobWriteRepository {
),
new_file AS (
INSERT INTO storage.files (name, folder_id, user_id, blob_hash, size, mime_type, category_order)
SELECT name,
SELECT COALESCE($3::text, name),
COALESCE($2::uuid, folder_id),
user_id,
blob_hash,
@@ -442,6 +444,7 @@ impl FileWritePort for FileBlobWriteRepository {
)
.bind(file_id)
.bind(&target_fid)
.bind(&rename_to)
.fetch_optional(self.pool.as_ref())
})
.await