feat: support time_zone for user registration context

This commit is contained in:
Ilia Denisov
2026-04-09 09:00:06 +02:00
parent e6b73a8f55
commit 7043af4cb3
40 changed files with 3452 additions and 164 deletions
+61 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"strings"
"galaxy/authsession/internal/domain/common"
"galaxy/authsession/internal/domain/userresolution"
@@ -23,7 +24,7 @@ type UserDirectory interface {
// EnsureUserByEmail returns an existing user for email, creates a new user
// when registration is allowed, or reports a blocked outcome when the
// address may not continue through confirm flow.
EnsureUserByEmail(ctx context.Context, email common.Email) (EnsureUserResult, error)
EnsureUserByEmail(ctx context.Context, input EnsureUserInput) (EnsureUserResult, error)
// BlockByUserID applies a block state to the user identified by
// input.UserID. Implementations must wrap ErrNotFound when input.UserID does
@@ -35,6 +36,65 @@ type UserDirectory interface {
BlockByEmail(ctx context.Context, input BlockUserByEmailInput) (BlockUserResult, error)
}
// EnsureUserInput describes one user-directory ensure request keyed by the
// normalized e-mail address.
type EnsureUserInput struct {
// Email identifies the normalized e-mail address that should resolve to an
// existing user, a newly created user, or a blocked outcome.
Email common.Email
// RegistrationContext carries create-only user initialization fields. The
// user directory must ignore this context for existing users.
RegistrationContext *RegistrationContext
}
// Validate reports whether EnsureUserInput contains a complete request.
func (i EnsureUserInput) Validate() error {
if err := i.Email.Validate(); err != nil {
return fmt.Errorf("ensure user input email: %w", err)
}
if i.RegistrationContext != nil {
if err := i.RegistrationContext.Validate(); err != nil {
return fmt.Errorf("ensure user input registration context: %w", err)
}
}
return nil
}
// RegistrationContext describes create-only user initialization fields
// forwarded from the public confirm-email-code flow.
type RegistrationContext struct {
// PreferredLanguage stores the BCP 47 language tag that should initialize a
// newly created user. During the current rollout phase Auth / Session
// Service sends a temporary `"en"` default until gateway geoip derivation is
// deployed.
PreferredLanguage string
// TimeZone stores the client-selected IANA time zone name that should
// initialize a newly created user.
TimeZone string
}
// Validate reports whether RegistrationContext contains complete create-only
// initialization metadata.
func (c RegistrationContext) Validate() error {
if strings.TrimSpace(c.PreferredLanguage) == "" {
return errors.New("preferred language must not be empty")
}
if strings.TrimSpace(c.PreferredLanguage) != c.PreferredLanguage {
return errors.New("preferred language must not contain surrounding whitespace")
}
if strings.TrimSpace(c.TimeZone) == "" {
return errors.New("time zone must not be empty")
}
if strings.TrimSpace(c.TimeZone) != c.TimeZone {
return errors.New("time zone must not contain surrounding whitespace")
}
return nil
}
// EnsureUserOutcome identifies the coarse outcome of ensuring a user record
// for one normalized e-mail address.
type EnsureUserOutcome string