feat(admin): search users by email + erase a bound email
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 14s
CI / ui (pull_request) Successful in 1m3s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m40s

Add an exact (strict) email filter to the /users list (UserFilter.EmailExact →
a kind='email' identity match) with a search input, and an 'Erase email' action on
the user card that deletes the bound email identity and its pending confirmations,
freeing the address. It refuses to remove the account's only identity
(ErrLastIdentity), which would leave it unreachable. Integration tests for both.
This commit is contained in:
Ilia Denisov
2026-07-03 05:30:30 +02:00
parent 1dca6741f1
commit 356bf1a5ba
7 changed files with 175 additions and 2 deletions
+7 -1
View File
@@ -28,11 +28,13 @@ type UserListItem struct {
// UserFilter narrows the admin user list: Robots selects robot accounts (otherwise the
// non-robot "people"); NameMask and ExternalIDMask are glob masks ('*' = any run, '?' =
// one char) matched case-insensitively against the display name / any identity's external
// id. An empty mask means no filter on that field.
// id; EmailExact is a strict (exact) match against an account's email identity. An empty
// value means no filter on that field.
type UserFilter struct {
Robots bool
NameMask string
ExternalIDMask string
EmailExact string
}
// robotExists is the correlated subquery testing whether account a is a robot.
@@ -63,6 +65,10 @@ func userListWhere(f UserFilter) (string, []any) {
args = append(args, ext)
where += fmt.Sprintf(` AND EXISTS (SELECT 1 FROM backend.identities i WHERE i.account_id = a.account_id AND i.external_id ILIKE $%d ESCAPE '\')`, len(args))
}
if email := strings.ToLower(strings.TrimSpace(f.EmailExact)); email != "" {
args = append(args, email)
where += fmt.Sprintf(` AND EXISTS (SELECT 1 FROM backend.identities i WHERE i.account_id = a.account_id AND i.kind = 'email' AND i.external_id = $%d)`, len(args))
}
return where, args
}