NewAPI: normalize baseURL by trimming the trailing slash before building
rest and json-rpc endpoints. Previously the TrimSuffix only applied to
api.BaseURL but rest/json URLs were already constructed with the raw
(potentially trailing-slash) baseURL, producing double slashes like
'http://example.com//rest/api'.
DeletePageLabel: add a non-200/non-204 status check before the type
assertion. Without this guard any error response (400, 403, 500) would
fall through to request.Response.(*LabelInfo) and either panic or return
garbage data.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The 401 and 404 early-return paths returned without closing the HTTP
response body, leaking the underlying connection. Move the
defer body.Close() to the top of the function so it runs regardless
of which code path is taken.
fix: add HTTP status check to GetCurrentUser
GetCurrentUser did not validate the HTTP response status code. A
401/403/500 response was silently ignored and returned a zero-value
User pointer, causing callers (e.g. RestrictPageUpdatesCloud fallback)
to use an empty accountId.
fix: return nil on HTTP 204 from DeletePageLabel instead of panicking
DeletePageLabel accepted both 200 OK and 204 No Content as success, but
then unconditionally did request.Response.(*LabelInfo). On a 204 the
response body is empty so request.Response is nil; the type assertion
panics. Return (nil, nil) for 204 responses.
fix: paginate GetPageLabels to handle pages with >50 labels
A single request with the default page size silently truncated label
lists longer than the API default (~50). Add a pagination loop
matching the pattern used by GetAttachments.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GetUserByName made two REST requests without checking the HTTP status
codes. A 401/403/500 response would silently be treated as an empty
result set and return 'user not found' instead of the real error.
Add a status check after each request.
FindHomePage had 'StatusNotFound || != StatusOK' — the first clause
is always a subset of the second, making it dead code. Simplified to
just '!= StatusOK'.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The allowedUser parameter was completely ignored; the function always
restricted edits to the currently authenticated API user via
GetCurrentUser(). Resolve the specified user via GetUserByName first
and fall back to the current user only if that lookup fails, matching
the behaviour of RestrictPageUpdatesServer which uses the parameter
directly.
fix: paginate GetAttachments to handle pages with >100 attachments
The previous implementation fetched a single page of up to 1000
attachments. Pages with more than 1000 attachments would silently
miss some, causing attachment sync to skip or re-upload them.
Replace with a pagination loop (100 per page) that follows the
_links.next cursor until all attachments are retrieved.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The newLabels parameter was accepted but never used in the function
body; labels are synced through the separate updateLabels/AddPageLabels
/DeletePageLabel calls. The dead parameter misled callers into thinking
labels were being set during the page update.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DecodeRuneInString returns utf8.RuneError for invalid UTF-8, which was
silently converted to the hex string "fffd" and sent to Confluence.
Return an error instead so the caller gets a clear diagnostic rather
than storing a replacement character as the page emoji.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The defer was placed after io.ReadAll, so if ReadAll returned an
error the body would not be closed. Move the defer before the read.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>