Commit Graph

19 Commits

Author SHA1 Message Date
Jakub Zych
f4969591e2 fix: read privileged membership and the admin actions through a clean statement (T-12.1-38, T-12.1-39)
classes.fresh chained WithContext onto a lazy NewDB session, which clones the
caller's statement with its conditions. A handle that carried a condition
made IsPrivilegedMember answer false for a member of a privileged group, so
the takeover guard would have let the request through. No caller passes such
a handle today: the admin hooks hand over the write's transaction handle.

- fresh builds the empty statement before anything is chained onto it
- IsPrivilegedMember and PrivilegedGroupIDs read through fresh
2026-10-05 14:53:41 +02:00
Jakub Zych
c7d9d7d25d feat: stamp users.last_seen on login and token refresh
One conditional UPDATE writes it at most once per five minutes per
user. A failed write is logged and never fails authentication, and no
user payload carries the column.
2026-10-05 13:26:53 +02:00
Jakub Zych
cdea47a178 feat: frontend permissions and the merged-permission resolver
- PermissionSet reads the stored JSON tolerantly and writes an object
  of integers; FrontendPermission is the catalogue row
- MergedPermissions, HasPermission and UserHasPermission port PHP
  getMergedPermissions and Winter's hasPermission: groups merge with
  most positive wins, the user's own values override, held means
  exactly 1, wildcards as in Winter
- User gains Permissions (never serialized) and declares the avatar
  attachment relation the user API already writes
2026-10-05 13:21:51 +02:00
Jakub Zych
970eba7734 feat: user preview, bulk and record actions and the permanent delete
- the list opens the preview, which shows one status hint (banned,
  deactivated, not activated, suspended) and the IP address fields
- bulk actions activate, deactivate, restore, ban and unban; record
  actions activate, unban and unsuspend, offered while they apply
- delete (form button and bulk) removes the user for good with the
  throttle rows, group memberships and attachments in one transaction;
  blobs go after the commit
- a privileged-group member is still refused, a bulk delete as a whole
2026-10-05 13:10:12 +02:00
Jakub Zych
b410a7fea9 feat: register the Users admin screen with the privileged-member guard
- permissions (the four Winter codes and manage_privileged_groups),
  the user navigation item and the embedded admin YAML
- Users controller: list with deactivated users, row states, the
  groups, created date and activated filters, and the form's name,
  surname and email
- a member of a group in golem15.user.privileged_groups (default
  admin) keeps their email, password and row unless the administrator
  holds golem15.users.manage_privileged_groups; the refusal is a 403
  that saves nothing
2026-10-05 13:01:48 +02:00
Jakub Zych
0fe5b91b63 feat: own shared user API tokens 2026-10-04 22:30:20 +02:00
Jakub Zych
d80d7990f6 feat: carry the register input on RegisterEvent and export the registration steps
- RegisterEvent.Payload: a copy of the register input without password and
  password_confirmation (Winter's golem15.user.register data array)
- RegisterUser, RegisterOptions, FireRegisterEvent, IssueToken and APIArray:
  the steps POST /register runs, now called by Register itself; its status
  codes and bodies are unchanged
- README documents the exports and Payload
2026-10-03 07:12:00 +02:00
Jakub Zych
c258e9fade test: cover user group codes and the small class helpers
- UserGroupCodes and HasGroupCode against Postgres: id order, code-less
  groups skipped, membership by code, a missing handle and a failing query
  reported as errors
- mail locale resolution, hook registration (a failing hook stops the
  chain), the code lifetimes and throttle settings carried on the context,
  constant-time code comparison, JWT secret loading and the principal
  lookup without an app or a gorm handle
2026-10-02 16:19:06 +02:00
Jakub Zych
86970074b7 feat: add Winter user groups
- user_groups (seeded with the guest and registered groups) and the
  users_groups pivot, folded from the PHP v1.1.1 and v2.8.0 migrations
  into migration 202610020001_create_user_groups
- models.UserGroup and a User.Groups relation that is never serialized
- classes.UserGroupCodes and classes.HasGroupCode for server-side checks
  such as the site-admin group code admin
- additive only: no route, payload or existing column changes; the user
  payload still answers "groups":[]
2026-10-02 11:44:01 +02:00
Jakub Zych
02ba1f0666 refactor: rename module to git.golem15.com/golem15/sm-user-plugin
Prefix replacement of the old application-nested module path in go.mod
and every import. No identifier, string, table, migration ID, config key
or comment changes.
2026-10-02 10:56:06 +02:00
Jakub Zych
af976e789f refactor(10.2-01): use nested framework modules
- Rewrite application and plugin framework imports
2026-09-28 02:21:38 +02:00
Jakub Zych
96bf78845d refactor(10.2-01): use nested festival module
- Point user event test at modules/festival
2026-09-28 02:16:45 +02:00
Jakub Zych
d4066a8c3f test(07-07): cover already-activated activate and 22-ported corpus counts
Unit tests now expect Winter 500 HTML when the target user is already
active, and the inventory assertions match 169/22/147.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 23:57:10 +02:00
Jakub Zych
d94634d5d8 feat(07-07): replay the 15 user-api routes and both nuxt auth flows
Match PHP payloads, already-activated Winter 500 HTML, and direct-DB
seeding so the corpus can flip those routes to ported without onboarding.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 23:57:00 +02:00
Jakub Zych
cb50d673c6 feat(07-03): add password reset and account activation
Reset and activation codes expire on a TTL, and a missing issued-at still accepts a cutover code. Forgot-password always returns the same 200 body.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 16:30:22 +02:00
Jakub Zych
97a39dc34c feat(07-02): register accounts and extend the user payload
Registration follows activate_mode and hides a disabled or throttled cause in production. Fonoteka adds organisation fields through GetApiArrayEvent.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 15:11:14 +02:00
Jakub Zych
6bceb8167c feat(07-02): serve login, logout, fetch, and refresh
Wire the user API session loop to the JWT blacklist and a pre-password throttle gate so a logged-out token cannot be fetched again.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 14:40:18 +02:00
Jakub Zych
00e6c51abd feat(07-02): throttle failed logins and pick mail template locale
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 14:03:31 +02:00
Jakub Zych
2d4245681e feat(05-01): restructure fonoteka plugins into Winter directories
- Move models, classes, controllers, middleware, and updates into subpackages
- Add self-registering models/updates/classes registries so later plans add files
- Keep the genres route and shipped migration SQL unchanged
2026-09-18 18:43:31 +02:00