Merge pull request 'fix(files): UpdateFile uses PUT (#25)' (#26) from fix/update-file-put#25 into main
Release / GoReleaser (push) Skipped
Release Please / Release Please (push) Skipped
Tests / Secret scan (gitleaks) (push) Successful in 4s
Tests / Test (Go stable) (push) Successful in 18s
Tests / Test (Go 1.25) (push) Successful in 23s

This commit was merged in pull request #26.
This commit is contained in:
2026-09-15 08:22:50 +01:00
2 changed files with 30 additions and 10 deletions
+20 -8
View File
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"net/http"
"net/url" "net/url"
"path" "path"
"strconv" "strconv"
@@ -357,20 +358,31 @@ func (c *Client) UploadToFolder(ctx context.Context, folderID, localPath string)
// UpdateFile uploads a new version of an existing file (same id, name and // UpdateFile uploads a new version of an existing file (same id, name and
// folder). It does not delete and does not create a second file. // folder). It does not delete and does not create a second file.
//
// The Documents API method is PUT /api/2.0/files/{id}/update; POST is kept as
// a fallback for older servers. The path is tried with and without .json.
func (c *Client) UpdateFile(ctx context.Context, fileID, localPath string) (*FileEntry, error) { func (c *Client) UpdateFile(ctx context.Context, fileID, localPath string) (*FileEntry, error) {
if fileID == "" || localPath == "" { if fileID == "" || localPath == "" {
return nil, fmt.Errorf("file id and local path are required") return nil, fmt.Errorf("file id and local path are required")
} }
uploadPath := fmt.Sprintf("/api/2.0/files/%s/update", url.PathEscape(fileID)) base := fmt.Sprintf("/api/2.0/files/%s/update", url.PathEscape(fileID))
raw, err := c.uploadMultipart(ctx, uploadPath, "file", localPath) attempts := []struct {
if err != nil { method, path string
uploadPath = fmt.Sprintf("/api/2.0/files/%s/update.json", url.PathEscape(fileID)) }{
raw, err = c.uploadMultipart(ctx, uploadPath, "file", localPath) {http.MethodPut, base},
if err != nil { {http.MethodPut, base + ".json"},
return nil, err {http.MethodPost, base},
} {http.MethodPost, base + ".json"},
} }
var lastErr error
for _, a := range attempts {
raw, err := c.uploadMultipartMethod(ctx, a.method, a.path, "file", localPath)
if err == nil {
return decodeResponseFileEntry(raw) return decodeResponseFileEntry(raw)
}
lastErr = err
}
return nil, lastErr
} }
// FileFolderID returns the parent folder id string for a file entry, if known. // FileFolderID returns the parent folder id string for a file entry, if known.
+9 -1
View File
@@ -346,6 +346,14 @@ func (c *Client) putJSON(ctx context.Context, path string, body any) (json.RawMe
// uploadMultipart posts a single file to path under the given form field name. // uploadMultipart posts a single file to path under the given form field name.
func (c *Client) uploadMultipart(ctx context.Context, path, fieldName, filePath string) (json.RawMessage, error) { func (c *Client) uploadMultipart(ctx context.Context, path, fieldName, filePath string) (json.RawMessage, error) {
return c.uploadMultipartMethod(ctx, http.MethodPost, path, fieldName, filePath)
}
// uploadMultipartMethod sends a single-file multipart request with the given
// HTTP method. The OnlyOffice Documents API needs PUT for /update (a new
// version) and POST for /upload (a new file); sending POST to /update answers
// 500 on current servers.
func (c *Client) uploadMultipartMethod(ctx context.Context, method, path, fieldName, filePath string) (json.RawMessage, error) {
auth, err := c.authHeader() auth, err := c.authHeader()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -368,7 +376,7 @@ func (c *Client) uploadMultipart(ctx context.Context, path, fieldName, filePath
if err := mw.Close(); err != nil { if err := mw.Close(); err != nil {
return nil, err return nil, err
} }
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL()+path, &buf) req, err := http.NewRequestWithContext(ctx, method, c.baseURL()+path, &buf)
if err != nil { if err != nil {
return nil, err return nil, err
} }