package activitytemplate import ( "hyapp-admin-server/internal/integration/userclient" activityv1 "hyapp.local/api/proto/activity/v1" ) type localeDTO struct { Locale string `json:"locale"` Title string `json:"title"` Rules string `json:"rules"` } type giftDTO struct { GiftID string `json:"gift_id"` SortOrder int32 `json:"sort_order"` Name string `json:"name"` IconURL string `json:"icon_url"` CoinPrice int64 `json:"coin_price"` PriceVersion string `json:"price_version"` } // rewardItemDTO is the immutable, display-safe reward item captured at publish // time. Admin reads this snapshot instead of joining mutable wallet catalog rows. type rewardItemDTO struct { ItemType string `json:"item_type"` ResourceID int64 `json:"resource_id"` ResourceType string `json:"resource_type"` Name string `json:"name"` IconURL string `json:"icon_url"` Quantity int64 `json:"quantity"` DurationMS int64 `json:"duration_ms"` WalletAssetType string `json:"wallet_asset_type"` WalletAssetAmount int64 `json:"wallet_asset_amount"` SortOrder int32 `json:"sort_order"` } type taskDTO struct { TaskKey string `json:"task_key"` TaskType string `json:"task_type"` TargetValue int64 `json:"target_value"` RewardResourceGroupID int64 `json:"reward_resource_group_id"` SortOrder int32 `json:"sort_order"` RewardSnapshotID string `json:"reward_snapshot_id"` RewardSnapshotHash string `json:"reward_snapshot_hash"` RewardName string `json:"reward_name"` RewardItems []rewardItemDTO `json:"reward_items"` } type rankRewardDTO struct { BoardType string `json:"board_type"` RankFrom int32 `json:"rank_from"` RankTo int32 `json:"rank_to"` ResourceGroupID int64 `json:"resource_group_id"` SortOrder int32 `json:"sort_order"` RewardSnapshotID string `json:"reward_snapshot_id"` RewardSnapshotHash string `json:"reward_snapshot_hash"` RewardName string `json:"reward_name"` RewardItems []rewardItemDTO `json:"reward_items"` } type assetDTO struct { AssetKey string `json:"asset_key"` Locale string `json:"locale"` URL string `json:"url"` MediaType string `json:"media_type"` SortOrder int32 `json:"sort_order"` } type templateSummaryDTO struct { AppCode string `json:"app_code"` TemplateID string `json:"template_id"` TemplateCode string `json:"template_code"` Name string `json:"name"` ActivityType string `json:"activity_type"` Status string `json:"status"` LifecycleStatus string `json:"lifecycle_status"` StartMS int64 `json:"start_ms"` EndMS int64 `json:"end_ms"` AllRegions bool `json:"all_regions"` RegionIDs []int64 `json:"region_ids"` Revision int64 `json:"revision"` PublishedVersion int64 `json:"published_version"` CreatedByAdminID int64 `json:"created_by_admin_id"` UpdatedByAdminID int64 `json:"updated_by_admin_id"` CreatedAtMS int64 `json:"created_at_ms"` UpdatedAtMS int64 `json:"updated_at_ms"` } type templateDTO struct { AppCode string `json:"app_code"` TemplateID string `json:"template_id"` TemplateCode string `json:"template_code"` Name string `json:"name"` ActivityType string `json:"activity_type"` Status string `json:"status"` LifecycleStatus string `json:"lifecycle_status"` StartMS int64 `json:"start_ms"` EndMS int64 `json:"end_ms"` AllRegions bool `json:"all_regions"` RegionIDs []int64 `json:"region_ids"` Locales []localeDTO `json:"locales"` Gifts []giftDTO `json:"gifts"` Tasks []taskDTO `json:"tasks"` DailyLeaderboardSize int32 `json:"daily_leaderboard_size"` TotalLeaderboardSize int32 `json:"total_leaderboard_size"` RankRewards []rankRewardDTO `json:"rank_rewards"` Assets []assetDTO `json:"assets"` DisplayConfigJSON string `json:"display_config_json"` Revision int64 `json:"revision"` PublishedVersion int64 `json:"published_version"` CreatedByAdminID int64 `json:"created_by_admin_id"` UpdatedByAdminID int64 `json:"updated_by_admin_id"` PublishedByAdminID int64 `json:"published_by_admin_id"` CreatedAtMS int64 `json:"created_at_ms"` UpdatedAtMS int64 `json:"updated_at_ms"` PublishedAtMS int64 `json:"published_at_ms"` ArchivedAtMS int64 `json:"archived_at_ms"` } type versionDTO struct { TemplateID string `json:"template_id"` VersionNo int64 `json:"version_no"` Snapshot templateDTO `json:"snapshot"` PublishedByAdminID int64 `json:"published_by_admin_id"` PublishedAtMS int64 `json:"published_at_ms"` RuntimeFromMS int64 `json:"runtime_from_ms"` RuntimeToMS int64 `json:"runtime_to_ms"` } type validationIssueDTO struct { Field string `json:"field"` Code string `json:"code"` Message string `json:"message"` } type pageDTO struct { Items any `json:"items"` Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` ServerTimeMS int64 `json:"server_time_ms,omitempty"` } type rankPeriodDTO struct { TemplateID string `json:"template_id"` TemplateCode string `json:"template_code"` VersionNo int64 `json:"version_no"` BoardType string `json:"board_type"` PeriodKey string `json:"period_key"` PeriodStartMS int64 `json:"period_start_ms"` PeriodEndMS int64 `json:"period_end_ms"` SettleAfterMS int64 `json:"settle_after_ms"` Status string `json:"status"` SettledAtMS int64 `json:"settled_at_ms"` } type leaderboardEntryDTO struct { RankNo int32 `json:"rank_no"` UserID int64 `json:"user_id"` Score int64 `json:"score"` GiftCount int64 `json:"gift_count"` CoinAmount int64 `json:"coin_amount"` FirstScoredAtMS int64 `json:"first_scored_at_ms"` Snapshot bool `json:"snapshot"` User *activityTemplateUserDTO `json:"user,omitempty"` } type leaderboardPageDTO struct { Period rankPeriodDTO `json:"period"` Items []leaderboardEntryDTO `json:"items"` Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` } type rewardJobDTO struct { RewardJobID string `json:"reward_job_id"` TemplateID string `json:"template_id"` TemplateCode string `json:"template_code"` VersionNo int64 `json:"version_no"` BoardType string `json:"board_type"` PeriodKey string `json:"period_key"` RankNo int32 `json:"rank_no"` UserID int64 `json:"user_id"` Score int64 `json:"score"` ResourceGroupID int64 `json:"resource_group_id"` WalletCommandID string `json:"wallet_command_id"` WalletGrantID string `json:"wallet_grant_id"` Status string `json:"status"` FailureReason string `json:"failure_reason"` AttemptCount int32 `json:"attempt_count"` MaxAttempts int32 `json:"max_attempts"` NextRetryAtMS int64 `json:"next_retry_at_ms"` CreatedAtMS int64 `json:"created_at_ms"` UpdatedAtMS int64 `json:"updated_at_ms"` GrantedAtMS int64 `json:"granted_at_ms"` RewardSnapshotID string `json:"reward_snapshot_id"` RewardSnapshotHash string `json:"reward_snapshot_hash"` RewardName string `json:"reward_name"` RewardItems []rewardItemDTO `json:"reward_items"` User *activityTemplateUserDTO `json:"user,omitempty"` } type taskClaimDTO struct { ClaimID string `json:"claim_id"` CommandID string `json:"command_id"` TemplateID string `json:"template_id"` TemplateCode string `json:"template_code"` VersionNo int64 `json:"version_no"` TaskDay string `json:"task_day"` TaskKey string `json:"task_key"` UserID int64 `json:"user_id"` RewardResourceGroupID int64 `json:"reward_resource_group_id"` WalletCommandID string `json:"wallet_command_id"` WalletGrantID string `json:"wallet_grant_id"` Status string `json:"status"` FailureReason string `json:"failure_reason"` AttemptCount int32 `json:"attempt_count"` CreatedAtMS int64 `json:"created_at_ms"` UpdatedAtMS int64 `json:"updated_at_ms"` GrantedAtMS int64 `json:"granted_at_ms"` RewardSnapshotID string `json:"reward_snapshot_id"` RewardSnapshotHash string `json:"reward_snapshot_hash"` RewardName string `json:"reward_name"` RewardItems []rewardItemDTO `json:"reward_items"` EarningRegionID int64 `json:"earning_region_id"` AttributionAtMS int64 `json:"attribution_at_ms"` User *activityTemplateUserDTO `json:"user,omitempty"` } type activityTemplateUserDTO struct { DisplayUserID string `json:"display_user_id"` Username string `json:"username"` Avatar string `json:"avatar"` } func rankPeriodFromProto(item *activityv1.ActivityTemplateRankPeriod) rankPeriodDTO { if item == nil { return rankPeriodDTO{} } return rankPeriodDTO{ TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), VersionNo: item.GetVersionNo(), BoardType: item.GetBoardType(), PeriodKey: item.GetPeriodKey(), PeriodStartMS: item.GetPeriodStartMs(), PeriodEndMS: item.GetPeriodEndMs(), SettleAfterMS: item.GetSettleAfterMs(), Status: item.GetStatus(), SettledAtMS: item.GetSettledAtMs(), } } func leaderboardEntryFromProto(item *activityv1.ActivityTemplateLeaderboardEntry, users map[int64]*userclient.User) leaderboardEntryDTO { if item == nil { return leaderboardEntryDTO{} } out := leaderboardEntryDTO{ RankNo: item.GetRankNo(), UserID: item.GetUserId(), Score: item.GetScore(), GiftCount: item.GetGiftCount(), CoinAmount: item.GetCoinAmount(), FirstScoredAtMS: item.GetFirstScoredAtMs(), Snapshot: item.GetSnapshot(), } out.User = activityTemplateUserFromClient(users[item.GetUserId()]) return out } func rewardJobFromProto(item *activityv1.ActivityTemplateRewardJob, users map[int64]*userclient.User) rewardJobDTO { if item == nil { return rewardJobDTO{} } out := rewardJobDTO{ RewardJobID: item.GetRewardJobId(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), VersionNo: item.GetVersionNo(), BoardType: item.GetBoardType(), PeriodKey: item.GetPeriodKey(), RankNo: item.GetRankNo(), UserID: item.GetUserId(), Score: item.GetScore(), ResourceGroupID: item.GetResourceGroupId(), WalletCommandID: item.GetWalletCommandId(), WalletGrantID: item.GetWalletGrantId(), Status: item.GetStatus(), FailureReason: item.GetFailureReason(), AttemptCount: item.GetAttemptCount(), MaxAttempts: item.GetMaxAttempts(), NextRetryAtMS: item.GetNextRetryAtMs(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), GrantedAtMS: item.GetGrantedAtMs(), RewardSnapshotID: item.GetRewardSnapshotId(), RewardSnapshotHash: item.GetRewardSnapshotHash(), RewardName: item.GetRewardName(), RewardItems: rewardItemsFromProto(item.GetRewardItems()), } out.User = activityTemplateUserFromClient(users[item.GetUserId()]) return out } func taskClaimFromProto(item *activityv1.ActivityTemplateTaskClaim, users map[int64]*userclient.User) taskClaimDTO { if item == nil { return taskClaimDTO{RewardItems: []rewardItemDTO{}} } out := taskClaimDTO{ ClaimID: item.GetClaimId(), CommandID: item.GetCommandId(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), VersionNo: item.GetVersionNo(), TaskDay: item.GetTaskDay(), TaskKey: item.GetTaskKey(), UserID: item.GetUserId(), RewardResourceGroupID: item.GetRewardResourceGroupId(), WalletCommandID: item.GetWalletCommandId(), WalletGrantID: item.GetWalletGrantId(), Status: item.GetStatus(), FailureReason: item.GetFailureReason(), AttemptCount: item.GetAttemptCount(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), GrantedAtMS: item.GetGrantedAtMs(), RewardSnapshotID: item.GetRewardSnapshotId(), RewardSnapshotHash: item.GetRewardSnapshotHash(), RewardName: item.GetRewardName(), RewardItems: rewardItemsFromProto(item.GetRewardItems()), EarningRegionID: item.GetEarningRegionId(), AttributionAtMS: item.GetAttributionAtMs(), } out.User = activityTemplateUserFromClient(users[item.GetUserId()]) return out } func rewardItemsFromProto(items []*activityv1.ActivityTemplateRewardItem) []rewardItemDTO { out := make([]rewardItemDTO, 0, len(items)) for _, item := range items { if item == nil { continue } out = append(out, rewardItemDTO{ ItemType: item.GetItemType(), ResourceID: item.GetResourceId(), ResourceType: item.GetResourceType(), Name: item.GetName(), IconURL: item.GetIconUrl(), Quantity: item.GetQuantity(), DurationMS: item.GetDurationMs(), WalletAssetType: item.GetWalletAssetType(), WalletAssetAmount: item.GetWalletAssetAmount(), SortOrder: item.GetSortOrder(), }) } return out } func activityTemplateUserFromClient(item *userclient.User) *activityTemplateUserDTO { if item == nil { return nil } return &activityTemplateUserDTO{DisplayUserID: item.DisplayUserID, Username: item.Username, Avatar: item.Avatar} } func summaryFromProto(item *activityv1.ActivityTemplateSummary) templateSummaryDTO { if item == nil { return templateSummaryDTO{RegionIDs: []int64{}} } return templateSummaryDTO{ AppCode: item.GetAppCode(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), Name: item.GetName(), ActivityType: item.GetActivityType(), Status: item.GetStatus(), LifecycleStatus: item.GetLifecycleStatus(), StartMS: item.GetStartMs(), EndMS: item.GetEndMs(), AllRegions: item.GetAllRegions(), RegionIDs: cloneInt64Slice(item.GetRegionIds()), Revision: item.GetRevision(), PublishedVersion: item.GetPublishedVersion(), CreatedByAdminID: item.GetCreatedByAdminId(), UpdatedByAdminID: item.GetUpdatedByAdminId(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func templateFromProto(item *activityv1.ActivityTemplate) templateDTO { if item == nil { return templateDTO{RegionIDs: []int64{}, Locales: []localeDTO{}, Gifts: []giftDTO{}, Tasks: []taskDTO{}, RankRewards: []rankRewardDTO{}, Assets: []assetDTO{}} } out := templateDTO{ AppCode: item.GetAppCode(), TemplateID: item.GetTemplateId(), TemplateCode: item.GetTemplateCode(), Name: item.GetName(), ActivityType: item.GetActivityType(), Status: item.GetStatus(), LifecycleStatus: item.GetLifecycleStatus(), StartMS: item.GetStartMs(), EndMS: item.GetEndMs(), AllRegions: item.GetAllRegions(), RegionIDs: cloneInt64Slice(item.GetRegionIds()), Locales: make([]localeDTO, 0, len(item.GetLocales())), Gifts: make([]giftDTO, 0, len(item.GetGifts())), Tasks: make([]taskDTO, 0, len(item.GetTasks())), RankRewards: make([]rankRewardDTO, 0, len(item.GetRankRewards())), Assets: make([]assetDTO, 0, len(item.GetAssets())), DailyLeaderboardSize: item.GetDailyLeaderboardSize(), TotalLeaderboardSize: item.GetTotalLeaderboardSize(), DisplayConfigJSON: item.GetDisplayConfigJson(), Revision: item.GetRevision(), PublishedVersion: item.GetPublishedVersion(), CreatedByAdminID: item.GetCreatedByAdminId(), UpdatedByAdminID: item.GetUpdatedByAdminId(), PublishedByAdminID: item.GetPublishedByAdminId(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), PublishedAtMS: item.GetPublishedAtMs(), ArchivedAtMS: item.GetArchivedAtMs(), } for _, locale := range item.GetLocales() { out.Locales = append(out.Locales, localeDTO{Locale: locale.GetLocale(), Title: locale.GetTitle(), Rules: locale.GetRules()}) } for _, gift := range item.GetGifts() { out.Gifts = append(out.Gifts, giftDTO{GiftID: gift.GetGiftId(), SortOrder: gift.GetSortOrder(), Name: gift.GetName(), IconURL: gift.GetIconUrl(), CoinPrice: gift.GetCoinPrice(), PriceVersion: gift.GetPriceVersion()}) } for _, task := range item.GetTasks() { out.Tasks = append(out.Tasks, taskDTO{ TaskKey: task.GetTaskKey(), TaskType: task.GetTaskType(), TargetValue: task.GetTargetValue(), RewardResourceGroupID: task.GetRewardResourceGroupId(), SortOrder: task.GetSortOrder(), RewardSnapshotID: task.GetRewardSnapshotId(), RewardSnapshotHash: task.GetRewardSnapshotHash(), RewardName: task.GetRewardName(), RewardItems: rewardItemsFromProto(task.GetRewardItems()), }) } for _, reward := range item.GetRankRewards() { out.RankRewards = append(out.RankRewards, rankRewardDTO{ BoardType: reward.GetBoardType(), RankFrom: reward.GetRankFrom(), RankTo: reward.GetRankTo(), ResourceGroupID: reward.GetResourceGroupId(), SortOrder: reward.GetSortOrder(), RewardSnapshotID: reward.GetRewardSnapshotId(), RewardSnapshotHash: reward.GetRewardSnapshotHash(), RewardName: reward.GetRewardName(), RewardItems: rewardItemsFromProto(reward.GetRewardItems()), }) } for _, asset := range item.GetAssets() { out.Assets = append(out.Assets, assetDTO{AssetKey: asset.GetAssetKey(), Locale: asset.GetLocale(), URL: asset.GetUrl(), MediaType: asset.GetMediaType(), SortOrder: asset.GetSortOrder()}) } return out } func cloneInt64Slice(items []int64) []int64 { out := make([]int64, len(items)) copy(out, items) return out }