Replace the github.com/spf13/afero dependency with a purpose-built
FileStorage interface (Open, Write, Stat, Remove, MkdirAll) with three
implementations: localStorage (with basePath), s3Storage (with key
prefix), and memStorage (for tests).
Each implementation owns its base path — callers pass only file IDs.
Delete s3fs.go, change File.File from afero.File to io.ReadCloser,
and fix duplication flows to buffer content for seeking.
http.ServeContent requires io.ReadSeeker which S3 files don't support.
Add S3 branch using io.Copy with explicit headers, matching the pattern
already used in task attachment downloads.
Refs: #2347
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the third-party afero-s3 library (and its temporary fork) with
a minimal in-tree afero.Fs implementation (~200 lines) that only supports
the three S3 operations Vikunja actually uses: Open (GetObject), Remove
(DeleteObject), and Stat (HeadObject).
The s3File implementation lazily opens a GetObject stream on first Read
and supports Seek by closing and re-opening the stream from the new offset,
matching the behavior of the fixed afero-s3 fork.
All other afero.Fs/File methods return ErrS3NotSupported since they are
never called in the S3 code path (writes already use direct PutObject).
This removes the fclairamb/afero-s3 dependency and the temporary replace
directive in go.mod entirely.
Closes#2347
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
File.Delete() had s.Commit() and s.Rollback() calls that could
prematurely commit or abort an outer transaction when using a shared
session. The caller is now responsible for transaction management.
Refactor functions that created their own sessions when called from
within existing transactions, which caused "database table is locked"
errors in SQLite's shared-cache mode.
Changes:
- Add files.CreateWithSession() to reuse caller's session
- Refactor DeleteBackgroundFileIfExists() to accept session parameter
- Add variadic session parameter to notifications.Notify() and
Notifiable.ShouldNotify() interface
- Update all Notify callers (~17 sites) to pass their session through
- Use files.CreateWithSession in SaveBackgroundFile and NewAttachment
- Fix test code to commit sessions before assertions
Add a CLI command that finds all files in the database with no MIME type
set, detects it from the stored file content, and updates the database.
This is useful for backfilling MIME types on files created before MIME
detection was added on upload.
Use mimetype.DetectReader in files.Create to automatically detect and
store the MIME type from file content. This fixes task attachment
previews, S3 Content-Type headers, and UI display for newly uploaded
files.
Adds `files.s3.disablesigning` config option that sends
`UNSIGNED-PAYLOAD` instead of computing SHA256 hashes for S3 request
signing which fixes `XAmzContentSHA256Mismatch` errors with
S3-compatible providers like Ceph RadosGW and Clever Cloud Cellar
Resolves https://github.com/go-vikunja/vikunja/issues/2181
Use a temp file instead of io.ReadAll to avoid buffering the entire
Unsplash image in RAM, which could cause OOM with large images or
high maxsize configuration.
Move the seek-to-start into the local file branch only and simplify
contentLengthFromReadSeeker to seek to end then back to 0 instead of
saving/restoring the original position. This reduces the S3 upload
path from 5 seek operations to 2.
- Replace custom testfile structs with bytes.NewReader
- Remove readerOnly wrapper and non-seekable reader tests (no longer
possible at the type level)
- Update S3 unit tests to remove temp file assertions
The S3 upload path used temp files (vikunja-s3-upload-*) to buffer
non-seekable readers. In Docker containers with restrictive permissions,
these temp files could not be created, causing "permission denied"
errors for avatar and background image uploads.
By changing the file storage API (Create, CreateWithMime,
CreateWithMimeAndSession, Save) to require io.ReadSeeker instead of
io.Reader, the temp file fallback is no longer needed and is removed.
This enforces at the type level that all callers provide seekable
readers, preventing this class of bug from recurring.
Closesgo-vikunja/vikunja#2185
This PR adds support for detecting and handling Linux user namespaces (commonly used in rootless Docker containers) and improves error diagnostics when file storage validation fails.
Docs PR: https://github.com/go-vikunja/website/pull/289
---------
Co-authored-by: Claude <noreply@anthropic.com>
Adds startup validation that checks if the configured file storage is writable. To do this, Vikunja now tries to create a temporary file and clean it up afterwards.
Fix lint
Fix lint
Fix loading tasks with search
Fix loading lists
Fix loading task
Fix loading lists and namespaces
Fix tests
Fix user commands
Fix upload
Fix migration handlers
Fix all manual root handlers
Fix session in avatar
Fix session in list duplication & routes
Use sessions in migration code
Make sure the openid stuff uses a session
Add alias for db type in db package
Use sessions for file
Use a session for everything in users
Use a session for everything in users
Make sure to use a session everywhere in models
Create new session from db
Add session handling for user list
Add session handling for unsplash
Add session handling for teams and related
Add session handling for tasks and related entities
Add session handling for task reminders
Add session handling for task relations
Add session handling for task comments
Add session handling for task collections
Add session handling for task attachments
Add session handling for task assignees
Add session handling for saved filters
Add session handling for namespace and related types
Add session handling for namespace and related types
Add session handling for list users
Add session handling for list tests
Add session handling to list teams and related entities
Add session handling for link shares and related entities
Add session handling for labels and related entities
Add session handling for kanban and related entities
Add session handling for bulk task and related entities
Add session handling for lists and related entities
Add session configuration for web handler
Update web handler
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/api/pulls/750
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>