129 lines
3.7 KiB
Go
129 lines
3.7 KiB
Go
package events
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
ForumPostLikedEventType = "forum.post.liked"
|
|
ForumPostImportedEventType = "forum.post.imported"
|
|
ForumRewardEventVersion = "v1"
|
|
|
|
ForumRewardSourceLike = "forum_like"
|
|
ForumRewardSourceImport = "forum_import"
|
|
)
|
|
|
|
// ForumPostRewardPayload 是计划广场作者奖励事件的统一载荷。
|
|
//
|
|
// 职责边界:
|
|
// 1. 只描述“哪个帖子因什么互动触发了作者奖励”,不直接携带最终 Token 数额;
|
|
// 2. source 负责表达奖励来源,真正的奖励规则仍由 token-store 自己解析;
|
|
// 3. event_id 必须稳定,供 outbox 重试和下游记账幂等共同使用。
|
|
type ForumPostRewardPayload struct {
|
|
EventID string `json:"event_id"`
|
|
PostID uint64 `json:"post_id"`
|
|
ImportID uint64 `json:"import_id"`
|
|
AuthorUserID uint64 `json:"author_user_id"`
|
|
ActorUserID uint64 `json:"actor_user_id"`
|
|
RewardReceiverUserID uint64 `json:"reward_receiver_user_id"`
|
|
Source string `json:"source"`
|
|
OccurredAt time.Time `json:"occurred_at"`
|
|
}
|
|
|
|
func NewForumPostLikedPayload(postID uint64, authorUserID uint64, actorUserID uint64, occurredAt time.Time) ForumPostRewardPayload {
|
|
return newForumPostRewardPayload(
|
|
ForumPostLikedEventType,
|
|
ForumRewardSourceLike,
|
|
postID,
|
|
0,
|
|
authorUserID,
|
|
actorUserID,
|
|
occurredAt,
|
|
)
|
|
}
|
|
|
|
func NewForumPostImportedPayload(postID uint64, importID uint64, authorUserID uint64, actorUserID uint64, occurredAt time.Time) ForumPostRewardPayload {
|
|
return newForumPostRewardPayload(
|
|
ForumPostImportedEventType,
|
|
ForumRewardSourceImport,
|
|
postID,
|
|
importID,
|
|
authorUserID,
|
|
actorUserID,
|
|
occurredAt,
|
|
)
|
|
}
|
|
|
|
func newForumPostRewardPayload(
|
|
eventType string,
|
|
source string,
|
|
postID uint64,
|
|
importID uint64,
|
|
authorUserID uint64,
|
|
actorUserID uint64,
|
|
occurredAt time.Time,
|
|
) ForumPostRewardPayload {
|
|
if occurredAt.IsZero() {
|
|
occurredAt = time.Now()
|
|
}
|
|
return ForumPostRewardPayload{
|
|
EventID: ForumRewardEventID(eventType, postID, actorUserID),
|
|
PostID: postID,
|
|
ImportID: importID,
|
|
AuthorUserID: authorUserID,
|
|
ActorUserID: actorUserID,
|
|
RewardReceiverUserID: authorUserID,
|
|
Source: strings.TrimSpace(source),
|
|
OccurredAt: occurredAt,
|
|
}
|
|
}
|
|
|
|
func ForumRewardEventID(eventType string, postID uint64, actorUserID uint64) string {
|
|
return fmt.Sprintf("%s:%d:%d", strings.TrimSpace(eventType), postID, actorUserID)
|
|
}
|
|
|
|
// EventType 根据 source 反推出当前奖励事件类型。
|
|
func (p ForumPostRewardPayload) EventType() string {
|
|
switch strings.TrimSpace(p.Source) {
|
|
case ForumRewardSourceLike:
|
|
return ForumPostLikedEventType
|
|
case ForumRewardSourceImport:
|
|
return ForumPostImportedEventType
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (p ForumPostRewardPayload) MessageKey() string {
|
|
return strings.TrimSpace(p.EventID)
|
|
}
|
|
|
|
func (p ForumPostRewardPayload) AggregateID() string {
|
|
return fmt.Sprintf("post:%d", p.PostID)
|
|
}
|
|
|
|
func (p ForumPostRewardPayload) Validate() error {
|
|
if strings.TrimSpace(p.EventID) == "" {
|
|
return errors.New("forum reward event_id 不能为空")
|
|
}
|
|
if strings.TrimSpace(p.EventType()) == "" {
|
|
return errors.New("forum reward source 非法")
|
|
}
|
|
if p.PostID == 0 {
|
|
return errors.New("forum reward post_id 不能为空")
|
|
}
|
|
if p.AuthorUserID == 0 || p.ActorUserID == 0 || p.RewardReceiverUserID == 0 {
|
|
return errors.New("forum reward user_id 不能为空")
|
|
}
|
|
if strings.TrimSpace(p.Source) == ForumRewardSourceImport && p.ImportID == 0 {
|
|
return errors.New("forum import reward import_id 不能为空")
|
|
}
|
|
if p.OccurredAt.IsZero() {
|
|
return errors.New("forum reward occurred_at 不能为空")
|
|
}
|
|
return nil
|
|
}
|