package grpc import ( "context" "time" activityv1 "hyapp.local/api/proto/activity/v1" "hyapp/pkg/appcode" "hyapp/pkg/xerr" domain "hyapp/services/activity-service/internal/domain/activitytemplate" service "hyapp/services/activity-service/internal/service/activitytemplate" ) // AdminActivityTemplateServer 只把 protobuf 转为领域命令;发布规则、版本和事务都由 service/repository 拥有。 type AdminActivityTemplateServer struct { activityv1.UnimplementedAdminActivityTemplateServiceServer svc *service.Service } func NewAdminActivityTemplateServer(svc *service.Service) *AdminActivityTemplateServer { return &AdminActivityTemplateServer{svc: svc} } func (s *AdminActivityTemplateServer) ListActivityTemplates(ctx context.Context, req *activityv1.ListActivityTemplatesRequest) (*activityv1.ListActivityTemplatesResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) query := domain.ListQuery{ Keyword: req.GetKeyword(), Status: req.GetStatus(), StartMS: req.GetStartMs(), EndMS: req.GetEndMs(), Page: req.GetPage(), PageSize: req.GetPageSize(), } if req.RegionId != nil { value := req.GetRegionId() query.RegionID = &value } if req.AllRegions != nil { value := req.GetAllRegions() query.AllRegions = &value } items, total, err := s.svc.List(ctx, query) if err != nil { return nil, xerr.ToGRPCError(err) } resp := &activityv1.ListActivityTemplatesResponse{ Templates: make([]*activityv1.ActivityTemplateSummary, 0, len(items)), Total: total, ServerTimeMs: time.Now().UTC().UnixMilli(), } for _, item := range items { resp.Templates = append(resp.Templates, activityTemplateSummaryToProto(item)) } return resp, nil } func (s *AdminActivityTemplateServer) CreateActivityTemplate(ctx context.Context, req *activityv1.CreateActivityTemplateRequest) (*activityv1.CreateActivityTemplateResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) item, err := s.svc.Create(ctx, activityTemplateFromProto(req.GetTemplate()), req.GetOperatorAdminId()) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.CreateActivityTemplateResponse{Template: activityTemplateToProto(item)}, nil } func (s *AdminActivityTemplateServer) GetActivityTemplate(ctx context.Context, req *activityv1.GetActivityTemplateRequest) (*activityv1.GetActivityTemplateResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) item, err := s.svc.Get(ctx, req.GetTemplateId()) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.GetActivityTemplateResponse{Template: activityTemplateToProto(item)}, nil } func (s *AdminActivityTemplateServer) UpdateActivityTemplate(ctx context.Context, req *activityv1.UpdateActivityTemplateRequest) (*activityv1.UpdateActivityTemplateResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) item, err := s.svc.Update(ctx, domain.UpdateCommand{ Template: activityTemplateFromProto(req.GetTemplate()), ExpectedRevision: req.GetExpectedRevision(), OperatorAdminID: req.GetOperatorAdminId(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.UpdateActivityTemplateResponse{Template: activityTemplateToProto(item)}, nil } func (s *AdminActivityTemplateServer) SetActivityTemplateStatus(ctx context.Context, req *activityv1.SetActivityTemplateStatusRequest) (*activityv1.SetActivityTemplateStatusResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) item, err := s.svc.SetStatus(ctx, domain.StatusCommand{ TemplateID: req.GetTemplateId(), Status: req.GetStatus(), ExpectedRevision: req.GetExpectedRevision(), OperatorAdminID: req.GetOperatorAdminId(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.SetActivityTemplateStatusResponse{Template: activityTemplateToProto(item)}, nil } func (s *AdminActivityTemplateServer) DeleteActivityTemplate(ctx context.Context, req *activityv1.DeleteActivityTemplateRequest) (*activityv1.DeleteActivityTemplateResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) item, archived, err := s.svc.Delete(ctx, domain.StatusCommand{ TemplateID: req.GetTemplateId(), ExpectedRevision: req.GetExpectedRevision(), OperatorAdminID: req.GetOperatorAdminId(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.DeleteActivityTemplateResponse{Template: activityTemplateToProto(item), Archived: archived}, nil } func (s *AdminActivityTemplateServer) ListActivityTemplateVersions(ctx context.Context, req *activityv1.ListActivityTemplateVersionsRequest) (*activityv1.ListActivityTemplateVersionsResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) items, total, err := s.svc.ListVersions(ctx, req.GetTemplateId(), req.GetPage(), req.GetPageSize()) if err != nil { return nil, xerr.ToGRPCError(err) } resp := &activityv1.ListActivityTemplateVersionsResponse{Versions: make([]*activityv1.ActivityTemplateVersion, 0, len(items)), Total: total} for _, item := range items { resp.Versions = append(resp.Versions, &activityv1.ActivityTemplateVersion{ TemplateId: item.TemplateID, VersionNo: item.VersionNo, Snapshot: activityTemplateToProto(item.Snapshot), PublishedByAdminId: item.PublishedByAdminID, PublishedAtMs: item.PublishedAtMS, RuntimeFromMs: item.RuntimeFromMS, RuntimeToMs: item.RuntimeToMS, }) } return resp, nil } func (s *AdminActivityTemplateServer) CloneActivityTemplate(ctx context.Context, req *activityv1.CloneActivityTemplateRequest) (*activityv1.CloneActivityTemplateResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) item, err := s.svc.Clone(ctx, domain.CloneCommand{ SourceTemplateID: req.GetSourceTemplateId(), SourceVersion: req.GetSourceVersion(), TemplateCode: req.GetTemplateCode(), Name: req.GetName(), OperatorAdminID: req.GetOperatorAdminId(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.CloneActivityTemplateResponse{Template: activityTemplateToProto(item)}, nil } func (s *AdminActivityTemplateServer) ValidateActivityTemplate(ctx context.Context, req *activityv1.ValidateActivityTemplateRequest) (*activityv1.ValidateActivityTemplateResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) issues, err := s.svc.Validate(ctx, activityTemplateFromProto(req.GetTemplate()), req.GetForPublish()) if err != nil { return nil, xerr.ToGRPCError(err) } resp := &activityv1.ValidateActivityTemplateResponse{Valid: len(issues) == 0, Issues: make([]*activityv1.ActivityTemplateValidationIssue, 0, len(issues))} for _, issue := range issues { resp.Issues = append(resp.Issues, &activityv1.ActivityTemplateValidationIssue{Field: issue.Field, Code: issue.Code, Message: issue.Message}) } return resp, nil } func activityTemplateFromProto(item *activityv1.ActivityTemplate) domain.Template { if item == nil { return domain.Template{} } out := domain.Template{ 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: append([]int64(nil), item.GetRegionIds()...), 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, domain.Locale{Locale: locale.GetLocale(), Title: locale.GetTitle(), Rules: locale.GetRules()}) } for _, gift := range item.GetGifts() { out.Gifts = append(out.Gifts, domain.Gift{ 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, domain.Task{ TaskKey: task.GetTaskKey(), TaskType: task.GetTaskType(), TargetValue: task.GetTargetValue(), RewardResourceGroupID: task.GetRewardResourceGroupId(), SortOrder: task.GetSortOrder(), RewardSnapshot: activityTemplateRewardSnapshotFromProto(task.GetRewardSnapshotId(), task.GetRewardSnapshotHash(), task.GetRewardName(), task.GetRewardItems()), }) } for _, reward := range item.GetRankRewards() { out.RankRewards = append(out.RankRewards, domain.RankReward{ BoardType: reward.GetBoardType(), RankFrom: reward.GetRankFrom(), RankTo: reward.GetRankTo(), ResourceGroupID: reward.GetResourceGroupId(), SortOrder: reward.GetSortOrder(), RewardSnapshot: activityTemplateRewardSnapshotFromProto(reward.GetRewardSnapshotId(), reward.GetRewardSnapshotHash(), reward.GetRewardName(), reward.GetRewardItems()), }) } for _, asset := range item.GetAssets() { out.Assets = append(out.Assets, domain.Asset{ AssetKey: asset.GetAssetKey(), Locale: asset.GetLocale(), URL: asset.GetUrl(), MediaType: asset.GetMediaType(), SortOrder: asset.GetSortOrder(), }) } return out } func activityTemplateToProto(item domain.Template) *activityv1.ActivityTemplate { if item.TemplateID == "" && item.TemplateCode == "" && item.Name == "" { return nil } out := &activityv1.ActivityTemplate{ AppCode: item.AppCode, TemplateId: item.TemplateID, TemplateCode: item.TemplateCode, Name: item.Name, ActivityType: item.ActivityType, Status: item.Status, LifecycleStatus: item.LifecycleStatus, StartMs: item.StartMS, EndMs: item.EndMS, AllRegions: item.AllRegions, RegionIds: append([]int64(nil), item.RegionIDs...), Locales: make([]*activityv1.ActivityTemplateLocale, 0, len(item.Locales)), Gifts: make([]*activityv1.ActivityTemplateGift, 0, len(item.Gifts)), Tasks: make([]*activityv1.ActivityTemplateTask, 0, len(item.Tasks)), DailyLeaderboardSize: item.DailyLeaderboardSize, TotalLeaderboardSize: item.TotalLeaderboardSize, RankRewards: make([]*activityv1.ActivityTemplateRankReward, 0, len(item.RankRewards)), Assets: make([]*activityv1.ActivityTemplateAsset, 0, len(item.Assets)), DisplayConfigJson: item.DisplayConfigJSON, Revision: item.Revision, PublishedVersion: item.PublishedVersion, CreatedByAdminId: item.CreatedByAdminID, UpdatedByAdminId: item.UpdatedByAdminID, PublishedByAdminId: item.PublishedByAdminID, CreatedAtMs: item.CreatedAtMS, UpdatedAtMs: item.UpdatedAtMS, PublishedAtMs: item.PublishedAtMS, ArchivedAtMs: item.ArchivedAtMS, } for _, locale := range item.Locales { out.Locales = append(out.Locales, &activityv1.ActivityTemplateLocale{Locale: locale.Locale, Title: locale.Title, Rules: locale.Rules}) } for _, gift := range item.Gifts { out.Gifts = append(out.Gifts, &activityv1.ActivityTemplateGift{ GiftId: gift.GiftID, SortOrder: gift.SortOrder, Name: gift.Name, IconUrl: gift.IconURL, CoinPrice: gift.CoinPrice, PriceVersion: gift.PriceVersion, }) } for _, task := range item.Tasks { out.Tasks = append(out.Tasks, &activityv1.ActivityTemplateTask{ TaskKey: task.TaskKey, TaskType: task.TaskType, TargetValue: task.TargetValue, RewardResourceGroupId: task.RewardResourceGroupID, SortOrder: task.SortOrder, RewardSnapshotId: task.RewardSnapshot.SnapshotID, RewardSnapshotHash: task.RewardSnapshot.SnapshotHash, RewardName: task.RewardSnapshot.Name, RewardItems: activityTemplateRewardItemsToProto(task.RewardSnapshot.Items), }) } for _, reward := range item.RankRewards { out.RankRewards = append(out.RankRewards, &activityv1.ActivityTemplateRankReward{ BoardType: reward.BoardType, RankFrom: reward.RankFrom, RankTo: reward.RankTo, ResourceGroupId: reward.ResourceGroupID, SortOrder: reward.SortOrder, RewardSnapshotId: reward.RewardSnapshot.SnapshotID, RewardSnapshotHash: reward.RewardSnapshot.SnapshotHash, RewardName: reward.RewardSnapshot.Name, RewardItems: activityTemplateRewardItemsToProto(reward.RewardSnapshot.Items), }) } for _, asset := range item.Assets { out.Assets = append(out.Assets, &activityv1.ActivityTemplateAsset{ AssetKey: asset.AssetKey, Locale: asset.Locale, Url: asset.URL, MediaType: asset.MediaType, SortOrder: asset.SortOrder, }) } return out } func activityTemplateRewardItemsToProto(items []domain.RewardItem) []*activityv1.ActivityTemplateRewardItem { out := make([]*activityv1.ActivityTemplateRewardItem, 0, len(items)) for _, item := range items { out = append(out, &activityv1.ActivityTemplateRewardItem{ ItemType: item.ItemType, ResourceId: item.ResourceID, ResourceType: item.ResourceType, Name: item.Name, IconUrl: item.IconURL, Quantity: item.Quantity, DurationMs: item.DurationMS, WalletAssetType: item.WalletAssetType, WalletAssetAmount: item.WalletAssetAmount, SortOrder: item.SortOrder, }) } return out } func activityTemplateRewardSnapshotFromProto(snapshotID, snapshotHash, name string, items []*activityv1.ActivityTemplateRewardItem) domain.RewardSnapshot { out := domain.RewardSnapshot{SnapshotID: snapshotID, SnapshotHash: snapshotHash, Name: name, Items: make([]domain.RewardItem, 0, len(items))} for _, item := range items { out.Items = append(out.Items, domain.RewardItem{ 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 activityTemplateSummaryToProto(item domain.Summary) *activityv1.ActivityTemplateSummary { return &activityv1.ActivityTemplateSummary{ AppCode: item.AppCode, TemplateId: item.TemplateID, TemplateCode: item.TemplateCode, Name: item.Name, ActivityType: item.ActivityType, Status: item.Status, LifecycleStatus: item.LifecycleStatus, StartMs: item.StartMS, EndMs: item.EndMS, AllRegions: item.AllRegions, RegionIds: append([]int64(nil), item.RegionIDs...), Revision: item.Revision, PublishedVersion: item.PublishedVersion, CreatedByAdminId: item.CreatedByAdminID, UpdatedByAdminId: item.UpdatedByAdminID, CreatedAtMs: item.CreatedAtMS, UpdatedAtMs: item.UpdatedAtMS, } }