111 lines
3.0 KiB
Go
111 lines
3.0 KiB
Go
// Package userresolution defines the domain result returned by the user
|
|
// resolution boundary before session creation.
|
|
package userresolution
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"galaxy/authsession/internal/domain/common"
|
|
)
|
|
|
|
// Kind identifies the coarse user-resolution result for one normalized e-mail.
|
|
type Kind string
|
|
|
|
const (
|
|
// KindExisting reports that the e-mail belongs to an existing user.
|
|
KindExisting Kind = "existing"
|
|
|
|
// KindCreatable reports that the e-mail is free and user creation is
|
|
// allowed.
|
|
KindCreatable Kind = "creatable"
|
|
|
|
// KindBlocked reports that the e-mail or subject is blocked from login or
|
|
// registration.
|
|
KindBlocked Kind = "blocked"
|
|
)
|
|
|
|
// IsKnown reports whether Kind is one of the user-resolution kinds supported
|
|
// by the current domain model.
|
|
func (k Kind) IsKnown() bool {
|
|
switch k {
|
|
case KindExisting, KindCreatable, KindBlocked:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// BlockReasonCode stores one machine-readable user-block reason.
|
|
type BlockReasonCode string
|
|
|
|
// String returns BlockReasonCode as its stored code value.
|
|
func (code BlockReasonCode) String() string {
|
|
return string(code)
|
|
}
|
|
|
|
// IsZero reports whether BlockReasonCode is empty.
|
|
func (code BlockReasonCode) IsZero() bool {
|
|
return strings.TrimSpace(string(code)) == ""
|
|
}
|
|
|
|
// Validate reports whether BlockReasonCode is non-empty and normalized for
|
|
// domain use.
|
|
func (code BlockReasonCode) Validate() error {
|
|
switch {
|
|
case code.IsZero():
|
|
return errors.New("block reason code must not be empty")
|
|
case strings.TrimSpace(string(code)) != string(code):
|
|
return errors.New("block reason code must not contain surrounding whitespace")
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Result stores the coarse user-resolution outcome consumed by later auth
|
|
// workflow stages.
|
|
type Result struct {
|
|
// Kind reports the coarse resolution outcome.
|
|
Kind Kind
|
|
|
|
// UserID is set only when Kind is KindExisting.
|
|
UserID common.UserID
|
|
|
|
// BlockReasonCode is set only when Kind is KindBlocked.
|
|
BlockReasonCode BlockReasonCode
|
|
}
|
|
|
|
// Validate reports whether Result satisfies the Stage-2 structural invariants.
|
|
func (r Result) Validate() error {
|
|
if !r.Kind.IsKnown() {
|
|
return fmt.Errorf("user resolution kind %q is unsupported", r.Kind)
|
|
}
|
|
|
|
switch r.Kind {
|
|
case KindExisting:
|
|
if err := r.UserID.Validate(); err != nil {
|
|
return fmt.Errorf("user resolution user id: %w", err)
|
|
}
|
|
if !r.BlockReasonCode.IsZero() {
|
|
return errors.New("existing user resolution must not contain block reason code")
|
|
}
|
|
case KindCreatable:
|
|
if !r.UserID.IsZero() {
|
|
return errors.New("creatable user resolution must not contain user id")
|
|
}
|
|
if !r.BlockReasonCode.IsZero() {
|
|
return errors.New("creatable user resolution must not contain block reason code")
|
|
}
|
|
case KindBlocked:
|
|
if !r.UserID.IsZero() {
|
|
return errors.New("blocked user resolution must not contain user id")
|
|
}
|
|
if err := r.BlockReasonCode.Validate(); err != nil {
|
|
return fmt.Errorf("user resolution block reason code: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|