Commit Graph

1968 Commits

Author SHA1 Message Date
kolaente 37fdd088d6 feat(config): add webhooks.allownonroutableips setting 2026-03-19 15:18:06 +01:00
kolaente 3bc0093686 fix: invalidate all sessions when enabling TOTP
When a user enables two factor authentication, all existing sessions are
now invalidated, requiring re-authentication. This prevents pre-existing
sessions from bypassing 2FA. The frontend now shows a notice explaining
the logout before the user confirms, and properly logs out after enabling.

Ref: GHSA-pgc7-cmvg-mvp4
2026-03-19 12:27:44 +01:00
Frederick [Bot] 369b456d64 [skip ci] Updated swagger docs 2026-03-19 09:26:05 +00:00
Tink d11f097eee
fix(tasks): support both expand and expand[] query parameter formats (#2415)
The `expand` query parameter only supported the `expand[]=foo` array
format, but the swagger docs described it as a plain string parameter.
This adds support for both formats (`expand=foo` and `expand[]=foo`),
matching the existing pattern used by `sort_by` and `order_by`
parameters.

Closes #2408

---------

Co-authored-by: kolaente <k@knt.li>
2026-03-19 09:18:11 +00:00
Tink ada2ebab9e
fix: preserve CalDAV inverse relations when parent has no RELATED-TO (#2389)
- Fixes `removeStaleRelations` in CalDAV storage provider to only remove
relations of kinds explicitly declared in the incoming VTODO's
`RELATED-TO` properties
- When a VTODO has no `RELATED-TO` at all (e.g., a parent task from
Tasks.org), no relations are removed — they were auto-created as
inverses by child tasks
- When a VTODO declares specific relation kinds (e.g.,
`RELATED-TO;RELTYPE=PARENT`), only relations of that kind are checked
for staleness; other kinds (like auto-created `subtask` inverses) are
preserved

Fixes #2383

---------

Co-authored-by: kolaente <k@knt.li>
2026-03-11 09:40:09 +01:00
kolaente e19bea8e3a fix: register bulk label route correctly for API token permissions
The tasks_labels_bulk route was not recognized as a CRUD route by
isStandardCRUDRoute, causing it to be processed as a non-CRUD route
and registered in the wrong apiTokenRoutes group. API tokens with
tasks_labels permissions could not access the bulk endpoint, resulting
in a 401 error.

Fixes https://github.com/go-vikunja/vikunja/issues/2375
2026-03-10 23:58:44 +01:00
kolaente 554593cdb6 test: add failing test for bulk label API token route registration 2026-03-10 23:58:44 +01:00
kolaente 675dfb3ea4 test: add web tests for bulk label task endpoint 2026-03-10 23:58:44 +01:00
kolaente 79a612aa5d fix: send account deletion notification before deleting user row
When deleting a user via CLI (`vikunja user delete <id> -n`), the user
row was deleted first, then `notifications.Notify` was called. But
`Notify` calls `User.ShouldNotify()` which queries the database to check
the user's status — and since the row was already deleted within the same
transaction, it returned `ErrUserDoesNotExist`.

Move the notification call before the `DELETE` so the user row still
exists when `ShouldNotify` checks it.

Closes go-vikunja/vikunja#2335
2026-03-10 23:44:53 +01:00
Frederick [Bot] 30fccfb058 chore(i18n): update translations via Crowdin 2026-03-10 01:08:39 +00:00
kolaente a043940e14 refactor: use config.ResolvePath for all rootpath-relative paths
Replaces ad-hoc path joining in files, config value loading, and
default config values with the centralized ResolvePath function.
2026-03-09 16:02:05 +01:00
kolaente 2a7165aaba refactor: add centralized ResolvePath for rootpath-relative paths 2026-03-09 16:02:05 +01:00
kolaente d3cbc4fc4f fix: prefer working directory for service.rootpath default
When running as a systemd service, the binary is often in /usr/local/bin
but WorkingDirectory points to a data directory like /var/lib/vikunja.
Previously, rootpath defaulted to the binary's directory, causing
Vikunja to attempt creating files/db in /usr/local/bin.

Now os.Getwd() is preferred, which respects systemd's WorkingDirectory
and is the intuitive default for all deployment scenarios.
2026-03-09 16:02:05 +01:00
Frederick [Bot] d5f52868c5 chore(i18n): update translations via Crowdin 2026-03-09 01:14:37 +00:00
Frederick [Bot] 74771ed132 [skip ci] Updated swagger docs 2026-03-08 18:53:26 +00:00
kolaente 05cc65fe9e test: add e2e tests for user-level webhooks
Add comprehensive e2e tests for user-level webhook CRUD operations
and update existing project webhook tests to use LoadFixtures() for
cleanup instead of manual DELETE queries.
2026-03-08 19:45:53 +01:00
kolaente 47a0775c73 feat: add API routes for user-level webhooks
Add CRUD endpoints for user-level webhooks under /user/settings/webhooks.
Users can create webhooks that fire on user-directed events (task.reminder.fired,
task.overdue, tasks.overdue). Includes proper permission checks via
canDoWebhook which loads webhook ownership from DB.
2026-03-08 19:45:53 +01:00
kolaente dbbc80aea6 feat: extend WebhookListener for user-level webhooks
Add User field to reminder and overdue events so the webhook listener
can look up user-level webhooks. Add conditional user filtering to
reminder and overdue cron jobs - when only email is enabled, filter to
email-enabled users; when webhooks are enabled, fetch all users so
events can be dispatched. Dispatch TasksOverdueEvent and
TaskReminderFiredEvent for webhook consumption.
2026-03-08 19:45:53 +01:00
kolaente d4577c660f feat: add user_id to webhooks and user-directed event infrastructure
Add user_id column to webhooks table (nullable, for user-level webhooks
vs project-level). Extend webhook model, permissions, and listener to
support user-level webhooks that fire for user-directed events like
task reminders and overdue task notifications.

Add TasksOverdueEvent for dispatching overdue notifications via webhooks.
Update webhook permissions to handle both user-level and project-level
ownership. Add webhook test fixture and register webhooks table in test
fixture loader.
2026-03-08 19:45:53 +01:00
kolaente aacf650ec2 test: add tests for conversational email system
Add tests for conversational header generation, HTML rendering
with p-tag wrapping, plain-text conversion, footer handling,
and conditional action links. Update mention test fixtures
with Project field.
2026-03-08 16:03:47 +01:00
kolaente def73e2f8e feat: add translation keys for conversational emails
Add action strings with doer names for comments, mentions,
assignments, and reminders. Add notification settings footer
and task identifier format strings.
2026-03-08 16:03:47 +01:00
kolaente b3572c5932 feat: convert notifications to conversational email style
Convert task comment, mention, assignment, and reminder notifications
to use the conversational email format. Add Project field to notification
structs, include task identifiers in subjects and headers, add doer
avatars, notification settings links in footers, and From headers.
2026-03-08 16:03:47 +01:00
kolaente d4b03026f0 feat: add conversational email template and rendering
Add conversational email style with GitHub-inspired header design.
Includes mail struct extensions (headerLine, conversational flag),
CreateConversationalHeader helper, HTML template with avatar support,
p-tag wrapping for content lines, plain-text stripping, and
conditional action link rendering.
2026-03-08 16:03:47 +01:00
Casper Børgesen b5afe82713
fix(cli): make user deletion confirmation check Windows compatible (#2339)
The current implementation of the user confirmation when deleting a user
using the CLI seems to favour Linux. On Windows the <ENTER> command adds
"\r\n" to the user input while Linux only adds "\n".

I have added an extra check to the confirmation, but GO is a new
language for me, so there is probably a much better way to do this.

---------

Co-authored-by: kolaente <k@knt.li>
2026-03-05 15:19:08 +01:00
kolaente d36ac9ddda test: fix ParadeDB project search count to 27
The recursive CTE pulls in child projects of matched parents,
resulting in 27 total results, not 12.
2026-03-05 13:57:05 +01:00
kolaente df0e3a84a9 test: fix non-ParadeDB project search count assertion
ILIKE '%Test1%' matches Test1, Test10, Test11, Test19 + favorites = 5,
not 2. Also use 'Test2"' pattern to avoid matching Test20/Test21.
2026-03-05 13:57:05 +01:00
kolaente c7c63e8ead test: add result count assertions for ParadeDB search tests
Address review feedback: assert exact result counts when ParadeDB is
active. fuzzy(1, prefix=true) broadens matches via edit distance,
returning 6 projects for "TEST10", 14 tasks for "number #17", and
12 projects for "Test1".
2026-03-05 13:57:05 +01:00
kolaente b69705e64b test: fix lint and adjust project search test for ParadeDB fuzzy matching
- Use require.NotEmpty instead of require.Greater for testifylint
- Skip exclusion assertions in web project search test when ParadeDB is
  active, since fuzzy(1, prefix=true) on "Test1" also matches Test2, Test3
2026-03-05 13:57:05 +01:00
kolaente 6268c48f15 test: adjust ParadeDB search tests for fuzzy prefix match broadening
ParadeDB fuzzy(1, prefix=true) returns more results than ILIKE due to
edit-distance tolerance on tokenized terms. Adjust assertions to check
containment rather than exact result sets when ParadeDB is active.
2026-03-05 13:57:05 +01:00
kolaente 3568aaacee test: add task #48 to expected results in feature tests
The new fixture task #48 (Landingpages update, project 1) needs to
appear in all feature test expected result sets that list project 1
tasks. Also bumps the expected next index in TestTask_Create.
2026-03-05 13:57:05 +01:00
kolaente e6cbd67ab5 test: call real MultiFieldSearch function and branch on db engine
Instead of manually constructing builder.Expr conditions to simulate
the ParadeDB path, call MultiFieldSearchWithTableAlias() directly and
use isParadeDB() to branch assertions. When ParadeDB is available,
assert the ||| operator with ::pdb.fuzzy(1, t) syntax; otherwise
assert the LIKE/ILIKE fallback. Tests skip when no database engine
is initialized (x == nil).
2026-03-05 13:57:05 +01:00
kolaente 0a38ec0838 fix: use ParadeDB v2 fuzzy prefix matching for search (#2346)
Switch from legacy @@@ paradedb.match() to v2 ||| operator with
::pdb.fuzzy(1, t) cast. This enables prefix matching so 'landing'
matches 'landingpages', and adds single-character typo tolerance.
2026-03-05 13:57:05 +01:00
kolaente ee2723d9cf test: rewrite MultiFieldSearch tests with SQL output verification 2026-03-05 13:57:05 +01:00
kolaente 892b38b3b6 test: add web tests for prefix/substring search (#2346) 2026-03-05 13:57:05 +01:00
kolaente 275f714224 test: add fixture task with compound word for prefix search testing 2026-03-05 13:57:05 +01:00
kolaente 1f3509bf27 test: add e2e API test package with webhook pipeline verification
New pkg/e2etests/ package runs with the real Watermill event system to
verify the full async pipeline: web handler -> DB -> event dispatch ->
Watermill -> listener -> side effect.

First test (TestTaskUpdateWebhookE2E) updates a task and asserts that
a webhook HTTP POST arrives at a test server.
2026-03-05 12:49:27 +01:00
kolaente 1b1e8e5b19 feat: add InitEventsForTesting and Unfake for real event dispatch in tests
InitEventsForTesting sets up a real Watermill GoChannel router with a
cancellable context, returning a readiness channel. Skips Prometheus
metrics and poison queue to avoid duplicate registration panics.

Unfake re-enables real event dispatch after test init helpers call Fake().

Also guards Dispatch against nil pubsub with a clear error message.
2026-03-05 12:49:27 +01:00
kolaente f9cb0a2de1 fix: include remote IP address in HTTP request logs 2026-03-04 23:47:40 +01:00
kolaente 7288483879 fix: handle deleted user in saved filter view event listener
Use a separate error variable for the user lookup in
UpdateTaskInSavedFilterViews so that ErrUserDoesNotExist does not
pollute the named return `err`. The `:=` inside the for loop shadowed
the outer `err`, leaving it set to the stale user-not-found error,
which caused the handler to be poisoned.

Closes #2359
2026-03-04 22:05:01 +01:00
Frederick [Bot] ff70fa1369 [skip ci] Updated swagger docs 2026-03-04 19:40:40 +00:00
kolaente b5086febc7 docs: update user search endpoint description for external team bypass 2026-03-04 20:32:11 +01:00
kolaente 54c7c4aef2 refactor: move ListUsers tests from pkg/user to pkg/models
The ListUsers function now references team_members and teams tables
via a subquery for external team discoverability. The pkg/user test
environment only syncs user tables, so these tests need to run in
pkg/models which has the full schema and all fixtures.

Also adds new tests for the external team discoverability bypass
directly in the models package alongside the moved tests.
2026-03-04 20:32:11 +01:00
kolaente 06617891fa test: verify email masking for external team name search 2026-03-04 20:32:11 +01:00
kolaente 28b913f29f feat: bypass discoverability settings for external team members 2026-03-04 20:32:11 +01:00
kolaente 3a730165bc test: add tests for external team user discoverability bypass 2026-03-04 20:32:11 +01:00
kolaente 64e455a613 test: add user 11 to external team 14 for discoverability tests 2026-03-04 20:32:11 +01:00
Weijie Zhao 54d977532e
fix: allow browser caching for file downloads (#2349) 2026-03-04 17:43:03 +01:00
Frederick [Bot] 740ec183d9 [skip ci] Updated swagger docs 2026-03-04 16:29:06 +00:00
kolaente 9c23e19644 fix: preserve cover image when duplicating task
Track old-to-new attachment ID mapping during duplication and
re-set CoverImageAttachmentID on the new task if the original
had a cover image configured.
2026-03-04 17:20:26 +01:00
kolaente 7aad96b199 fix: close source file handle when duplicating attachments
Save the source file handle before calling NewAttachment (which
overwrites attachment.File) and use defer to ensure it gets closed.
This prevents file descriptor leaks on both success and error paths.
2026-03-04 17:20:26 +01:00