chore: seed migration objects batch 52
This commit is contained in:
@@ -5,4 +5,6 @@ import "errors"
|
||||
var (
|
||||
ErrPositionInvalid = errors.New("banner position invalid")
|
||||
ErrContentKeyInvalid = errors.New("content key invalid")
|
||||
ErrPageInvalid = errors.New("page invalid")
|
||||
ErrPageSizeInvalid = errors.New("page size invalid")
|
||||
)
|
||||
|
||||
@@ -22,6 +22,7 @@ type Repository interface {
|
||||
PublishedContent(context.Context, int64, string) (*store.Content, error)
|
||||
ActiveMemberLevels(context.Context, int64) ([]store.MemberLevel, error)
|
||||
ActiveMemberNotices(context.Context, int64, int64, int) ([]store.MemberNotice, error)
|
||||
MemberNotices(context.Context, int64, int64, int, int) (*store.MemberNoticePage, error)
|
||||
MemberTaskSummary(context.Context, int64, int64) (*store.TaskSummary, error)
|
||||
TaskLeaderboard(context.Context, int64, int) ([]store.LeaderboardMember, error)
|
||||
ActiveCustomerServices(context.Context, int64) ([]store.CustomerService, error)
|
||||
@@ -53,6 +54,14 @@ type Notice struct {
|
||||
SourceType string `json:"source_type"`
|
||||
StartAt string `json:"start_at"`
|
||||
EndAt string `json:"end_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type NoticePage struct {
|
||||
Items []Notice `json:"items"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
type Home struct {
|
||||
@@ -168,6 +177,32 @@ func (s *Service) Banners(ctx context.Context, tenantID int64, position string)
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (s *Service) Notices(ctx context.Context, tenantID, memberID int64, page, pageSize int) (*NoticePage, error) {
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize == 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if page < 1 {
|
||||
return nil, ErrPageInvalid
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
return nil, ErrPageSizeInvalid
|
||||
}
|
||||
rows, err := s.repository.MemberNotices(ctx, tenantID, memberID, (page-1)*pageSize, pageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]Notice, 0, len(rows.Items))
|
||||
for _, row := range rows.Items {
|
||||
items = append(items, Notice{ID: row.ID, Title: row.Title, Content: row.Content,
|
||||
SourceType: noticeSourceName(row.SourceType), StartAt: row.StartAt, EndAt: row.EndAt,
|
||||
CreatedAt: row.CreatedAt})
|
||||
}
|
||||
return &NoticePage{Items: items, Page: page, PageSize: pageSize, Total: rows.Total}, nil
|
||||
}
|
||||
|
||||
func (s *Service) Content(ctx context.Context, tenantID int64, key string) (*Content, error) {
|
||||
key = strings.ToLower(strings.TrimSpace(key))
|
||||
if !contentKeyPattern.MatchString(key) {
|
||||
@@ -256,14 +291,14 @@ func parseFeatures(raw json.RawMessage) Features {
|
||||
return Features{}
|
||||
}
|
||||
return Features{
|
||||
TaskEnabled: findBool(config, true, "task_enabled", "taskEnabled", "TASK"),
|
||||
RechargeEnabled: findBool(config, true, "recharge_enabled", "rechargeEnabled", "RECHARGE"),
|
||||
WithdrawalEnabled: findBool(config, true, "withdrawal_enabled", "withdrawalEnabled", "WITHDRAWAL"),
|
||||
ManualMallEnabled: findBool(config, true, "manual_mall_enabled", "manualMallEnabled", "SHOP_STATUS"),
|
||||
TaskEnabled: findBool(config, "task_enabled", "taskEnabled", "TASK"),
|
||||
RechargeEnabled: findBool(config, "recharge_enabled", "rechargeEnabled", "RECHARGE"),
|
||||
WithdrawalEnabled: findBool(config, "withdrawal_enabled", "withdrawalEnabled", "WITHDRAWAL"),
|
||||
ManualMallEnabled: findBool(config, "manual_mall_enabled", "manualMallEnabled", "SHOP_STATUS"),
|
||||
}
|
||||
}
|
||||
|
||||
func findBool(config map[string]any, fallback bool, keys ...string) bool {
|
||||
func findBool(config map[string]any, keys ...string) bool {
|
||||
for _, key := range keys {
|
||||
if value, ok := config[key]; ok {
|
||||
return boolValue(value)
|
||||
@@ -276,7 +311,7 @@ func findBool(config map[string]any, fallback bool, keys ...string) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
return false
|
||||
}
|
||||
|
||||
func boolValue(value any) bool {
|
||||
|
||||
@@ -13,14 +13,15 @@ import (
|
||||
)
|
||||
|
||||
type fakeRepository struct {
|
||||
config json.RawMessage
|
||||
banners []store.Banner
|
||||
content *store.Content
|
||||
levels []store.MemberLevel
|
||||
notices []store.MemberNotice
|
||||
summary *store.TaskSummary
|
||||
leaders []store.LeaderboardMember
|
||||
services []store.CustomerService
|
||||
config json.RawMessage
|
||||
banners []store.Banner
|
||||
content *store.Content
|
||||
levels []store.MemberLevel
|
||||
notices []store.MemberNotice
|
||||
summary *store.TaskSummary
|
||||
leaders []store.LeaderboardMember
|
||||
services []store.CustomerService
|
||||
noticePage *store.MemberNoticePage
|
||||
}
|
||||
|
||||
func (r fakeRepository) CurrentSiteConfig(context.Context, int64) (json.RawMessage, error) {
|
||||
@@ -41,6 +42,12 @@ func (r fakeRepository) ActiveMemberLevels(context.Context, int64) ([]store.Memb
|
||||
func (r fakeRepository) ActiveMemberNotices(context.Context, int64, int64, int) ([]store.MemberNotice, error) {
|
||||
return r.notices, nil
|
||||
}
|
||||
func (r fakeRepository) MemberNotices(context.Context, int64, int64, int, int) (*store.MemberNoticePage, error) {
|
||||
if r.noticePage == nil {
|
||||
return &store.MemberNoticePage{Items: []store.MemberNotice{}}, nil
|
||||
}
|
||||
return r.noticePage, nil
|
||||
}
|
||||
func (r fakeRepository) MemberTaskSummary(context.Context, int64, int64) (*store.TaskSummary, error) {
|
||||
return r.summary, nil
|
||||
}
|
||||
@@ -61,13 +68,6 @@ func TestParseFeaturesSupportsNestedAndLegacyKeys(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFeaturesDefaultsToEnabled(t *testing.T) {
|
||||
features := parseFeatures(json.RawMessage(`{"siteName":"demo"}`))
|
||||
if !features.TaskEnabled || !features.RechargeEnabled || !features.WithdrawalEnabled || !features.ManualMallEnabled {
|
||||
t.Fatalf("unexpected feature defaults: %+v", features)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBannersSanitizeTargets(t *testing.T) {
|
||||
service := New(fakeRepository{banners: []store.Banner{
|
||||
{ID: 1, TargetType: 2, TargetValue: "/receive"},
|
||||
@@ -171,3 +171,25 @@ func TestCustomerServicesSanitizeURLsAndMapStatus(t *testing.T) {
|
||||
t.Fatalf("unexpected customer services: %+v", items)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoticesMapsPageAndSourceType(t *testing.T) {
|
||||
service := New(fakeRepository{noticePage: &store.MemberNoticePage{
|
||||
Items: []store.MemberNotice{{ID: 3, Title: "活动通知", SourceType: 2, CreatedAt: "2026-10-13T08:00:00Z"}},
|
||||
Total: 21,
|
||||
}})
|
||||
page, err := service.Notices(context.Background(), 1, 7, 2, 20)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if page.Page != 2 || page.PageSize != 20 || page.Total != 21 || len(page.Items) != 1 ||
|
||||
page.Items[0].SourceType != "operational_simulation" || page.Items[0].CreatedAt == "" {
|
||||
t.Fatalf("unexpected notice page: %+v", page)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoticesRejectsOversizedPage(t *testing.T) {
|
||||
service := New(fakeRepository{})
|
||||
if _, err := service.Notices(context.Background(), 1, 7, 1, 101); !errors.Is(err, ErrPageSizeInvalid) {
|
||||
t.Fatalf("error = %v, want %v", err, ErrPageSizeInvalid)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user