103 lines
3.4 KiB
Go
103 lines
3.4 KiB
Go
package ports
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"galaxy/authsession/internal/domain/common"
|
|
)
|
|
|
|
// MailSender delivers the public login code or intentionally suppresses
|
|
// outward delivery while keeping the auth flow success-shaped.
|
|
type MailSender interface {
|
|
// SendLoginCode attempts delivery for one generated login code. Explicit
|
|
// delivery failure is reported through error, while sent vs suppressed is
|
|
// returned in the result.
|
|
SendLoginCode(ctx context.Context, input SendLoginCodeInput) (SendLoginCodeResult, error)
|
|
}
|
|
|
|
// SendLoginCodeInput describes one mail-delivery request generated by the auth
|
|
// flow.
|
|
type SendLoginCodeInput struct {
|
|
// Email identifies the normalized target e-mail address.
|
|
Email common.Email
|
|
|
|
// IdempotencyKey stores the raw challenge_id value sent to Mail Service as
|
|
// the required Idempotency-Key header.
|
|
IdempotencyKey string
|
|
|
|
// Code stores the cleartext login code that should be delivered to Email.
|
|
Code string
|
|
|
|
// Locale stores the canonical BCP 47 language tag that selects the auth
|
|
// mail template locale.
|
|
Locale string
|
|
}
|
|
|
|
// Validate reports whether SendLoginCodeInput contains a complete delivery
|
|
// request.
|
|
func (i SendLoginCodeInput) Validate() error {
|
|
if err := i.Email.Validate(); err != nil {
|
|
return fmt.Errorf("send login code input email: %w", err)
|
|
}
|
|
switch {
|
|
case strings.TrimSpace(i.IdempotencyKey) == "":
|
|
return errors.New("send login code input idempotency key must not be empty")
|
|
case strings.TrimSpace(i.IdempotencyKey) != i.IdempotencyKey:
|
|
return errors.New("send login code input idempotency key must not contain surrounding whitespace")
|
|
case strings.TrimSpace(i.Code) == "":
|
|
return errors.New("send login code input code must not be empty")
|
|
case strings.TrimSpace(i.Code) != i.Code:
|
|
return errors.New("send login code input code must not contain surrounding whitespace")
|
|
case strings.TrimSpace(i.Locale) == "":
|
|
return errors.New("send login code input locale must not be empty")
|
|
case strings.TrimSpace(i.Locale) != i.Locale:
|
|
return errors.New("send login code input locale must not contain surrounding whitespace")
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// SendLoginCodeOutcome identifies the coarse mail-delivery outcome reported
|
|
// back to the auth flow.
|
|
type SendLoginCodeOutcome string
|
|
|
|
const (
|
|
// SendLoginCodeOutcomeSent reports that delivery was attempted and accepted.
|
|
SendLoginCodeOutcomeSent SendLoginCodeOutcome = "sent"
|
|
|
|
// SendLoginCodeOutcomeSuppressed reports that outward behavior remains
|
|
// success-shaped while actual delivery is intentionally skipped.
|
|
SendLoginCodeOutcomeSuppressed SendLoginCodeOutcome = "suppressed"
|
|
)
|
|
|
|
// IsKnown reports whether SendLoginCodeOutcome is supported by the current
|
|
// mail-sender contract.
|
|
func (o SendLoginCodeOutcome) IsKnown() bool {
|
|
switch o {
|
|
case SendLoginCodeOutcomeSent, SendLoginCodeOutcomeSuppressed:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// SendLoginCodeResult describes the stable outcome returned by MailSender for
|
|
// one delivery request.
|
|
type SendLoginCodeResult struct {
|
|
// Outcome reports whether delivery was sent or intentionally suppressed.
|
|
Outcome SendLoginCodeOutcome
|
|
}
|
|
|
|
// Validate reports whether SendLoginCodeResult satisfies the mail-sender
|
|
// contract invariants.
|
|
func (r SendLoginCodeResult) Validate() error {
|
|
if !r.Outcome.IsKnown() {
|
|
return fmt.Errorf("send login code result outcome %q is unsupported", r.Outcome)
|
|
}
|
|
|
|
return nil
|
|
}
|