This commit is contained in:
Leon Bösche
2026-02-03 19:38:13 +01:00
parent 85fed3d1d9
commit 88aefae33b
2 changed files with 65 additions and 8 deletions

Binary file not shown.

View File

@@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"path"
"path/filepath"
"strings"
"sync"
"time"
@@ -524,7 +525,7 @@ func wopiPutFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
return
}
// Read file content from request body
// Read file content from request body first
content, err := io.ReadAll(r.Body)
if err != nil {
fmt.Printf("[WOPI-STORAGE] Failed to read request body: %v\n", err)
@@ -533,28 +534,84 @@ func wopiPutFileHandler(w http.ResponseWriter, r *http.Request, db *database.DB,
}
defer r.Body.Close()
// Check for suggested target (used for export operations like Save as PDF)
suggestedTarget := r.Header.Get("X-WOPI-SuggestedTarget")
isExport := suggestedTarget != ""
var targetFile *database.File
var targetRemotePath string
if isExport {
// Parse suggested target
var newName string
if strings.HasPrefix(suggestedTarget, ".") {
// Extension only, e.g., ".pdf"
baseName := strings.TrimSuffix(file.Name, filepath.Ext(file.Name))
newName = baseName + suggestedTarget
} else {
// Full filename, e.g., "document.pdf"
newName = suggestedTarget
}
// Determine new path
var newPath string
if file.OrgID != nil {
// For org files, place in same directory
dir := filepath.Dir(file.Path)
newPath = filepath.Join(dir, newName)
} else {
// For user files, place in same directory
dir := filepath.Dir(file.Path)
newPath = filepath.Join(dir, newName)
}
// Create new file entry in database
newFile, err := db.CreateFile(r.Context(), file.OrgID, file.UserID, newName, newPath, "application/pdf", int64(len(content)))
if err != nil {
fmt.Printf("[WOPI-EXPORT] Failed to create export file: %v\n", err)
errors.WriteError(w, errors.CodeInternal, "Failed to create export file", http.StatusInternalServerError)
return
}
targetFile = newFile
// Set remote path for the new file
if file.OrgID != nil {
rel := strings.TrimPrefix(newPath, "/")
targetRemotePath = path.Join("/orgs", file.OrgID.String(), rel)
} else {
targetRemotePath = newPath
}
fmt.Printf("[WOPI-EXPORT] Export operation: original=%s new=%s path=%s\n", file.Name, newName, targetRemotePath)
} else {
// Normal save operation
targetFile = file
targetRemotePath = remotePath
}
// Upload to storage
fmt.Printf("[WOPI-STORAGE] PutFile uploading: file=%s remotePath=%s\n", fileID, remotePath)
err = webDAVClient.Upload(r.Context(), remotePath, strings.NewReader(string(content)), int64(len(content)))
fmt.Printf("[WOPI-STORAGE] PutFile uploading: file=%s remotePath=%s\n", targetFile.ID.String(), targetRemotePath)
err = webDAVClient.Upload(r.Context(), targetRemotePath, strings.NewReader(string(content)), int64(len(content)))
if err != nil {
fmt.Printf("[WOPI-STORAGE] Failed to upload file: file=%s path=%s error=%v\n", fileID, file.Path, err)
fmt.Printf("[WOPI-STORAGE] Failed to upload file: file=%s path=%s error=%v\n", targetFile.ID.String(), targetFile.Path, err)
errors.WriteError(w, errors.CodeInternal, "Failed to save file", http.StatusInternalServerError)
return
}
// Update file size and modification time in database
newSize := int64(len(content))
err = db.UpdateFileSize(r.Context(), fileUUID, newSize, &userID)
err = db.UpdateFileSize(r.Context(), targetFile.ID, newSize, &userID)
if err != nil {
fmt.Printf("[WOPI-STORAGE] Failed to update file size: file=%s error=%v\n", fileID, err)
fmt.Printf("[WOPI-STORAGE] Failed to update file size: file=%s error=%v\n", targetFile.ID.String(), err)
// Don't fail the upload, just log the warning
}
fmt.Printf("[WOPI-STORAGE] PutFile: file=%s user=%s bytes=%d\n", fileID, userID.String(), newSize)
fmt.Printf("[WOPI-STORAGE] PutFile: file=%s user=%s bytes=%d\n", targetFile.ID.String(), userID.String(), newSize)
// Return response
response := models.WOPIPutFileResponse{
ItemVersion: fileUUID.String(),
ItemVersion: targetFile.ID.String(),
}
w.Header().Set("Content-Type", "application/json")