chore: build
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
package site
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
repo Repository
|
||||
@@ -14,10 +18,190 @@ func (s *Service) Get(ctx context.Context) (*Settings, error) {
|
||||
return s.repo.Get(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) Update(ctx context.Context, name, description, slug string) (*Settings, error) {
|
||||
settings := &Settings{Name: name, Description: description, Slug: slug}
|
||||
func (s *Service) Update(ctx context.Context, name, description string, ordersEnabled bool) (*Settings, error) {
|
||||
settings := &Settings{Name: name, Description: description, OrdersEnabled: ordersEnabled}
|
||||
if err := s.repo.Update(ctx, settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.repo.Get(ctx)
|
||||
}
|
||||
|
||||
// AppearanceInput is updated independently from site identity (name/slug):
|
||||
// the "Appearance" admin page only ever touches these fields, so it must
|
||||
// not be blocked by identity validation (e.g. an unset slug) or clobber
|
||||
// name/description/slug on save. Each field is a pointer so the admin can
|
||||
// change a single option (e.g. just the product layout) without resending
|
||||
// every color -- nil fields keep their current, already-saved value.
|
||||
type AppearanceInput struct {
|
||||
HeaderBgColor *string
|
||||
HeaderTextColor *string
|
||||
BodyBgColor *string
|
||||
BodyTextColor *string
|
||||
FooterBgColor *string
|
||||
FooterTextColor *string
|
||||
AccentColor *string
|
||||
ProductLayout *string
|
||||
ProductColumns *int
|
||||
ProductScroll *string
|
||||
|
||||
ContactCardTransparent *bool
|
||||
ContactCardBgColor *string
|
||||
|
||||
// LogoMediaIDSet/HeroMediaIDSet distinguish "the admin didn't touch
|
||||
// this field" (false: keep the current value) from "the admin
|
||||
// explicitly chose an image, possibly clearing it to nil" (true: use
|
||||
// the ID as-is, nil included) -- same reasoning as
|
||||
// CustomerAuthInput.VerificationContactLinkSet.
|
||||
LogoMediaIDSet bool
|
||||
LogoMediaID *uuid.UUID
|
||||
HeroMediaIDSet bool
|
||||
HeroMediaID *uuid.UUID
|
||||
HeroPages *string
|
||||
}
|
||||
|
||||
func (s *Service) UpdateAppearance(ctx context.Context, in AppearanceInput) (*Settings, error) {
|
||||
current, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
settings := &Settings{
|
||||
HeaderBgColor: applyIfSet(in.HeaderBgColor, current.HeaderBgColor),
|
||||
HeaderTextColor: applyIfSet(in.HeaderTextColor, current.HeaderTextColor),
|
||||
BodyBgColor: applyIfSet(in.BodyBgColor, current.BodyBgColor),
|
||||
BodyTextColor: applyIfSet(in.BodyTextColor, current.BodyTextColor),
|
||||
FooterBgColor: applyIfSet(in.FooterBgColor, current.FooterBgColor),
|
||||
FooterTextColor: applyIfSet(in.FooterTextColor, current.FooterTextColor),
|
||||
AccentColor: applyIfSet(in.AccentColor, current.AccentColor),
|
||||
ProductLayout: applyIfSet(in.ProductLayout, current.ProductLayout),
|
||||
ProductColumns: applyIntIfSet(in.ProductColumns, current.ProductColumns),
|
||||
ProductScroll: applyIfSet(in.ProductScroll, current.ProductScroll),
|
||||
ContactCardTransparent: applyBoolIfSet(in.ContactCardTransparent, current.ContactCardTransparent),
|
||||
ContactCardBgColor: applyIfSet(in.ContactCardBgColor, current.ContactCardBgColor),
|
||||
LogoMediaID: current.LogoMediaID,
|
||||
HeroMediaID: current.HeroMediaID,
|
||||
HeroPages: applyIfSet(in.HeroPages, current.HeroPages),
|
||||
}
|
||||
if in.LogoMediaIDSet {
|
||||
settings.LogoMediaID = in.LogoMediaID
|
||||
}
|
||||
if in.HeroMediaIDSet {
|
||||
settings.HeroMediaID = in.HeroMediaID
|
||||
}
|
||||
if err := s.repo.UpdateAppearance(ctx, settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.repo.Get(ctx)
|
||||
}
|
||||
|
||||
func applyIfSet(value *string, fallback string) string {
|
||||
if value == nil {
|
||||
return fallback
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
func applyIntIfSet(value *int, fallback int) int {
|
||||
if value == nil {
|
||||
return fallback
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
// CustomerAuthInput is updated independently from identity/appearance, same
|
||||
// reasoning as AppearanceInput: the "Customer accounts" admin page only
|
||||
// ever touches these fields. LoginEnabled and RegistrationEnabled are two
|
||||
// independent switches (e.g. an invite-only shop can enable login while
|
||||
// keeping registration off), so each is its own optional pointer.
|
||||
type CustomerAuthInput struct {
|
||||
LoginEnabled *bool
|
||||
RegistrationEnabled *bool
|
||||
VerificationRequired *bool
|
||||
// VerificationContactLinkSet distinguishes "the admin didn't touch this
|
||||
// field" (false: keep the current value) from "the admin explicitly
|
||||
// chose a link, possibly clearing it to nil" (true: use
|
||||
// VerificationContactLinkID as-is, nil included).
|
||||
VerificationContactLinkSet bool
|
||||
VerificationContactLinkID *uuid.UUID
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCustomerAuth(ctx context.Context, in CustomerAuthInput) (*Settings, error) {
|
||||
current, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
settings := &Settings{
|
||||
CustomerLoginEnabled: applyBoolIfSet(in.LoginEnabled, current.CustomerLoginEnabled),
|
||||
CustomerRegistrationEnabled: applyBoolIfSet(in.RegistrationEnabled, current.CustomerRegistrationEnabled),
|
||||
CustomerVerificationRequired: applyBoolIfSet(in.VerificationRequired, current.CustomerVerificationRequired),
|
||||
VerificationContactLinkID: current.VerificationContactLinkID,
|
||||
}
|
||||
if in.VerificationContactLinkSet {
|
||||
settings.VerificationContactLinkID = in.VerificationContactLinkID
|
||||
}
|
||||
if err := s.repo.UpdateCustomerAuth(ctx, settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.repo.Get(ctx)
|
||||
}
|
||||
|
||||
func applyBoolIfSet(value *bool, fallback bool) bool {
|
||||
if value == nil {
|
||||
return fallback
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
// CustomerLoginEnabled is consumed by auth.CustomerHandler to gate the
|
||||
// customer login page/endpoint behind the admin's toggle.
|
||||
func (s *Service) CustomerLoginEnabled(ctx context.Context) (bool, error) {
|
||||
settings, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return settings.CustomerLoginEnabled, nil
|
||||
}
|
||||
|
||||
// CustomerRegistrationEnabled is consumed by auth.CustomerHandler to gate
|
||||
// the customer registration page/endpoint behind the admin's toggle,
|
||||
// independently of CustomerLoginEnabled.
|
||||
func (s *Service) CustomerRegistrationEnabled(ctx context.Context) (bool, error) {
|
||||
settings, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return settings.CustomerRegistrationEnabled, nil
|
||||
}
|
||||
|
||||
// CustomerAccountsAvailable is consumed by users.Service.Create to prevent
|
||||
// creating customer-role users when neither login nor registration is
|
||||
// enabled -- such an account could never be used to sign in.
|
||||
func (s *Service) CustomerAccountsAvailable(ctx context.Context) (bool, error) {
|
||||
settings, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return settings.CustomerLoginEnabled || settings.CustomerRegistrationEnabled, nil
|
||||
}
|
||||
|
||||
// CustomerCheckoutSettings is consumed by orders.RequireAccountsEnabled /
|
||||
// RequireApprovedVerificationIfNeeded to gate order creation.
|
||||
func (s *Service) CustomerCheckoutSettings(ctx context.Context) (accountsEnabled, verificationRequired bool, err error) {
|
||||
settings, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
return settings.CustomerLoginEnabled, settings.CustomerVerificationRequired, nil
|
||||
}
|
||||
|
||||
// OrdersEnabled is consumed by orders.RequireOrdersEnabled: the site-wide
|
||||
// "vitrine vs boutique" switch, checked before any of the customer-account
|
||||
// gates so a pure showcase site never has to think about accounts at all.
|
||||
func (s *Service) OrdersEnabled(ctx context.Context) (bool, error) {
|
||||
settings, err := s.repo.Get(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return settings.OrdersEnabled, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user