This commit is contained in:
@@ -41,12 +41,29 @@ func (l *UnbindDeviceLogic) UnbindDevice(req *types.UnbindDeviceRequest) error {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DeviceNotExist), "find device")
|
||||
}
|
||||
|
||||
if device.UserId != userInfo.Id {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device not belong to user")
|
||||
isSelf := (device.UserId == userInfo.Id)
|
||||
|
||||
if !isSelf {
|
||||
// Not own device — check if in the same family
|
||||
if !l.isInSameFamily(userInfo.Id, device.UserId) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "not in same family")
|
||||
}
|
||||
}
|
||||
|
||||
targetUser, err := l.svcCtx.UserModel.FindOne(l.ctx, device.UserId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find target user")
|
||||
}
|
||||
|
||||
// If kicking another user (not self), check if subscription transfer is needed
|
||||
if !isSelf {
|
||||
if err := l.transferSubscriptionsIfNeeded(userInfo, targetUser); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
currentSessionID, _ := l.ctx.Value(constant.CtxKeySessionID).(string)
|
||||
return l.logoutUnbind(userInfo, device, currentSessionID)
|
||||
return l.logoutUnbind(targetUser, device, currentSessionID)
|
||||
}
|
||||
|
||||
func (l *UnbindDeviceLogic) logoutUnbind(userInfo *user.User, device *user.Device, currentSessionID string) error {
|
||||
@@ -177,3 +194,59 @@ func (l *UnbindDeviceLogic) clearAllSessions(userId int64) {
|
||||
logger.Field("count", len(sessions)),
|
||||
)
|
||||
}
|
||||
|
||||
// isInSameFamily checks whether two users belong to the same active family
|
||||
func (l *UnbindDeviceLogic) isInSameFamily(userID1, userID2 int64) bool {
|
||||
var relation1 struct{ FamilyId int64 }
|
||||
err := l.svcCtx.DB.WithContext(l.ctx).
|
||||
Model(&user.UserFamilyMember{}).
|
||||
Select("family_id").
|
||||
Where("user_id = ? AND status = ?", userID1, user.FamilyMemberActive).
|
||||
First(&relation1).Error
|
||||
if err != nil || relation1.FamilyId == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var count int64
|
||||
l.svcCtx.DB.WithContext(l.ctx).
|
||||
Model(&user.UserFamilyMember{}).
|
||||
Where("family_id = ? AND user_id = ? AND status = ?",
|
||||
relation1.FamilyId, userID2, user.FamilyMemberActive).
|
||||
Count(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
// transferSubscriptionsIfNeeded transfers subscriptions from the kicked user to the kicker
|
||||
func (l *UnbindDeviceLogic) transferSubscriptionsIfNeeded(kicker *user.User, kicked *user.User) error {
|
||||
// Query kicked user's subscriptions
|
||||
var subscribes []user.Subscribe
|
||||
if err := l.svcCtx.DB.WithContext(l.ctx).
|
||||
Model(&user.Subscribe{}).
|
||||
Where("user_id = ?", kicked.Id).
|
||||
Find(&subscribes).Error; err != nil {
|
||||
return nil // query error, skip transfer
|
||||
}
|
||||
if len(subscribes) == 0 {
|
||||
return nil // no subscriptions to transfer
|
||||
}
|
||||
|
||||
// Transfer subscriptions: UPDATE user_subscribe SET user_id = kicker WHERE user_id = kicked
|
||||
if err := l.svcCtx.DB.WithContext(l.ctx).
|
||||
Model(&user.Subscribe{}).
|
||||
Where("user_id = ?", kicked.Id).
|
||||
Update("user_id", kicker.Id).Error; err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "transfer subscriptions failed")
|
||||
}
|
||||
|
||||
// Clear subscription caches for both users
|
||||
for _, sub := range subscribes {
|
||||
_ = l.svcCtx.UserModel.ClearSubscribeCache(l.ctx, &sub)
|
||||
}
|
||||
|
||||
l.Infow("subscriptions transferred",
|
||||
logger.Field("from_user_id", kicked.Id),
|
||||
logger.Field("to_user_id", kicker.Id),
|
||||
logger.Field("count", len(subscribes)),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user