44 lines
1.4 KiB
Go
44 lines
1.4 KiB
Go
package geo
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"galaxy/backend/internal/postgres/jet/backend/table"
|
|
|
|
"github.com/go-jet/jet/v2/postgres"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// SetDeclaredCountryAtRegistration writes the geoip-derived country to
|
|
// `accounts.declared_country` for userID, and only when the column is
|
|
// currently NULL. The semantics match PLAN.md §5.8: declared_country is
|
|
// captured at first registration and never updated thereafter, so
|
|
// repeated calls on the same account are no-ops.
|
|
//
|
|
// The geoip lookup itself is best-effort: a missing or invalid country
|
|
// returns nil (no UPDATE executed) and never blocks the auth flow. Errors
|
|
// from the database UPDATE itself surface to the caller so the auth
|
|
// service can decide whether to log or escalate.
|
|
func (s *Service) SetDeclaredCountryAtRegistration(ctx context.Context, userID uuid.UUID, sourceIP string) error {
|
|
if s == nil {
|
|
return errors.New("geo: nil service")
|
|
}
|
|
country := s.LookupCountry(sourceIP)
|
|
if country == "" {
|
|
return nil
|
|
}
|
|
stmt := table.Accounts.UPDATE(table.Accounts.DeclaredCountry, table.Accounts.UpdatedAt).
|
|
SET(postgres.String(country), postgres.NOW()).
|
|
WHERE(
|
|
table.Accounts.UserID.EQ(postgres.UUID(userID)).
|
|
AND(table.Accounts.DeclaredCountry.IS_NULL()).
|
|
AND(table.Accounts.DeletedAt.IS_NULL()),
|
|
)
|
|
if _, err := stmt.ExecContext(ctx, s.db); err != nil {
|
|
return fmt.Errorf("geo: set declared_country for %s: %w", userID, err)
|
|
}
|
|
return nil
|
|
}
|