2026-07-22 18:36:49 +08:00

123 lines
3.7 KiB
Go

package resource
import (
"context"
"encoding/json"
"fmt"
"strings"
activityv1 "hyapp.local/api/proto/activity/v1"
walletv1 "hyapp.local/api/proto/wallet/v1"
)
const (
resourceGrantNoticeTitle = "System Gift"
resourceGrantNoticeBody = "You received the following system-granted resources."
)
type resourceNoticeSnapshot struct {
ResourceType string
Name string
AssetURL string
PreviewURL string
MetadataJSON string
}
func (h *Handler) createResourceGrantNotice(ctx context.Context, requestID string, appCode string, grant *walletv1.ResourceGrant) error {
if grant == nil {
return fmt.Errorf("resource grant response is empty")
}
return h.createResourceBatchGrantNotice(ctx, requestID, appCode, grant.GetGrantId(), grant.GetTargetUserId(), []*walletv1.ResourceGrant{grant})
}
func (h *Handler) createResourceBatchGrantNotice(ctx context.Context, requestID string, appCode string, commandID string, targetUserID int64, grants []*walletv1.ResourceGrant) error {
if h.activity == nil {
// Tests and isolated local handlers may omit integrations; the production constructor always wires activity-service.
return nil
}
snapshots, err := resourceNoticeSnapshots(grants)
if err != nil {
return err
}
body := resourceGrantNoticeBody
imageURLs := resourceNoticeImageURLs(snapshots)
if len(grants) == 1 && len(snapshots) == 1 && strings.EqualFold(strings.TrimSpace(snapshots[0].ResourceType), resourceTypeVIPTrialCard) {
level := vipTrialLevel(snapshots[0].MetadataJSON)
body = "You received a VIP trial card."
if level > 0 {
body = fmt.Sprintf("You received a VIP%d trial card.", level)
}
imageURLs = nil
}
producerEventID := "resource_grant:" + strings.TrimSpace(commandID)
_, err = h.activity.CreateInboxMessage(ctx, &activityv1.CreateInboxMessageRequest{
Meta: &activityv1.RequestMeta{RequestId: strings.TrimSpace(requestID), Caller: "admin-server", AppCode: strings.TrimSpace(appCode)},
TargetUserId: targetUserID,
Producer: "admin-server",
ProducerEventId: producerEventID,
ProducerEventType: "AdminResourceGranted",
MessageType: "system",
AggregateType: "resource_grant",
AggregateId: strings.TrimSpace(commandID),
Title: resourceGrantNoticeTitle,
Summary: body,
Body: body,
ImageUrl: firstNoticeImageURL(imageURLs),
ImageUrls: imageURLs,
})
return err
}
func resourceNoticeSnapshots(grants []*walletv1.ResourceGrant) ([]resourceNoticeSnapshot, error) {
result := make([]resourceNoticeSnapshot, 0)
for _, grant := range grants {
if grant == nil {
continue
}
for _, item := range grant.GetItems() {
raw := strings.TrimSpace(item.GetResourceSnapshotJson())
if raw == "" || raw == "{}" {
continue
}
var snapshot resourceNoticeSnapshot
if err := json.Unmarshal([]byte(raw), &snapshot); err != nil {
return nil, fmt.Errorf("decode granted resource snapshot: %w", err)
}
result = append(result, snapshot)
}
}
return result, nil
}
func resourceNoticeImageURLs(snapshots []resourceNoticeSnapshot) []string {
result := make([]string, 0, len(snapshots))
for _, snapshot := range snapshots {
url := strings.TrimSpace(snapshot.PreviewURL)
if url == "" {
url = strings.TrimSpace(snapshot.AssetURL)
}
if url == "" {
continue
}
result = append(result, url)
}
return result
}
func vipTrialLevel(metadataJSON string) int32 {
var metadata struct {
VIPLevel int32 `json:"vip_level"`
}
if err := json.Unmarshal([]byte(strings.TrimSpace(metadataJSON)), &metadata); err != nil {
return 0
}
return metadata.VIPLevel
}
func firstNoticeImageURL(imageURLs []string) string {
if len(imageURLs) == 0 {
return ""
}
return imageURLs[0]
}