254 lines
9.1 KiB
Go
254 lines
9.1 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
activityv1 "hyapp.local/api/proto/activity/v1"
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
messagedomain "hyapp/services/activity-service/internal/domain/message"
|
|
messageservice "hyapp/services/activity-service/internal/service/message"
|
|
)
|
|
|
|
// MessageServer adapts the message inbox owner to gRPC without mixing it into activity status APIs.
|
|
type MessageServer struct {
|
|
activityv1.UnimplementedMessageInboxServiceServer
|
|
|
|
svc *messageservice.Service
|
|
}
|
|
|
|
// NewMessageServer creates the gRPC adapter for system/activity inbox RPCs.
|
|
func NewMessageServer(svc *messageservice.Service) *MessageServer {
|
|
return &MessageServer{svc: svc}
|
|
}
|
|
|
|
func (s *MessageServer) ListMessageTabs(ctx context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
sections, err := s.svc.ListMessageTabs(ctx, req.GetUserId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
result := make([]*activityv1.MessageTabSection, 0, len(sections))
|
|
for _, section := range sections {
|
|
result = append(result, &activityv1.MessageTabSection{
|
|
Section: section.Section,
|
|
Title: section.Title,
|
|
UnreadCount: section.UnreadCount,
|
|
Source: section.Source,
|
|
})
|
|
}
|
|
return &activityv1.ListMessageTabsResponse{Sections: result}, nil
|
|
}
|
|
|
|
func (s *MessageServer) ListInboxMessages(ctx context.Context, req *activityv1.ListInboxMessagesRequest) (*activityv1.ListInboxMessagesResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
messages, nextPageToken, err := s.svc.ListInboxMessages(ctx, req.GetUserId(), req.GetSection(), req.GetPageSize(), req.GetPageToken())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
items := make([]*activityv1.InboxMessage, 0, len(messages))
|
|
for _, message := range messages {
|
|
items = append(items, inboxMessageProto(message))
|
|
}
|
|
return &activityv1.ListInboxMessagesResponse{Section: req.GetSection(), Items: items, NextPageToken: nextPageToken}, nil
|
|
}
|
|
|
|
func (s *MessageServer) MarkInboxMessageRead(ctx context.Context, req *activityv1.MarkInboxMessageReadRequest) (*activityv1.MarkInboxMessageReadResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
message, err := s.svc.MarkInboxMessageRead(ctx, req.GetUserId(), req.GetMessageId())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.MarkInboxMessageReadResponse{MessageId: message.MessageID, Read: true, ReadAtMs: message.ReadAtMS}, nil
|
|
}
|
|
|
|
func (s *MessageServer) MarkInboxSectionRead(ctx context.Context, req *activityv1.MarkInboxSectionReadRequest) (*activityv1.MarkInboxSectionReadResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
count, err := s.svc.MarkInboxSectionRead(ctx, req.GetUserId(), req.GetSection())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.MarkInboxSectionReadResponse{Section: req.GetSection(), ReadCount: count}, nil
|
|
}
|
|
|
|
func (s *MessageServer) DeleteInboxMessage(ctx context.Context, req *activityv1.DeleteInboxMessageRequest) (*activityv1.DeleteInboxMessageResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
if err := s.svc.DeleteInboxMessage(ctx, req.GetUserId(), req.GetMessageId()); err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.DeleteInboxMessageResponse{MessageId: req.GetMessageId(), Deleted: true}, nil
|
|
}
|
|
|
|
func (s *MessageServer) CreateInboxMessage(ctx context.Context, req *activityv1.CreateInboxMessageRequest) (*activityv1.CreateInboxMessageResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
actions, err := inboxActionsFromProto(req.GetActions())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(xerr.New(xerr.InvalidArgument, "actions JSON is invalid"))
|
|
}
|
|
message, created, err := s.svc.CreateInboxMessage(ctx, messagedomain.CreateInput{
|
|
TargetUserID: req.GetTargetUserId(),
|
|
Producer: req.GetProducer(),
|
|
ProducerEventID: req.GetProducerEventId(),
|
|
ProducerEventType: req.GetProducerEventType(),
|
|
MessageType: req.GetMessageType(),
|
|
AggregateType: req.GetAggregateType(),
|
|
AggregateID: req.GetAggregateId(),
|
|
TemplateID: req.GetTemplateId(),
|
|
TemplateVersion: req.GetTemplateVersion(),
|
|
Title: req.GetTitle(),
|
|
Summary: req.GetSummary(),
|
|
Body: req.GetBody(),
|
|
IconURL: req.GetIconUrl(),
|
|
ImageURL: req.GetImageUrl(),
|
|
ImageURLs: req.GetImageUrls(),
|
|
RewardItems: inboxRewardItemsFromProto(req.GetRewardItems()),
|
|
Actions: actions,
|
|
ActionType: req.GetActionType(),
|
|
ActionParam: req.GetActionParam(),
|
|
Priority: req.GetPriority(),
|
|
SentAtMS: req.GetSentAtMs(),
|
|
ExpireAtMS: req.GetExpireAtMs(),
|
|
MetadataJSON: req.GetMetadataJson(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.CreateInboxMessageResponse{MessageId: message.MessageID, Created: created}, nil
|
|
}
|
|
|
|
func (s *MessageServer) CreateFanoutJob(ctx context.Context, req *activityv1.CreateFanoutJobRequest) (*activityv1.CreateFanoutJobResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
job, created, err := s.svc.CreateFanoutJob(ctx, messagedomain.CreateFanoutInput{
|
|
CommandID: req.GetCommandId(),
|
|
MessageType: req.GetMessageType(),
|
|
TargetScope: req.GetTargetScope(),
|
|
TargetFilterJSON: req.GetTargetFilterJson(),
|
|
TemplateSnapshotJSON: req.GetTemplateSnapshotJson(),
|
|
BatchSize: req.GetBatchSize(),
|
|
CreatedBy: req.GetCreatedBy(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &activityv1.CreateFanoutJobResponse{JobId: job.JobID, Status: job.Status, Created: created}, nil
|
|
}
|
|
|
|
func inboxMessageProto(message messagedomain.InboxMessage) *activityv1.InboxMessage {
|
|
imageURLs := message.ImageURLs
|
|
if len(imageURLs) == 0 && strings.TrimSpace(message.ImageURL) != "" {
|
|
imageURLs = []string{strings.TrimSpace(message.ImageURL)}
|
|
}
|
|
return &activityv1.InboxMessage{
|
|
MessageId: message.MessageID,
|
|
Section: message.MessageType,
|
|
Title: message.Title,
|
|
Summary: message.Summary,
|
|
Body: message.Body,
|
|
IconUrl: message.IconURL,
|
|
ImageUrl: message.ImageURL,
|
|
ImageUrls: imageURLs,
|
|
RewardItems: inboxRewardItemsToProto(message.RewardItems),
|
|
Actions: inboxActionsToProto(message.Actions),
|
|
ActionType: message.ActionType,
|
|
ActionParam: message.ActionParam,
|
|
Read: message.Read(),
|
|
SentAtMs: message.SentAtMS,
|
|
}
|
|
}
|
|
|
|
func inboxActionsFromProto(items []*activityv1.InboxAction) ([]messagedomain.InboxAction, error) {
|
|
result := make([]messagedomain.InboxAction, 0, len(items))
|
|
for _, item := range items {
|
|
if item == nil {
|
|
continue
|
|
}
|
|
query := map[string]any{}
|
|
if raw := strings.TrimSpace(item.GetApi().GetQueryJson()); raw != "" {
|
|
if err := json.Unmarshal([]byte(raw), &query); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
var body any
|
|
if raw := strings.TrimSpace(item.GetApi().GetBodyJson()); raw != "" {
|
|
if err := json.Unmarshal([]byte(raw), &body); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
result = append(result, messagedomain.InboxAction{
|
|
Action: item.GetAction(),
|
|
Label: item.GetLabel(),
|
|
Style: item.GetStyle(),
|
|
API: messagedomain.InboxActionAPI{
|
|
Method: item.GetApi().GetMethod(),
|
|
Path: item.GetApi().GetPath(),
|
|
Query: query,
|
|
Body: body,
|
|
},
|
|
})
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func inboxActionsToProto(items []messagedomain.InboxAction) []*activityv1.InboxAction {
|
|
result := make([]*activityv1.InboxAction, 0, len(items))
|
|
for _, item := range items {
|
|
queryJSON := ""
|
|
if len(item.API.Query) > 0 {
|
|
if encoded, err := json.Marshal(item.API.Query); err == nil {
|
|
queryJSON = string(encoded)
|
|
}
|
|
}
|
|
bodyJSON := ""
|
|
if item.API.Body != nil {
|
|
if encoded, err := json.Marshal(item.API.Body); err == nil {
|
|
bodyJSON = string(encoded)
|
|
}
|
|
}
|
|
result = append(result, &activityv1.InboxAction{
|
|
Action: item.Action,
|
|
Label: item.Label,
|
|
Style: item.Style,
|
|
Api: &activityv1.InboxActionAPI{
|
|
Method: item.API.Method,
|
|
Path: item.API.Path,
|
|
QueryJson: queryJSON,
|
|
BodyJson: bodyJSON,
|
|
},
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func inboxRewardItemsFromProto(items []*activityv1.InboxRewardItem) []messagedomain.RewardItem {
|
|
result := make([]messagedomain.RewardItem, 0, len(items))
|
|
for _, item := range items {
|
|
if item == nil {
|
|
continue
|
|
}
|
|
result = append(result, messagedomain.RewardItem{
|
|
RewardType: item.GetRewardType(),
|
|
Name: item.GetName(),
|
|
ImageURL: item.GetImageUrl(),
|
|
Quantity: item.GetQuantity(),
|
|
DurationDays: item.GetDurationDays(),
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
func inboxRewardItemsToProto(items []messagedomain.RewardItem) []*activityv1.InboxRewardItem {
|
|
result := make([]*activityv1.InboxRewardItem, 0, len(items))
|
|
for _, item := range items {
|
|
result = append(result, &activityv1.InboxRewardItem{
|
|
RewardType: item.RewardType,
|
|
Name: item.Name,
|
|
ImageUrl: item.ImageURL,
|
|
Quantity: item.Quantity,
|
|
DurationDays: item.DurationDays,
|
|
})
|
|
}
|
|
return result
|
|
}
|