Commit Graph

2266 Commits

Author SHA1 Message Date
kolaente
2fc6f033f2 refactor(handler): return domain error for forbidden instead of echo.HTTPError
Keeps the Do* helpers framework-neutral so non-Echo callers (upcoming
Huma /v2 handlers) don't need a translation shim.

Addresses review feedback on #2670.
2026-04-21 09:23:13 +00:00
kolaente
939381fb12 refactor(handler): extract DoDelete from DeleteWeb 2026-04-21 09:23:13 +00:00
kolaente
1f4471c38f refactor(handler): extract DoUpdate from UpdateWeb 2026-04-21 09:23:13 +00:00
kolaente
0e800b4936 refactor(handler): extract DoReadAll from ReadAllWeb 2026-04-21 09:23:13 +00:00
kolaente
9ec5c2672f refactor(handler): extract DoReadOne from ReadOneWeb 2026-04-21 09:23:13 +00:00
kolaente
11c9137080 refactor(handler): extract DoCreate from CreateWeb 2026-04-21 09:23:13 +00:00
Frederick [Bot]
5d3e34e870 [skip ci] Updated swagger docs 2026-04-20 19:16:29 +00:00
kolaente
af8beb5758 fix(user): skip last-admin guard when target is already unreachable
GuardLastAdmin counted only active, non-deletion-scheduled admins, but gated only on target.IsAdmin. Demoting or deleting an already-disabled or deletion-scheduled admin would then be blocked whenever exactly one active admin remained, even though removing a user who isn't in the reachable set can't reduce the count. Return early when the target isn't part of the counted set.
2026-04-20 18:55:06 +00:00
kolaente
73a0f691ec fix(license): degrade to free when servers unreachable or key rejected
On startup, if the license server was unreachable with no usable cached status, or the server rejected the key, we only logged a warning without clearing persisted license.state. On Redis/keyvalue deployments a previous run's Licensed=true could remain active even though pro features were advertised as unavailable. Route both paths through degradeToFree so the persisted state is cleared.
2026-04-20 18:55:06 +00:00
kolaente
c8893f4533 fix(cli): guard last admin on scheduled CLI deletion path
The last-admin guard was only enforced in the --now branch of 'user delete'. The default scheduled path called user.RequestDeletion without the guard, letting an operator schedule deletion of the last reachable admin via the CLI; the cron flow would then confirm and execute it, violating the invariant the HTTP admin API already enforces.
2026-04-20 18:55:06 +00:00
kolaente
d64ca0c777 fix(admin): reload created user before returning in admin create handler
The admin create-user handler returned the in-memory newUser struct directly. On mail-enabled instances with skip_email_confirm=false, user.CreateUser persists the account as email-confirmation-required, but the returned struct still reflects the pre-persist status, so the admin API reported a misleading active status immediately after creation.
2026-04-20 18:55:06 +00:00
kolaente
f90ebbf0f4 refactor(license): return typed feature slice for JSON encoding 2026-04-20 18:55:06 +00:00
kolaente
d5f4928034 feat(admin): wire up /admin route group with all endpoints 2026-04-20 18:55:06 +00:00
kolaente
9ad9a1e987 refactor(register): use models.RegisterUser helper 2026-04-20 18:55:06 +00:00
kolaente
d24b96b99c feat(user): extract last-admin guard and close invariant gaps 2026-04-20 18:55:06 +00:00
kolaente
23c82bd5fa feat(frontend): expose isAdmin on current user and add config feature check 2026-04-20 18:55:06 +00:00
kolaente
3498dfe7fb test(admin): add webtests for /admin/* endpoints and share bypass 2026-04-20 18:55:06 +00:00
kolaente
d32dcf3a78 feat(license): add runtime state snapshot and reload helpers 2026-04-20 18:55:06 +00:00
kolaente
803f625ed7 feat(admin): add create-user endpoint 2026-04-20 18:55:06 +00:00
kolaente
128c0abf59 feat(admin): add user status and delete endpoints with reassign owner 2026-04-20 18:55:06 +00:00
kolaente
4a7cb6a7bf feat(admin): add users/projects list endpoints and is_admin patch 2026-04-20 18:55:06 +00:00
kolaente
e7fcbff827 feat(admin): add /admin route group and overview endpoint 2026-04-20 18:55:06 +00:00
kolaente
ec1833dbeb feat(license): expose enabled_pro_features on /info 2026-04-20 18:55:06 +00:00
kolaente
d208629909 feat(middleware): add RequireFeature and RequireSiteAdmin 404 gates 2026-04-20 18:55:06 +00:00
kolaente
3b3bc4c775 feat(cli): add user set-admin command (license-gated) 2026-04-20 18:55:06 +00:00
kolaente
87a06d6cb9 feat(permissions): site admins bypass all Can* checks (license-gated) 2026-04-20 18:55:06 +00:00
kolaente
7c7e060d16 feat(auth): include is_admin in JWT claims 2026-04-20 18:55:06 +00:00
kolaente
deccc9d29b feat(user): add IsAdmin field to User struct 2026-04-20 18:55:06 +00:00
kolaente
736773ea77 feat(db): add is_admin column to users 2026-04-20 18:55:06 +00:00
MidoriKurage
3a5ba17ca0 fix(api/docs): Use Base in redoc template 2026-04-20 14:26:49 +00:00
MidoriKurage
fb0d0cb32c fix(auth): Cleanup getRefreshTokenCookiePath implementation 2026-04-20 14:26:49 +00:00
MidoriKurage
e8615efe8e fix(api/docs): Make redoc load docs.json from public URL 2026-04-20 14:26:49 +00:00
MidoriKurage
c027d7ef40 fix(auth): Make refresh token path respect to public URL 2026-04-20 14:26:49 +00:00
Frederick [Bot]
3120c2b12c chore(i18n): update translations via Crowdin 2026-04-16 01:46:56 +00:00
kolaente
35f183979c feat: add license comments for agents and humans 2026-04-15 10:32:37 +00:00
kolaente
a82bea567a feat(db): add license_status table migration
Add database migration for the license_status table that stores instance
ID, cached license validation response, and validation timestamps.
2026-04-15 10:32:37 +00:00
kolaente
7dd664fdc4 feat(init): integrate license validation into startup and shutdown
Call license.Init() after database initialization and before the web
server starts. Call license.Shutdown() during graceful shutdown to stop
the background check goroutine.
2026-04-15 10:32:37 +00:00
kolaente
ed2632ddb2 feat(license): add license key validation package
Implement the license validation system with:
- Server communication with retry logic and exponential backoff
- In-memory state management for feature flags and user limits
- Cached validation with 72h expiry stored in database
- Background goroutine with adaptive check intervals (24h/1h)
- Graceful degradation to community mode on failure
- Instance ID generation and persistence
2026-04-15 10:32:37 +00:00
kolaente
ecc2243513 feat(config): add license.key configuration option
Add license key configuration under the license section. When empty or
absent, Vikunja runs in community mode with no licensed features.
2026-04-15 10:32:37 +00:00
Frederick [Bot]
88528d927e [skip ci] Updated swagger docs 2026-04-13 16:21:02 +00:00
kolaente
85836076be feat(migration/wekan): import attachments from board export
Parse the top-level `attachments` array in WeKan board JSON exports,
group them by card ID, base64-decode the payload, and attach the
resulting files to the generated tasks so they land in Vikunja as
task attachments. Orphaned attachments (cardId with no matching card)
are silently skipped; decode errors are logged and skipped.
2026-04-13 16:04:14 +00:00
kolaente
1eafd31a2a refactor(projects): use getAllProjectsForUser in getProjectsToDelete (#2616) 2026-04-13 12:32:32 +02:00
Claude
85cfadc5b0 fix: fatal with clear message when keyvalue type is redis but redis is not enabled
Instead of panicking with a nil pointer dereference when keyvalue.type
is set to "redis" but redis.enabled is false, log a fatal error with a
clear, actionable message telling the user to enable redis.

Closes go-vikunja/vikunja#2608

https://claude.ai/code/session_01TRuPTGYDQjxqHRFWQaJGvy
2026-04-12 09:43:31 +00:00
Frederick [Bot]
bacee1597a chore(i18n): update translations via Crowdin 2026-04-12 01:43:16 +00:00
Frederick [Bot]
9a12c8f254 [skip ci] Updated swagger docs 2026-04-11 21:00:40 +00:00
kolaente
8578fe3468 feat(api): add GET /projects/:project/tasks/by-index/:index endpoint 2026-04-11 20:44:28 +00:00
kolaente
9206f98d64 feat(tasks): enforce unique (project_id, index) via migration 2026-04-11 20:44:28 +00:00
kolaente
8f9b50bdcb feat(tasks): add GetTaskByProjectAndIndex resolver 2026-04-11 20:44:28 +00:00
kolaente
ced7ebd97f fix(auth): tolerate string booleans in oidc provider config (#2599)
The four boolean OIDC provider fields (emailfallback, usernamefallback,
forceuserinfo, requireavailability) were parsed with a strict .(bool)
type assertion. That works for YAML/JSON config where leaves are native
bools, but fails for every other input path: env vars always arrive as
strings, and GetConfigValueFromFile (used by the *.file Docker secret
convention) also always returns strings. The assertion would silently
zero the field for emailfallback and usernamefallback, and log an error
and zero the field for forceuserinfo and requireavailability, which is
what #2599 reports.

Extract a small parseBoolField helper that accepts both native bools and
strings (via strconv.ParseBool) and logs a parse error from each call
site. This also fixes the previously-silent drop of stringified
emailfallback / usernamefallback values — those now log an error if the
input is garbage, matching the behaviour of the other two fields.

Fixes #2599
2026-04-11 19:10:26 +00:00
kolaente
3008dc09db test(auth): cover env-var string booleans for oidc providers (#2599)
Regression test for #2599. Exercises getProviderFromMap with native
bools and with stringified booleans ("true"/"false"/"1"/"0") for all
four boolean provider fields — emailfallback, usernamefallback,
forceuserinfo, requireavailability. From env vars and from the
GetConfigValueFromFile path every leaf arrives as a string, so the
current .(bool) assertion silently zeros these fields.
2026-04-11 19:10:26 +00:00