package systemconfig import ( "encoding/json" "errors" "strings" ) var ( ErrDependencyUnavailable = errors.New("dependency unavailable") ErrInvalidConfig = errors.New("invalid config") ) type Service struct { repo *Repository } func NewService(repo *Repository) *Service { return &Service{repo: repo} } func (s *Service) List() ([]ConfigDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } return s.repo.List() } func (s *Service) PublishOptions() (*PublishOptionsDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } options, err := s.publishOptions() if err != nil { return nil, err } return &options, nil } func (s *Service) SalePriceConfig() (*PublishSalePriceConfig, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } config, err := s.salePriceConfig() if err != nil { return nil, err } return &config, nil } func (s *Service) OrderAgreements() (*OrderAgreementsDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } agreements, err := s.orderAgreements() if err != nil { return nil, err } return &agreements, nil } func (s *Service) PostRentalNotice() (*PostRentalNoticeDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } notice, err := s.postRentalNotice() if err != nil { return nil, err } return ¬ice, nil } func (s *Service) publishOptions() (PublishOptionsDTO, error) { value, err := s.repo.FindValue(publishOptionsConfigKey) if err != nil { return PublishOptionsDTO{}, err } options := DefaultPublishOptions() if err := json.Unmarshal([]byte(value), &options); err != nil { options = DefaultPublishOptions() } normalizePublishOptions(&options) return options, nil } func (s *Service) salePriceConfig() (PublishSalePriceConfig, error) { value, err := s.repo.FindValue(salePriceConfigKey) if err != nil { return PublishSalePriceConfig{}, err } config := DefaultSalePriceConfig() if err := json.Unmarshal([]byte(value), &config); err != nil { config = DefaultSalePriceConfig() } normalizeSalePriceConfig(&config) return config, nil } func (s *Service) orderAgreements() (OrderAgreementsDTO, error) { value, err := s.repo.FindValue(orderAgreementsConfigKey) if err != nil { return OrderAgreementsDTO{}, err } agreements := DefaultOrderAgreements() if err := json.Unmarshal([]byte(value), &agreements); err != nil { agreements = DefaultOrderAgreements() } normalizeOrderAgreements(&agreements) return agreements, nil } func (s *Service) postRentalNotice() (PostRentalNoticeDTO, error) { value, err := s.repo.FindValue(postRentalNoticeConfigKey) if err != nil { return PostRentalNoticeDTO{}, err } notice := DefaultPostRentalNotice() if err := json.Unmarshal([]byte(value), ¬ice); err != nil { notice = DefaultPostRentalNotice() } normalizePostRentalNotice(¬ice) return notice, nil } func (s *Service) HomeAnnouncements() (*HomeAnnouncementsDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } items, err := s.homeAnnouncements() if err != nil { return nil, err } return &HomeAnnouncementsDTO{Items: items}, nil } func (s *Service) HomeConfig() (*HomeConfigDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } announcements, err := s.homeAnnouncements() if err != nil { return nil, err } banners, err := s.homeBanners() if err != nil { return nil, err } publishOptions, err := s.publishOptions() if err != nil { return nil, err } return &HomeConfigDTO{ Announcements: announcements, Banners: banners, PublishOptions: publishOptions, }, nil } func (s *Service) homeAnnouncements() ([]string, error) { value, err := s.repo.FindValue(homeAnnouncementsConfigKey) if err != nil { return nil, err } items := defaultHomeAnnouncements() if err := json.Unmarshal([]byte(value), &items); err != nil { items = defaultHomeAnnouncements() } return normalizeAnnouncements(items), nil } func (s *Service) homeBanners() ([]HomeBannerItem, error) { value, err := s.repo.FindValue(homeBannersConfigKey) if err != nil { return nil, err } items := defaultHomeBanners() if err := json.Unmarshal([]byte(value), &items); err != nil { items = defaultHomeBanners() } return normalizeHomeBanners(items), nil } func (s *Service) Update(actorID uint64, key string, req UpdateRequest, meta AuditMeta) (*ConfigDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } if key == "" || req.Value == "" { return nil, ErrInvalidConfig } return s.repo.Update(actorID, key, req, meta) } func normalizeAnnouncements(items []string) []string { normalized := make([]string, 0, len(items)) for _, item := range items { item = strings.TrimSpace(item) if item != "" { normalized = append(normalized, item) } } if len(normalized) == 0 { return defaultHomeAnnouncements() } return normalized } func normalizeHomeBanners(items []HomeBannerItem) []HomeBannerItem { normalized := make([]HomeBannerItem, 0, len(items)) for _, item := range items { item.Eyebrow = strings.TrimSpace(item.Eyebrow) item.Title = strings.TrimSpace(item.Title) item.Badge = strings.TrimSpace(item.Badge) item.Pill = strings.TrimSpace(item.Pill) item.Tone = strings.TrimSpace(item.Tone) item.ImageURL = strings.TrimSpace(item.ImageURL) if item.Title == "" && item.ImageURL == "" { continue } if item.Tone != "green" && item.Tone != "orange" { item.Tone = "blue" } normalized = append(normalized, item) } if len(normalized) == 0 { return defaultHomeBanners() } return normalized } func normalizeOrderAgreements(agreements *OrderAgreementsDTO) { defaults := DefaultOrderAgreements() agreements.VirtualAssetPurchase.Title = strings.TrimSpace(agreements.VirtualAssetPurchase.Title) agreements.VirtualAssetPurchase.Content = strings.TrimSpace(agreements.VirtualAssetPurchase.Content) agreements.RenterAgreement.Title = strings.TrimSpace(agreements.RenterAgreement.Title) agreements.RenterAgreement.Content = strings.TrimSpace(agreements.RenterAgreement.Content) if agreements.VirtualAssetPurchase.Title == "" { agreements.VirtualAssetPurchase.Title = defaults.VirtualAssetPurchase.Title } if agreements.VirtualAssetPurchase.Content == "" { agreements.VirtualAssetPurchase.Content = defaults.VirtualAssetPurchase.Content } if agreements.RenterAgreement.Title == "" { agreements.RenterAgreement.Title = defaults.RenterAgreement.Title } if agreements.RenterAgreement.Content == "" { agreements.RenterAgreement.Content = defaults.RenterAgreement.Content } } func normalizePostRentalNotice(notice *PostRentalNoticeDTO) { defaults := DefaultPostRentalNotice() notice.Title = strings.TrimSpace(notice.Title) notice.Content = strings.TrimSpace(notice.Content) if notice.Title == "" { notice.Title = defaults.Title } if notice.Content == "" { notice.Content = defaults.Content } } func normalizePublishOptions(options *PublishOptionsDTO) { defaults := DefaultPublishOptions() if len(options.ServerOptions) == 0 { options.ServerOptions = defaults.ServerOptions } if len(options.FaceOptions) == 0 { options.FaceOptions = defaults.FaceOptions } if len(options.RankOptions) == 0 { options.RankOptions = defaults.RankOptions } if len(options.InsuranceOptions) == 0 { options.InsuranceOptions = defaults.InsuranceOptions } if len(options.LevelOptions) == 0 { options.LevelOptions = defaults.LevelOptions } if len(options.LoginMethodOptions) == 0 { options.LoginMethodOptions = defaults.LoginMethodOptions } if len(options.RegionOptions) == 0 { options.RegionOptions = defaults.RegionOptions } if len(options.SkinGroups) == 0 { options.SkinGroups = defaults.SkinGroups } if len(options.QuantityItems) == 0 { options.QuantityItems = defaults.QuantityItems } if len(options.ScreenshotSlots) == 0 { options.ScreenshotSlots = defaults.ScreenshotSlots } if len(options.BanRecordOptions) == 0 { options.BanRecordOptions = defaults.BanRecordOptions } if len(options.BanEvidenceOptions) == 0 { options.BanEvidenceOptions = defaults.BanEvidenceOptions } if options.FireLevelMin <= 0 { options.FireLevelMin = defaults.FireLevelMin } if options.PriceConfig.DepositPlaceholder == "" { options.PriceConfig.DepositPlaceholder = defaults.PriceConfig.DepositPlaceholder } if options.PriceConfig.PricePlaceholder == "" { options.PriceConfig.PricePlaceholder = defaults.PriceConfig.PricePlaceholder } if options.PriceConfig.RatioDescription == "" { options.PriceConfig.RatioDescription = defaults.PriceConfig.RatioDescription } if options.DepositRecommend.BaseAmount <= 0 { options.DepositRecommend.BaseAmount = defaults.DepositRecommend.BaseAmount } if len(options.DepositRecommend.SkinGroupRules) == 0 { options.DepositRecommend.SkinGroupRules = defaults.DepositRecommend.SkinGroupRules } if len(options.RatioConfig.InsuranceBaseRatios) == 0 { options.RatioConfig.InsuranceBaseRatios = defaults.RatioConfig.InsuranceBaseRatios } if len(options.RatioConfig.ConfigItems) == 0 { options.RatioConfig.ConfigItems = defaults.RatioConfig.ConfigItems } if len(options.RatioConfig.CoinCorrections) == 0 { options.RatioConfig.CoinCorrections = defaults.RatioConfig.CoinCorrections } } func normalizeSalePriceConfig(config *PublishSalePriceConfig) { defaults := DefaultSalePriceConfig() if len(config.FixedMarkupRules) == 0 { config.FixedMarkupRules = defaults.FixedMarkupRules } if len(config.RatioAdjustmentRules) == 0 { config.RatioAdjustmentRules = defaults.RatioAdjustmentRules } }