feat: add Role (owner|admin) to the user domain, persistence model and mapper

This commit is contained in:
fsylvain committed 2026-09-30 00:58:58 +02:00
1 parent 162fea4afb
commit 461e93e3b5
30 files changed
+791 -48

No files matched your search

+13 -7
View File
@@ -6,9 +6,13 @@ Feature: A verified user can invite another person by email, and the users list
registration stays closed to everyone who was not invited
Background:
Given the workspace is shared: there are no roles, no ownership and no way to remove a user
Given the workspace is shared: every verified user sees the same articles and the same list,
roles are owner and admin (features/user_roles.feature), and there is no way to remove a user
And POST /v1/user/invite and GET /v1/user/ are mounted in NewUserRouter, inside the group that
requires a valid jwt cookie, a current token_version and a verified user
And POST /v1/user/invite additionally requires the owner role (403
apperr.OwnerRequiredErrorMessage for an admin); GET /v1/user/ is open to every verified user
And wherever a scenario has verified user id 7 post an invite, user 7 is the owner
And an invite has an id, an email stored in lower case, a hashed code, an expires_at equal to
its creation time plus 3 days, an invited_by user id, a nullable accepted_at and a created_at
And the raw invite code is a uuid, hashed with the same hash.Hasher used for verification codes,
@@ -17,8 +21,8 @@ Feature: A verified user can invite another person by email, and the users list
expires_at is in the future, expired when accepted_at is empty and expires_at is in the past,
accepted when accepted_at is set
And the users list item shape is: id, kind ("user" or "invite"), status, created_at, plus
username and display_name for a user, plus email for an invite; a user is never listed with
an email, and neither the code, its hash, invited_by nor password fields ever appear
username, display_name, email and role for a user, plus email for an invite; neither the
code, its hash, invited_by nor password fields ever appear
And error responses are plain text from http.Error, success responses are JSON
And the invite email uses the template "invitation" with data Host (the configured PublicURL),
VerificationCode (the raw code), Email (the invited address) and InvitedBy (the inviter's
@@ -30,7 +34,7 @@ Feature: A verified user can invite another person by email, and the users list
/login and /password-reset
Scenario: A verified user invites a new address
Given a user repository containing verified user id 7, username "marta", display_name ""
Given a user repository containing verified user id 7, who is the owner, username "marta", display_name ""
And an empty invite repository
And a valid jwt cookie for user id 7
When the client sends POST /v1/user/invite with body {"email": "Sam.Oliveira@Renew.example"}
@@ -116,6 +120,7 @@ Feature: A verified user can invite another person by email, and the users list
| with no jwt cookie | POST | /v1/user/invite | 401 |
| with a jwt cookie of an unverified user | POST | /v1/user/invite | 403 |
| with a jwt cookie whose token_version is stale | POST | /v1/user/invite | 401 |
| with a jwt cookie of a verified admin | POST | /v1/user/invite | 403 |
| with no jwt cookie | GET | /v1/user/ | 401 |
| with a jwt cookie of an unverified user | GET | /v1/user/ | 403 |
@@ -142,9 +147,10 @@ Feature: A verified user can invite another person by email, and the users list
And the accepted invite is not listed
And the invite items have exactly the keys id, kind, email, status, created_at, with kind
"invite" and status "pending" or "expired"
And the user items have exactly the keys id, kind, username, display_name, status, created_at,
with kind "user" and status "accepted"
And no user item has an email key, and no item has a key named password, password_reset_code,
And the user items have exactly the keys id, kind, username, display_name, email, role, status,
created_at, with kind "user" and status "accepted"
And each user item has its own email and a role
And no item has a key named password, password_reset_code,
verification_code, verification_expiration, password_reset_expiration, token_version,
code, hashed_code, invited_by or accepted_at