2026-07-15 09:43:33 +08:00

326 lines
15 KiB
Go

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,
}
}