A migration clears the background of projects whose background file is
also a task attachment, an avatar, a data export, a pending import upload
or another project's background. Of projects sharing a file, the oldest
keeps it.
The Unsplash and upload providers now remove the old background through
DeleteBackgroundFileIfExists.
Images longer than MaxSide (65535) pixels on either side are now rejected
before decoding, like images over the pixel limit.
Attachments with such images are still stored; only their preview is not
generated. Project backgrounds and avatars reject them with the existing
image too large error.
The user data export embedded every related task in full, repeating its
description once per relation. Related tasks are now exported as id and
project id only, since every related task is part of the export anyway.
The importer resolves such references across all imported projects and
creates relations once every project exists, so relations between
projects survive the round trip instead of duplicating the related task.
Exports with the full related task shape import as before.
- Reject a config that maps a column more than once, already when the
import is started or previewed.
- Import repeated labels of a row once and reject rows with more than
MaxLabelsPerTask (100) labels.
- Count items while converting rows so a file over the import item limit
fails before the whole structure is built.
- Walk mappings sorted by column so a row only visits the cells it has.
Lists, cards, checklists and attachments are looked up by id while
converting a board, so a repeated id imported the whole group once per
copy. Keep the first entry of each id and stop the conversion as soon as
the import item limit is exceeded instead of after building everything.
An empty find_action result looked identical to "not authorized", so
agents guessing a wrong resource prefix (task_relations instead of
tasks_relations) concluded their token lacked permission.
Refs #4342
Adds a mock OpenID provider issuing signed ID tokens so AuthenticateCallback
can be tested end to end, and pins the current behaviour for OIDC-created
users (email/name/avatar/team sync, disabled user refused). The proxy test
reuses the same mock instead of its inline copy.
Every login matched through emailfallback or usernamefallback now warns that both options will be removed and the user has to link the provider from their account settings.
Review finding: CreateTaskRelationsForImport relied on an unenforced
invariant that every related task came from the same import. It now takes
the imported batch, builds the relations itself and rejects related tasks
outside the batch.
The fields projection argument was stripped from every tool's arguments,
including write tools like tasks_bulk_update where fields is part of the
request body, so bulk updates always failed with ErrBulkTaskFieldsRequired.
Fixes#4235
Planka instances on a private network were rejected by the SSRF guard with
a generic "could not reach" error. Return a dedicated error pointing at
outgoingrequests.allownonroutableips instead.
Refs #4234
Address review decision: the post-commit avatar sync still blocked the
LDAP/OIDC login response for the download and up to 30s of decode
queueing. It now runs in a goroutine on a context that outlives the
request, with panics recovered and failures logged.
Address pr-swarm findings: avatar GETs queued for decode capacity on
context.Background(), so an abandoned request still waited 30s. The
request context now reaches the providers; gravatar's shared fetch keeps
running for other waiters when one disconnects. Busy shedding is logged
as a warning instead of an error.
Address pr-swarm finding: the flush ran before commit while the old blob
stays readable until then, so a queued avatar GET could re-cache the old
image with no expiry. The flush now runs on commit and the cache key
carries the file id.
Address pr-swarm finding: users start on defaultsettings.avatar_file_id,
so the first avatar upload or provider sync deleted that shared file for
everyone. Replacing now skips it, through the same check account
deletion uses.
Address review decision: SaveAvatar removed the old file's blob from
storage inside the transaction, so a later rollback left the user on an
avatar whose content was gone. The files row is still deleted in the
session; the blob and its previews go once the session commits.
Address review decision: the provider avatar was decoded inside the login
transaction after the user row was written, holding it while queued for
decode capacity, and a later rollback (TOTP, disabled user) discarded the
work. Logins now commit first; the avatar is decoded without a session
and saved in its own short transaction.
Address review decision: a background upload queued for decode capacity
held its transaction for up to 30s. The permission check now runs in a
short read session, the image is decoded and encoded without a session,
and a fresh write session re-checks permission and stores the result.
Address review decision: previews (4037) and other decodes (4040) had two
busy errors for one condition. ErrDecodeBusy now carries 4037 and the
preview-only error is gone.
Address review decision: a decode queued for capacity held the request's
transaction for up to 30s, so on SQLite a concurrent write made the
upload fail with database is locked. Uploads and avatar reads now decode
and encode first; only the encoded PNG enters the transaction.
Address review decision: uploads skipped the square crop synced avatars
got, so non-square API uploads were stored as-is although avatars render
square. Non-square uploads are now center-cropped.
Address pr-swarm finding: both logins copied crop, store and flush, had
diverged, decoded every avatar twice, and imaging.Fill cloned images
thinner than 100 px at full resolution outside the decode budget.