修复(#126): 修复家庭组邀请记录漏查验收分支
Build docker and publish / build (20.15.1) (push) Failing after 20m3s
Build docker and publish / build (20.15.1) (pull_request) Failing after 21m10s

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-05-29 20:35:37 -07:00
parent e17dc4a273
commit e5d6539d79
4 changed files with 287 additions and 44 deletions
@@ -5,7 +5,6 @@ import (
"encoding/json"
logmodel "github.com/perfect-panel/server/internal/model/log"
ordermodel "github.com/perfect-panel/server/internal/model/order"
"github.com/perfect-panel/server/internal/model/user"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
@@ -14,6 +13,7 @@ import (
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"gorm.io/gorm"
)
const (
@@ -45,8 +45,10 @@ type parsedInviteRecordLog struct {
}
type inviteOrderUser struct {
OrderNo string `gorm:"column:order_no"`
UserId int64 `gorm:"column:user_id"`
OrderNo string `gorm:"column:order_no"`
UserId int64 `gorm:"column:user_id"`
SubscriptionUserId int64 `gorm:"column:subscription_user_id"`
RefererId int64 `gorm:"column:referer_id"`
}
// Get invite gift records
@@ -67,9 +69,17 @@ func (l *GetInviteRecordsLogic) GetInviteRecords(req *types.GetInviteRecordsRequ
normalizeInviteRecordsPagination(req)
visibleUserIds, err := l.resolveInviteRecordVisibleUserIds(u.Id)
if err != nil {
l.Errorw("[GetInviteRecords] resolve visible users failed",
logger.Field("error", err.Error()),
logger.Field("user_id", u.Id))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "resolve visible users failed: %v", err.Error())
}
query := l.svcCtx.DB.WithContext(l.ctx).
Table("system_logs").
Where("type = ? AND object_id = ?", logmodel.TypeGift.Uint8(), u.Id).
Where("type = ? AND object_id IN ?", logmodel.TypeGift.Uint8(), visibleUserIds).
Where("JSON_VALID(content) = 1").
Where("JSON_UNQUOTE(JSON_EXTRACT(content, '$.remark')) = ?", "邀请赠送")
if req.StartTime > 0 {
@@ -79,20 +89,10 @@ func (l *GetInviteRecordsLogic) GetInviteRecords(req *types.GetInviteRecordsRequ
query = query.Where("created_at <= FROM_UNIXTIME(?)", req.EndTime)
}
var total int64
if err = query.Count(&total).Error; err != nil {
l.Errorw("[GetInviteRecords] count logs failed",
logger.Field("error", err.Error()),
logger.Field("user_id", u.Id))
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count logs failed: %v", err.Error())
}
var logs []inviteRecordLog
if err = query.
Select("id, object_id, content, CAST(UNIX_TIMESTAMP(created_at) * 1000 AS SIGNED) AS created_at").
Order("created_at DESC, id DESC").
Limit(req.Size).
Offset((req.Page - 1) * req.Size).
Scan(&logs).Error; err != nil {
l.Errorw("[GetInviteRecords] query logs failed",
logger.Field("error", err.Error()),
@@ -102,7 +102,7 @@ func (l *GetInviteRecordsLogic) GetInviteRecords(req *types.GetInviteRecordsRequ
parsedLogs, orderNos := l.parseInviteRecordContents(logs)
if len(logs) == 0 || len(parsedLogs) == 0 {
return &types.GetInviteRecordsResponse{Total: total, List: []types.InviteRecord{}}, nil
return &types.GetInviteRecordsResponse{Total: 0, List: []types.InviteRecord{}}, nil
}
orders, err := l.queryInviteRecordOrders(orderNos)
@@ -113,10 +113,15 @@ func (l *GetInviteRecordsLogic) GetInviteRecords(req *types.GetInviteRecordsRequ
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query orders failed: %v", err.Error())
}
list := make([]types.InviteRecord, 0, len(parsedLogs))
allRecords := make([]types.InviteRecord, 0, len(parsedLogs))
for _, parsed := range parsedLogs {
content := parsed.content
logItem := parsed.log
orderInfo, hasOrder := orders[content.OrderNo]
if !l.canViewInviteRecord(u.Id, logItem.ObjectId, hasOrder, orderInfo) {
continue
}
record := types.InviteRecord{
Role: inviteRecordRoleInviter,
GiftDays: content.Amount,
@@ -124,7 +129,7 @@ func (l *GetInviteRecordsLogic) GetInviteRecords(req *types.GetInviteRecordsRequ
CreatedAt: logItem.CreatedAt,
}
if orderInfo, ok := orders[content.OrderNo]; ok {
if hasOrder {
peerId := orderInfo.UserId
if orderInfo.UserId == u.Id {
record.Role = inviteRecordRoleInvitee
@@ -135,15 +140,56 @@ func (l *GetInviteRecordsLogic) GetInviteRecords(req *types.GetInviteRecordsRequ
}
}
list = append(list, record)
allRecords = append(allRecords, record)
}
total := int64(len(allRecords))
list := paginateInviteRecords(allRecords, req.Page, req.Size)
return &types.GetInviteRecordsResponse{
Total: total,
List: list,
}, nil
}
func (l *GetInviteRecordsLogic) resolveInviteRecordVisibleUserIds(currentUserId int64) ([]int64, error) {
visibleUserIds := []int64{currentUserId}
var relation struct {
FamilyId int64 `gorm:"column:family_id"`
Role uint8 `gorm:"column:role"`
OwnerUserId int64 `gorm:"column:owner_user_id"`
}
err := l.svcCtx.DB.WithContext(l.ctx).
Model(&user.UserFamilyMember{}).
Select("user_family_member.family_id, user_family_member.role, user_family.owner_user_id").
Joins("JOIN user_family ON user_family.id = user_family_member.family_id AND user_family.deleted_at IS NULL AND user_family.status = ?", user.FamilyStatusActive).
Where("user_family_member.user_id = ? AND user_family_member.status = ? AND user_family_member.deleted_at IS NULL", currentUserId, user.FamilyMemberActive).
First(&relation).Error
if err == nil {
if relation.Role != user.FamilyRoleOwner && relation.OwnerUserId > 0 && relation.OwnerUserId != currentUserId {
visibleUserIds = append(visibleUserIds, relation.OwnerUserId)
}
return visibleUserIds, nil
}
if errors.Is(err, gorm.ErrRecordNotFound) {
return visibleUserIds, nil
}
return nil, err
}
func (l *GetInviteRecordsLogic) canViewInviteRecord(currentUserId, logObjectId int64, hasOrder bool, orderInfo inviteOrderUser) bool {
if logObjectId == currentUserId {
if hasOrder {
return orderInfo.UserId == currentUserId || orderInfo.RefererId == currentUserId
}
return true
}
if !hasOrder {
return false
}
return orderInfo.UserId == currentUserId && orderInfo.SubscriptionUserId == logObjectId
}
func normalizeInviteRecordsPagination(req *types.GetInviteRecordsRequest) {
if req.Page < 1 {
req.Page = 1
@@ -156,6 +202,18 @@ func normalizeInviteRecordsPagination(req *types.GetInviteRecordsRequest) {
}
}
func paginateInviteRecords(records []types.InviteRecord, page, size int) []types.InviteRecord {
start := (page - 1) * size
if start >= len(records) {
return []types.InviteRecord{}
}
end := start + size
if end > len(records) {
end = len(records)
}
return records[start:end]
}
func (l *GetInviteRecordsLogic) parseInviteRecordContents(logs []inviteRecordLog) ([]parsedInviteRecordLog, []string) {
parsedLogs := make([]parsedInviteRecordLog, 0, len(logs))
orderNos := make([]string, 0, len(logs))
@@ -183,9 +241,10 @@ func (l *GetInviteRecordsLogic) queryInviteRecordOrders(orderNos []string) (map[
var orderData []inviteOrderUser
err := l.svcCtx.DB.WithContext(l.ctx).
Model(&ordermodel.Order{}).
Select("order_no, user_id").
Where("order_no IN ?", orderNos).
Table("`order`").
Select("`order`.order_no, `order`.user_id, `order`.subscription_user_id, invitee.referer_id").
Joins("LEFT JOIN user invitee ON invitee.id = `order`.user_id").
Where("`order`.order_no IN ?", orderNos).
Scan(&orderData).Error
if err != nil {
return nil, err