This commit is contained in:
2026-08-24 04:03:44 +02:00
parent 8a690a0464
commit 7bafd7a322
9 changed files with 391 additions and 53 deletions
+40
View File
@@ -74,6 +74,46 @@ func EmailsEqual(a, b string) bool {
return strings.EqualFold(strings.TrimSpace(a), strings.TrimSpace(b))
}
// Invite password modes for accept-invite UX (also drives AcceptInvite branching).
const (
InvitePasswordSet = "set" // new account — choose a password
InvitePasswordVerify = "verify" // existing account with active memberships — current password
InvitePasswordRecover = "recover" // existing account with no active memberships — set a new password
)
// InvitePasswordMode reports how accept-invite should treat the password field for email.
func (s *Service) InvitePasswordMode(ctx context.Context, email string) (string, error) {
email = strings.ToLower(strings.TrimSpace(email))
if email == "" {
return InvitePasswordSet, nil
}
var (
userID uuid.UUID
mustSet bool
)
err := s.Pool.QueryRow(ctx, `
SELECT id, must_set_password FROM users WHERE email = $1`, email).Scan(&userID, &mustSet)
if errors.Is(err, pgx.ErrNoRows) {
return InvitePasswordSet, nil
}
if err != nil {
return "", err
}
if mustSet {
return InvitePasswordSet, nil
}
var active int64
if err := s.Pool.QueryRow(ctx, `
SELECT count(*) FROM memberships
WHERE user_id = $1 AND status = 'active'`, userID).Scan(&active); err != nil {
return "", err
}
if active == 0 {
return InvitePasswordRecover, nil
}
return InvitePasswordVerify, nil
}
// ResolveInviteEmail returns the invitee email for a pending, unexpired invite token.
func (s *Service) ResolveInviteEmail(ctx context.Context, token string) (string, error) {
token = strings.TrimSpace(token)