624 lines
19 KiB
Go
624 lines
19 KiB
Go
// Copyright © 2023 OpenIM open source community. All rights reserved.
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
package chat
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"regexp"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"git.imall.cloud/openim/protocol/wrapperspb"
|
||
"github.com/openimsdk/tools/utils/stringutil"
|
||
|
||
"git.imall.cloud/openim/chat/pkg/common/db/dbutil"
|
||
chatdb "git.imall.cloud/openim/chat/pkg/common/db/table/chat"
|
||
constantpb "git.imall.cloud/openim/protocol/constant"
|
||
"github.com/openimsdk/tools/mcontext"
|
||
"go.mongodb.org/mongo-driver/mongo"
|
||
|
||
"git.imall.cloud/openim/chat/pkg/common/constant"
|
||
"git.imall.cloud/openim/chat/pkg/common/mctx"
|
||
"git.imall.cloud/openim/chat/pkg/eerrs"
|
||
"git.imall.cloud/openim/chat/pkg/protocol/chat"
|
||
"github.com/openimsdk/tools/errs"
|
||
"github.com/openimsdk/tools/log"
|
||
)
|
||
|
||
func (o *chatSvr) checkUpdateInfo(ctx context.Context, req *chat.UpdateUserInfoReq) error {
|
||
if req.AreaCode != nil || req.PhoneNumber != nil {
|
||
if !(req.AreaCode != nil && req.PhoneNumber != nil) {
|
||
return errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together")
|
||
}
|
||
if req.AreaCode.Value == "" || req.PhoneNumber.Value == "" {
|
||
if req.AreaCode.Value != req.PhoneNumber.Value {
|
||
return errs.ErrArgs.WrapMsg("areaCode and phoneNumber must be set together")
|
||
}
|
||
}
|
||
}
|
||
if req.UserID == "" {
|
||
return errs.ErrArgs.WrapMsg("user id is empty")
|
||
}
|
||
|
||
credentials, err := o.Database.TakeCredentialsByUserID(ctx, req.UserID)
|
||
if err != nil {
|
||
return err
|
||
} else if len(credentials) == 0 {
|
||
return errs.ErrArgs.WrapMsg("user not found")
|
||
}
|
||
var (
|
||
credNum, delNum, addNum = len(credentials), 0, 0
|
||
)
|
||
|
||
addFunc := func(s *wrapperspb.StringValue) {
|
||
if s != nil {
|
||
if s.Value != "" {
|
||
addNum++
|
||
}
|
||
}
|
||
}
|
||
|
||
for _, s := range []*wrapperspb.StringValue{req.Account, req.PhoneNumber, req.Email} {
|
||
addFunc(s)
|
||
}
|
||
|
||
for _, credential := range credentials {
|
||
switch credential.Type {
|
||
case constant.CredentialAccount:
|
||
if req.Account != nil {
|
||
if req.Account.Value == credential.Account {
|
||
req.Account = nil
|
||
} else if req.Account.Value == "" {
|
||
delNum += 1
|
||
}
|
||
}
|
||
case constant.CredentialPhone:
|
||
if req.PhoneNumber != nil {
|
||
phoneAccount := BuildCredentialPhone(req.AreaCode.Value, req.PhoneNumber.Value)
|
||
if phoneAccount == credential.Account {
|
||
req.AreaCode = nil
|
||
req.PhoneNumber = nil
|
||
} else if req.PhoneNumber.Value == "" {
|
||
delNum += 1
|
||
}
|
||
}
|
||
case constant.CredentialEmail:
|
||
if req.Email != nil {
|
||
if req.Email.Value == credential.Account {
|
||
req.Email = nil
|
||
} else if req.Email.Value == "" {
|
||
delNum += 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if addNum+credNum-delNum <= 0 {
|
||
return errs.ErrArgs.WrapMsg("a login method must exist")
|
||
}
|
||
|
||
if req.PhoneNumber.GetValue() != "" {
|
||
if !strings.HasPrefix(req.AreaCode.GetValue(), "+") {
|
||
req.AreaCode.Value = "+" + req.AreaCode.Value
|
||
}
|
||
if _, err := strconv.ParseUint(req.AreaCode.Value[1:], 10, 64); err != nil {
|
||
return errs.ErrArgs.WrapMsg("area code must be number")
|
||
}
|
||
if _, err := strconv.ParseUint(req.PhoneNumber.GetValue(), 10, 64); err != nil {
|
||
return errs.ErrArgs.WrapMsg("phone number must be number")
|
||
}
|
||
phoneAccount := BuildCredentialPhone(req.AreaCode.GetValue(), req.PhoneNumber.GetValue())
|
||
existingCredential, err := o.Database.TakeCredentialByAccount(ctx, phoneAccount)
|
||
if err == nil {
|
||
// 如果手机号已存在,检查是否是当前用户的手机号
|
||
if existingCredential.UserID == req.UserID {
|
||
// 是当前用户的手机号,允许更新(实际上是相同值,不需要更新)
|
||
req.AreaCode = nil
|
||
req.PhoneNumber = nil
|
||
} else {
|
||
// 是其他用户的手机号,返回错误
|
||
return eerrs.ErrPhoneAlreadyRegister.Wrap()
|
||
}
|
||
} else if !dbutil.IsDBNotFound(err) {
|
||
return err
|
||
}
|
||
}
|
||
if req.Account.GetValue() != "" {
|
||
accountValue := req.Account.GetValue()
|
||
// 验证长度:6到20位
|
||
if len(accountValue) < 6 || len(accountValue) > 20 {
|
||
return errs.ErrArgs.WrapMsg("account must be between 6 and 20 characters")
|
||
}
|
||
// 验证格式:只能包含数字、字母、下划线(_)、横线(-)
|
||
pattern := `^[a-zA-Z0-9_-]+$`
|
||
matched, err := regexp.MatchString(pattern, accountValue)
|
||
if err != nil || !matched {
|
||
return errs.ErrArgs.WrapMsg("account must contain only letters, numbers, underscores, and hyphens")
|
||
}
|
||
existingCredential, err := o.Database.TakeCredentialByAccount(ctx, accountValue)
|
||
if err == nil {
|
||
// 如果账户已存在,检查是否是当前用户的账户
|
||
if existingCredential.UserID == req.UserID {
|
||
// 是当前用户的账户,允许更新(实际上是相同值,不需要更新)
|
||
req.Account = nil
|
||
|
||
} else {
|
||
// 是其他用户的账户,返回错误
|
||
return eerrs.ErrAccountAlreadyRegister.Wrap()
|
||
}
|
||
} else if !dbutil.IsDBNotFound(err) {
|
||
return err
|
||
}
|
||
}
|
||
if req.Email.GetValue() != "" {
|
||
if !stringutil.IsValidEmail(req.Email.GetValue()) {
|
||
return errs.ErrArgs.WrapMsg("invalid email")
|
||
}
|
||
existingCredential, err := o.Database.TakeCredentialByAccount(ctx, req.Email.GetValue())
|
||
if err == nil {
|
||
// 如果邮箱已存在,检查是否是当前用户的邮箱
|
||
if existingCredential.UserID == req.UserID {
|
||
// 是当前用户的邮箱,允许更新(实际上是相同值,不需要更新)
|
||
req.Email = nil
|
||
} else {
|
||
// 是其他用户的邮箱,返回错误
|
||
return eerrs.ErrEmailAlreadyRegister.Wrap()
|
||
}
|
||
} else if !dbutil.IsDBNotFound(err) {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (o *chatSvr) UpdateUserInfo(ctx context.Context, req *chat.UpdateUserInfoReq) (*chat.UpdateUserInfoResp, error) {
|
||
opUserID, userType, err := mctx.Check(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if err = o.checkUpdateInfo(ctx, req); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
switch userType {
|
||
case constant.NormalUser:
|
||
if req.RegisterType != nil {
|
||
return nil, errs.ErrNoPermission.WrapMsg("registerType can not be updated")
|
||
}
|
||
if req.UserID != opUserID {
|
||
return nil, errs.ErrNoPermission.WrapMsg("only admin can update other user info")
|
||
}
|
||
// 普通用户不能修改自己的用户类型
|
||
if req.UserType != 0 {
|
||
return nil, errs.ErrNoPermission.WrapMsg("normal user can not update userType")
|
||
}
|
||
|
||
case constant.AdminUser:
|
||
// 管理员可以修改用户类型,但需要验证值
|
||
if req.UserType < 0 || req.UserType > 3 {
|
||
return nil, errs.ErrArgs.WrapMsg("invalid userType: must be 0-3")
|
||
}
|
||
default:
|
||
return nil, errs.ErrNoPermission.WrapMsg("user type error")
|
||
}
|
||
|
||
update, err := ToDBAttributeUpdate(req)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if userType == constant.NormalUser {
|
||
delete(update, "user_flag")
|
||
delete(update, "user_type")
|
||
}
|
||
|
||
credUpdate, credDel, err := ToDBCredentialUpdate(req, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if len(update) > 0 {
|
||
if err := o.Database.UpdateUseInfo(ctx, req.UserID, update, credUpdate, credDel); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
return &chat.UpdateUserInfoResp{}, nil
|
||
}
|
||
|
||
func (o *chatSvr) FindUserPublicInfo(ctx context.Context, req *chat.FindUserPublicInfoReq) (*chat.FindUserPublicInfoResp, error) {
|
||
if len(req.UserIDs) == 0 {
|
||
return nil, errs.ErrArgs.WrapMsg("UserIDs is empty")
|
||
}
|
||
attributes, err := o.Database.FindAttribute(ctx, req.UserIDs)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &chat.FindUserPublicInfoResp{
|
||
Users: DbToPbAttributes(attributes),
|
||
}, nil
|
||
}
|
||
|
||
func (o *chatSvr) AddUserAccount(ctx context.Context, req *chat.AddUserAccountReq) (*chat.AddUserAccountResp, error) {
|
||
if _, _, err := mctx.Check(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if err := o.checkRegisterInfo(ctx, req.User, true); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if req.User.UserID == "" {
|
||
for i := 0; i < 20; i++ {
|
||
userID := o.genUserID()
|
||
_, err := o.Database.GetUser(ctx, userID)
|
||
if err == nil {
|
||
continue
|
||
} else if dbutil.IsDBNotFound(err) {
|
||
req.User.UserID = userID
|
||
break
|
||
} else {
|
||
return nil, err
|
||
}
|
||
}
|
||
if req.User.UserID == "" {
|
||
return nil, errs.ErrInternalServer.WrapMsg("gen user id failed")
|
||
}
|
||
} else {
|
||
_, err := o.Database.GetUser(ctx, req.User.UserID)
|
||
if err == nil {
|
||
return nil, errs.ErrArgs.WrapMsg("appoint user id already register")
|
||
} else if !dbutil.IsDBNotFound(err) {
|
||
return nil, err
|
||
}
|
||
}
|
||
|
||
var (
|
||
credentials []*chatdb.Credential
|
||
)
|
||
|
||
if req.User.PhoneNumber != "" {
|
||
credentials = append(credentials, &chatdb.Credential{
|
||
UserID: req.User.UserID,
|
||
Account: BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber),
|
||
Type: constant.CredentialPhone,
|
||
AllowChange: true,
|
||
})
|
||
}
|
||
|
||
if req.User.Account != "" {
|
||
credentials = append(credentials, &chatdb.Credential{
|
||
UserID: req.User.UserID,
|
||
Account: req.User.Account,
|
||
Type: constant.CredentialAccount,
|
||
AllowChange: true,
|
||
})
|
||
}
|
||
|
||
if req.User.Email != "" {
|
||
credentials = append(credentials, &chatdb.Credential{
|
||
UserID: req.User.UserID,
|
||
Account: req.User.Email,
|
||
Type: constant.CredentialEmail,
|
||
AllowChange: true,
|
||
})
|
||
}
|
||
|
||
register := &chatdb.Register{
|
||
UserID: req.User.UserID,
|
||
DeviceID: req.DeviceID,
|
||
IP: req.Ip,
|
||
Platform: constantpb.PlatformID2Name[int(req.Platform)],
|
||
AccountType: "",
|
||
Mode: constant.UserMode,
|
||
CreateTime: time.Now(),
|
||
}
|
||
account := &chatdb.Account{
|
||
UserID: req.User.UserID,
|
||
Password: req.User.Password,
|
||
OperatorUserID: mcontext.GetOpUserID(ctx),
|
||
ChangeTime: register.CreateTime,
|
||
CreateTime: register.CreateTime,
|
||
}
|
||
attribute := &chatdb.Attribute{
|
||
UserID: req.User.UserID,
|
||
Account: req.User.Account,
|
||
PhoneNumber: req.User.PhoneNumber,
|
||
AreaCode: req.User.AreaCode,
|
||
Email: req.User.Email,
|
||
Nickname: req.User.Nickname,
|
||
FaceURL: req.User.FaceURL,
|
||
Gender: req.User.Gender,
|
||
BirthTime: time.UnixMilli(req.User.Birth),
|
||
ChangeTime: register.CreateTime,
|
||
CreateTime: register.CreateTime,
|
||
AllowVibration: constant.DefaultAllowVibration,
|
||
AllowBeep: constant.DefaultAllowBeep,
|
||
AllowAddFriend: constant.DefaultAllowAddFriend,
|
||
}
|
||
|
||
if err := o.Database.RegisterUser(ctx, register, account, attribute, credentials); err != nil {
|
||
return nil, err
|
||
}
|
||
return &chat.AddUserAccountResp{}, nil
|
||
}
|
||
|
||
func (o *chatSvr) SearchUserPublicInfo(ctx context.Context, req *chat.SearchUserPublicInfoReq) (*chat.SearchUserPublicInfoResp, error) {
|
||
if _, _, err := mctx.Check(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
total, list, err := o.Database.Search(ctx, constant.FinDAllUser, req.Keyword, req.Genders, nil, nil, req.Pagination)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &chat.SearchUserPublicInfoResp{
|
||
Total: uint32(total),
|
||
Users: DbToPbAttributes(list),
|
||
}, nil
|
||
}
|
||
|
||
func (o *chatSvr) FindUserFullInfo(ctx context.Context, req *chat.FindUserFullInfoReq) (*chat.FindUserFullInfoResp, error) {
|
||
if _, _, err := mctx.Check(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
if len(req.UserIDs) == 0 {
|
||
return nil, errs.ErrArgs.WrapMsg("UserIDs is empty")
|
||
}
|
||
attributes, err := o.Database.FindAttribute(ctx, req.UserIDs)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 获取每个用户的最新登录IP
|
||
userIPMap := make(map[string]string)
|
||
for _, attr := range attributes {
|
||
ip, err := o.Database.GetLatestLoginIP(ctx, attr.UserID)
|
||
if err != nil {
|
||
// 如果获取IP失败,记录错误但继续处理其他用户
|
||
continue
|
||
}
|
||
userIPMap[attr.UserID] = ip
|
||
}
|
||
|
||
return &chat.FindUserFullInfoResp{Users: DbToPbUserFullInfosWithIP(attributes, userIPMap)}, nil
|
||
}
|
||
|
||
func (o *chatSvr) SearchUserFullInfo(ctx context.Context, req *chat.SearchUserFullInfoReq) (*chat.SearchUserFullInfoResp, error) {
|
||
if _, _, err := mctx.Check(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
// 解析时间戳为 time.Time(毫秒时间戳)
|
||
var startTime, endTime *time.Time
|
||
if req.StartTime > 0 {
|
||
st := time.UnixMilli(req.StartTime)
|
||
startTime = &st
|
||
}
|
||
if req.EndTime > 0 {
|
||
// 将endTime加1000毫秒,确保包含到当天的最后一毫秒
|
||
// 例如:endTime=1727740799000 (2025-11-01 23:59:59) 会被转换为 1727740800000 (2025-11-02 00:00:00)
|
||
// 这样使用 $lt 查询时,会包含 2025-11-01 23:59:59.999 但不包含 2025-11-02 00:00:00
|
||
et := time.UnixMilli(req.EndTime + 1000)
|
||
endTime = &et
|
||
}
|
||
// 使用支持实名信息搜索的方法
|
||
total, list, err := o.Database.SearchWithRealNameAuth(ctx, req.Normal, req.Keyword, req.Genders, startTime, endTime, req.RealNameKeyword, req.IdCardKeyword, req.Pagination)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 批量获取钱包信息(用于填充实名信息)
|
||
userIDs := make([]string, 0, len(list))
|
||
for _, attr := range list {
|
||
userIDs = append(userIDs, attr.UserID)
|
||
}
|
||
walletMap := make(map[string]*chatdb.Wallet)
|
||
if len(userIDs) > 0 {
|
||
wallets, err := o.Database.GetWalletsByUserIDs(ctx, userIDs)
|
||
if err != nil {
|
||
log.ZWarn(ctx, "Failed to get wallets for user search", err, "userIDs", userIDs)
|
||
} else {
|
||
for _, wallet := range wallets {
|
||
walletMap[wallet.UserID] = wallet
|
||
}
|
||
}
|
||
}
|
||
|
||
// 获取每个用户的最新登录IP
|
||
userIPMap := make(map[string]string)
|
||
for _, attr := range list {
|
||
ip, err := o.Database.GetLatestLoginIP(ctx, attr.UserID)
|
||
if err != nil {
|
||
// 如果获取IP失败,记录错误但继续处理其他用户
|
||
log.ZWarn(ctx, "Failed to get latest login IP for user", err, "userID", attr.UserID)
|
||
// 即使出错也设置空字符串,确保map中有该用户的记录
|
||
userIPMap[attr.UserID] = ""
|
||
continue
|
||
}
|
||
// 记录获取到的IP(用于调试)
|
||
if ip != "" {
|
||
log.ZDebug(ctx, "Got latest login IP for user", "userID", attr.UserID, "ip", ip)
|
||
} else {
|
||
log.ZDebug(ctx, "No login IP found for user (empty string)", "userID", attr.UserID)
|
||
}
|
||
userIPMap[attr.UserID] = ip
|
||
}
|
||
// 统计有IP的用户数量
|
||
usersWithIP := 0
|
||
for _, ip := range userIPMap {
|
||
if ip != "" {
|
||
usersWithIP++
|
||
}
|
||
}
|
||
log.ZInfo(ctx, "User IP map summary", "totalUsers", len(list), "ipMapSize", len(userIPMap), "usersWithIP", usersWithIP)
|
||
|
||
return &chat.SearchUserFullInfoResp{
|
||
Total: uint32(total),
|
||
Users: DbToPbUserFullInfosWithRealNameAuthAndIP(list, walletMap, userIPMap),
|
||
}, nil
|
||
}
|
||
|
||
// GetUserLoginRecords 查询用户登录记录
|
||
func (o *chatSvr) GetUserLoginRecords(ctx context.Context, req *chat.GetUserLoginRecordsReq) (*chat.GetUserLoginRecordsResp, error) {
|
||
// 检查管理员权限
|
||
if _, err := mctx.CheckAdmin(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 查询登录记录
|
||
total, records, err := o.Database.SearchUserLoginRecords(ctx, req.UserId, req.Ip, req.Pagination)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 收集所有用户ID
|
||
userIDs := make([]string, 0, len(records))
|
||
userIDSet := make(map[string]bool)
|
||
for _, record := range records {
|
||
if !userIDSet[record.UserID] {
|
||
userIDs = append(userIDs, record.UserID)
|
||
userIDSet[record.UserID] = true
|
||
}
|
||
}
|
||
|
||
// 批量获取用户属性(头像和昵称)
|
||
userAttrMap := make(map[string]*chatdb.Attribute)
|
||
if len(userIDs) > 0 {
|
||
attributes, err := o.Database.FindAttribute(ctx, userIDs)
|
||
if err != nil {
|
||
log.ZWarn(ctx, "Failed to get user attributes for login records", err, "userIDs", userIDs)
|
||
} else {
|
||
for _, attr := range attributes {
|
||
userAttrMap[attr.UserID] = attr
|
||
}
|
||
}
|
||
}
|
||
|
||
// 转换结果
|
||
var recordInfos []*chat.UserLoginRecordInfo
|
||
for _, record := range records {
|
||
recordInfo := &chat.UserLoginRecordInfo{
|
||
UserId: record.UserID,
|
||
LoginTime: record.LoginTime.UnixMilli(),
|
||
Ip: record.IP,
|
||
DeviceId: record.DeviceID,
|
||
Platform: record.Platform,
|
||
}
|
||
// 填充用户头像和昵称
|
||
if attr, ok := userAttrMap[record.UserID]; ok {
|
||
recordInfo.FaceUrl = attr.FaceURL
|
||
recordInfo.Nickname = attr.Nickname
|
||
}
|
||
recordInfos = append(recordInfos, recordInfo)
|
||
}
|
||
|
||
return &chat.GetUserLoginRecordsResp{
|
||
Total: uint32(total),
|
||
Records: recordInfos,
|
||
}, nil
|
||
}
|
||
|
||
func (o *chatSvr) FindUserAccount(ctx context.Context, req *chat.FindUserAccountReq) (*chat.FindUserAccountResp, error) {
|
||
if len(req.UserIDs) == 0 {
|
||
return nil, errs.ErrArgs.WrapMsg("user id list must be set")
|
||
}
|
||
if _, _, err := mctx.CheckAdminOrUser(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
attributes, err := o.Database.FindAttribute(ctx, req.UserIDs)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
userAccountMap := make(map[string]string)
|
||
for _, attribute := range attributes {
|
||
userAccountMap[attribute.UserID] = attribute.Account
|
||
}
|
||
return &chat.FindUserAccountResp{UserAccountMap: userAccountMap}, nil
|
||
}
|
||
|
||
func (o *chatSvr) FindAccountUser(ctx context.Context, req *chat.FindAccountUserReq) (*chat.FindAccountUserResp, error) {
|
||
if len(req.Accounts) == 0 {
|
||
return nil, errs.ErrArgs.WrapMsg("account list must be set")
|
||
}
|
||
if _, _, err := mctx.CheckAdminOrUser(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
attributes, err := o.Database.FindAttribute(ctx, req.Accounts)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
accountUserMap := make(map[string]string)
|
||
for _, attribute := range attributes {
|
||
accountUserMap[attribute.Account] = attribute.UserID
|
||
}
|
||
return &chat.FindAccountUserResp{AccountUserMap: accountUserMap}, nil
|
||
}
|
||
|
||
func (o *chatSvr) SearchUserInfo(ctx context.Context, req *chat.SearchUserInfoReq) (*chat.SearchUserInfoResp, error) {
|
||
if _, _, err := mctx.Check(ctx); err != nil {
|
||
return nil, err
|
||
}
|
||
total, list, err := o.Database.SearchUser(ctx, req.Keyword, req.UserIDs, req.Genders, req.Pagination)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &chat.SearchUserInfoResp{
|
||
Total: uint32(total),
|
||
Users: DbToPbUserFullInfos(list),
|
||
}, nil
|
||
}
|
||
|
||
func (o *chatSvr) CheckUserExist(ctx context.Context, req *chat.CheckUserExistReq) (resp *chat.CheckUserExistResp, err error) {
|
||
if req.User == nil {
|
||
return nil, errs.ErrArgs.WrapMsg("user is nil")
|
||
}
|
||
if req.User.PhoneNumber != "" {
|
||
account, err := o.Database.TakeCredentialByAccount(ctx, BuildCredentialPhone(req.User.AreaCode, req.User.PhoneNumber))
|
||
// err != nil is not found User
|
||
if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
|
||
return nil, err
|
||
}
|
||
if account != nil {
|
||
return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil
|
||
}
|
||
}
|
||
if req.User.Email != "" {
|
||
account, err := o.Database.TakeCredentialByAccount(ctx, req.User.AreaCode)
|
||
if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
|
||
return nil, err
|
||
}
|
||
if account != nil {
|
||
return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil
|
||
}
|
||
}
|
||
if req.User.Account != "" {
|
||
account, err := o.Database.TakeCredentialByAccount(ctx, req.User.Account)
|
||
if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
|
||
return nil, err
|
||
}
|
||
if account != nil {
|
||
return &chat.CheckUserExistResp{Userid: account.UserID, IsRegistered: true}, nil
|
||
}
|
||
}
|
||
return nil, nil
|
||
}
|
||
|
||
func (o *chatSvr) DelUserAccount(ctx context.Context, req *chat.DelUserAccountReq) (resp *chat.DelUserAccountResp, err error) {
|
||
if err := o.Database.DelUserAccount(ctx, req.UserIDs); err != nil && errs.Unwrap(err) != mongo.ErrNoDocuments {
|
||
return nil, err
|
||
}
|
||
return nil, nil
|
||
}
|