合并 internal → main: 退款/提现/激活/CI 全面优化 #4
@@ -21,8 +21,10 @@ type (
|
||||
InviteManageRecord {
|
||||
InviterId int64 `json:"inviter_id"`
|
||||
InviterIdentifier string `json:"inviter_identifier"`
|
||||
InviterDeviceNo string `json:"inviter_device_no"`
|
||||
InviteeId int64 `json:"invitee_id"`
|
||||
InviteeIdentifier string `json:"invitee_identifier"`
|
||||
InviteeDeviceNo string `json:"invitee_device_no"`
|
||||
InviteeAvatar string `json:"invitee_avatar"`
|
||||
InviteeEnable bool `json:"invitee_enable"`
|
||||
InvitedAt int64 `json:"invited_at"`
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"slices"
|
||||
|
||||
modellog "github.com/perfect-panel/server/internal/model/log"
|
||||
"github.com/perfect-panel/server/pkg/tool"
|
||||
"github.com/perfect-panel/server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
@@ -188,26 +189,35 @@ func fillGiftBenefits(ctx context.Context, db *gorm.DB, benefits map[int64]Benef
|
||||
return nil
|
||||
}
|
||||
|
||||
func QueryIdentifiers(ctx context.Context, db *gorm.DB, userIds []int64) (map[int64]string, error) {
|
||||
identifiers := make(map[int64]string, len(userIds))
|
||||
type DeviceIdentifier struct {
|
||||
Identifier string
|
||||
DeviceNo string
|
||||
}
|
||||
|
||||
func QueryDeviceIdentifiers(ctx context.Context, db *gorm.DB, userIds []int64) (map[int64]DeviceIdentifier, error) {
|
||||
identifiers := make(map[int64]DeviceIdentifier, len(userIds))
|
||||
if len(userIds) == 0 {
|
||||
return identifiers, nil
|
||||
}
|
||||
|
||||
type identifierRow struct {
|
||||
UserId int64 `gorm:"column:user_id"`
|
||||
DeviceId int64 `gorm:"column:device_id"`
|
||||
Identifier string `gorm:"column:identifier"`
|
||||
}
|
||||
var rows []identifierRow
|
||||
if err := db.WithContext(ctx).
|
||||
Table("user_auth_methods uam").
|
||||
Select("uam.user_id, uam.auth_identifier as identifier").
|
||||
Joins("JOIN (SELECT user_id, MIN(id) AS id FROM user_auth_methods WHERE user_id IN ? GROUP BY user_id) first_uam ON first_uam.id = uam.id", userIds).
|
||||
Table("user_device ud").
|
||||
Select("ud.user_id, ud.id as device_id, ud.identifier as identifier").
|
||||
Joins("JOIN (SELECT user_id, MIN(id) AS id FROM user_device WHERE user_id IN ? GROUP BY user_id) first_ud ON first_ud.id = ud.id", userIds).
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user identifiers failed: %v", err)
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user device identifiers failed: %v", err)
|
||||
}
|
||||
for _, row := range rows {
|
||||
identifiers[row.UserId] = row.Identifier
|
||||
identifiers[row.UserId] = DeviceIdentifier{
|
||||
Identifier: row.Identifier,
|
||||
DeviceNo: tool.DeviceIdToHash(row.DeviceId),
|
||||
}
|
||||
}
|
||||
return identifiers, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/perfect-panel/server/pkg/tool"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -73,6 +74,39 @@ func TestQueryBenefitsKeepsDirectInviteeGift(t *testing.T) {
|
||||
assertBenefitsExpectations(t, mock)
|
||||
}
|
||||
|
||||
func TestQueryDeviceIdentifiersReturnsDeviceIdentifierAndNo(t *testing.T) {
|
||||
db, mock, cleanup := newBenefitsTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
mock.ExpectQuery("FROM user_device ud").
|
||||
WithArgs(int64(100), int64(200)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"user_id", "device_id", "identifier"}).
|
||||
AddRow(100, 11, "inviter-hash").
|
||||
AddRow(200, 22, "invitee-hash"))
|
||||
|
||||
identifiers, err := QueryDeviceIdentifiers(context.Background(), db, []int64{100, 200})
|
||||
if err != nil {
|
||||
t.Fatalf("QueryDeviceIdentifiers returned error: %v", err)
|
||||
}
|
||||
|
||||
inviter := identifiers[100]
|
||||
if inviter.Identifier != "inviter-hash" {
|
||||
t.Fatalf("inviter identifier = %q, want inviter-hash", inviter.Identifier)
|
||||
}
|
||||
if inviter.DeviceNo != tool.DeviceIdToHash(11) {
|
||||
t.Fatalf("inviter device no = %q, want %q", inviter.DeviceNo, tool.DeviceIdToHash(11))
|
||||
}
|
||||
|
||||
invitee := identifiers[200]
|
||||
if invitee.Identifier != "invitee-hash" {
|
||||
t.Fatalf("invitee identifier = %q, want invitee-hash", invitee.Identifier)
|
||||
}
|
||||
if invitee.DeviceNo != tool.DeviceIdToHash(22) {
|
||||
t.Fatalf("invitee device no = %q, want %q", invitee.DeviceNo, tool.DeviceIdToHash(22))
|
||||
}
|
||||
assertBenefitsExpectations(t, mock)
|
||||
}
|
||||
|
||||
func newBenefitsTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func()) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ func (l *GetInviteManageListLogic) GetInviteManageList(req *types.GetInviteManag
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
identifiers, err := QueryIdentifiers(l.ctx, l.svcCtx.DB, userIds)
|
||||
devices, err := QueryDeviceIdentifiers(l.ctx, l.svcCtx.DB, userIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -78,9 +78,11 @@ func (l *GetInviteManageListLogic) GetInviteManageList(req *types.GetInviteManag
|
||||
benefit := benefits[row.InviteeId]
|
||||
list = append(list, types.InviteManageRecord{
|
||||
InviterId: row.InviterId,
|
||||
InviterIdentifier: identifiers[row.InviterId],
|
||||
InviterIdentifier: devices[row.InviterId].Identifier,
|
||||
InviterDeviceNo: devices[row.InviterId].DeviceNo,
|
||||
InviteeId: row.InviteeId,
|
||||
InviteeIdentifier: identifiers[row.InviteeId],
|
||||
InviteeIdentifier: devices[row.InviteeId].Identifier,
|
||||
InviteeDeviceNo: devices[row.InviteeId].DeviceNo,
|
||||
InviteeAvatar: row.InviteeAvatar,
|
||||
InviteeEnable: row.InviteeEnable,
|
||||
InvitedAt: row.InvitedAt,
|
||||
|
||||
@@ -1845,8 +1845,10 @@ type InviteConfig struct {
|
||||
type InviteManageRecord struct {
|
||||
InviterId int64 `json:"inviter_id"`
|
||||
InviterIdentifier string `json:"inviter_identifier"`
|
||||
InviterDeviceNo string `json:"inviter_device_no"`
|
||||
InviteeId int64 `json:"invitee_id"`
|
||||
InviteeIdentifier string `json:"invitee_identifier"`
|
||||
InviteeDeviceNo string `json:"invitee_device_no"`
|
||||
InviteeAvatar string `json:"invitee_avatar"`
|
||||
InviteeEnable bool `json:"invitee_enable"`
|
||||
InvitedAt int64 `json:"invited_at"`
|
||||
|
||||
Reference in New Issue
Block a user