用户设置

pull/3727/head
hawklin2017 2 months ago
parent 33e2a71362
commit 42064d31a7

@ -159,6 +159,11 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co
userRouterGroup.POST("/update_notification_account", u.UpdateNotificationAccountInfo)
userRouterGroup.POST("/search_notification_account", u.SearchNotificationAccount)
// 手机号可见性设置(所有人/仅好友/隐藏)
userRouterGroup.POST("/set_phone_visibility", u.SetPhoneVisibility)
userRouterGroup.POST("/set_call_accept_setting", u.SetCallAcceptSetting)
userRouterGroup.POST("/set_msg_receive_setting", u.SetMsgReceiveSetting)
// 全局黑名单管理(仅管理员)
userRouterGroup.POST("/add_global_blacklist", bl.AddGlobalBlacklist)
userRouterGroup.POST("/remove_global_blacklist", bl.RemoveGlobalBlacklist)

@ -305,3 +305,15 @@ func (u *UserApi) UpdateNotificationAccountInfo(c *gin.Context) {
func (u *UserApi) SearchNotificationAccount(c *gin.Context) {
a2r.Call(c, user.UserClient.SearchNotificationAccount, u.Client)
}
func (u *UserApi) SetPhoneVisibility(c *gin.Context) {
a2r.Call(c, user.UserClient.SetPhoneVisibility, u.Client)
}
func (u *UserApi) SetCallAcceptSetting(c *gin.Context) {
a2r.Call(c, user.UserClient.SetCallAcceptSetting, u.Client)
}
func (u *UserApi) SetMsgReceiveSetting(c *gin.Context) {
a2r.Call(c, user.UserClient.SetMsgReceiveSetting, u.Client)
}

@ -38,6 +38,10 @@ func (s *groupServer) groupDB2PB(group *model.Group, ownerUserID string, memberC
ApplyMemberFriend: group.ApplyMemberFriend,
NotificationUpdateTime: group.NotificationUpdateTime.UnixMilli(),
NotificationUserID: group.NotificationUserID,
AllowSendMsg: group.AllowSendMsg,
AllowPinMsg: group.AllowPinMsg,
AllowAddMember: group.AllowAddMember,
AllowEditGroupInfo: group.AllowEditGroupInfo,
}
}

@ -53,6 +53,18 @@ func UpdateGroupInfoMap(ctx context.Context, group *sdkws.GroupInfoForSet) map[s
if group.Ex != nil {
m["ex"] = group.Ex.Value
}
if group.AllowSendMsg != nil {
m["allow_send_msg"] = group.AllowSendMsg.Value
}
if group.AllowPinMsg != nil {
m["allow_pin_msg"] = group.AllowPinMsg.Value
}
if group.AllowAddMember != nil {
m["allow_add_member"] = group.AllowAddMember.Value
}
if group.AllowEditGroupInfo != nil {
m["allow_edit_group_info"] = group.AllowEditGroupInfo.Value
}
return m
}
@ -100,6 +112,22 @@ func UpdateGroupInfoExMap(ctx context.Context, group *pbgroup.SetGroupInfoExReq)
m["ex"] = group.Ex.Value
normalFlag = true
}
if group.AllowSendMsg != nil {
m["allow_send_msg"] = group.AllowSendMsg.Value
normalFlag = true
}
if group.AllowPinMsg != nil {
m["allow_pin_msg"] = group.AllowPinMsg.Value
normalFlag = true
}
if group.AllowAddMember != nil {
m["allow_add_member"] = group.AllowAddMember.Value
normalFlag = true
}
if group.AllowEditGroupInfo != nil {
m["allow_edit_group_info"] = group.AllowEditGroupInfo.Value
normalFlag = true
}
return m, normalFlag, groupNameFlag, notificationFlag, nil
}

@ -458,6 +458,11 @@ func (s *groupServer) InviteUserToGroup(ctx context.Context, req *pbgroup.Invite
if err := s.PopulateGroupMember(ctx, groupMember); err != nil {
return nil, err
}
// AllowAddMember == 1 时仅群主/管理员可拉人
isOwnerOrAdmin := groupMember.RoleLevel == constant.GroupOwner || groupMember.RoleLevel == constant.GroupAdmin
if group.AllowAddMember == model.GroupPermAdminOnly && !isOwnerOrAdmin {
return nil, errs.ErrNoPermission.WrapMsg("only owner or admin can add members to this group")
}
} else {
opUserID = mcontext.GetOpUserID(ctx)
}
@ -1098,8 +1103,22 @@ func (s *groupServer) SetGroupInfo(ctx context.Context, req *pbgroup.SetGroupInf
if err != nil {
return nil, err
}
if !(opMember.RoleLevel == constant.GroupOwner || opMember.RoleLevel == constant.GroupAdmin) {
return nil, errs.ErrNoPermission.WrapMsg("no group owner or admin")
isOwnerOrAdmin := opMember.RoleLevel == constant.GroupOwner || opMember.RoleLevel == constant.GroupAdmin
requestsPermField := req.GroupInfoForSet.AllowSendMsg != nil ||
req.GroupInfoForSet.AllowPinMsg != nil ||
req.GroupInfoForSet.AllowAddMember != nil ||
req.GroupInfoForSet.AllowEditGroupInfo != nil
if requestsPermField && !isOwnerOrAdmin {
return nil, errs.ErrNoPermission.WrapMsg("only owner or admin can change group permission settings")
}
if !isOwnerOrAdmin {
grp, err := s.db.TakeGroup(ctx, req.GroupInfoForSet.GroupID)
if err != nil {
return nil, err
}
if grp.AllowEditGroupInfo == model.GroupPermAdminOnly {
return nil, errs.ErrNoPermission.WrapMsg("only owner or admin can edit group info")
}
}
if err := s.PopulateGroupMember(ctx, opMember); err != nil {
return nil, err
@ -1193,9 +1212,24 @@ func (s *groupServer) SetGroupInfoEx(ctx context.Context, req *pbgroup.SetGroupI
if err != nil {
return nil, err
}
if !(opMember.RoleLevel == constant.GroupOwner || opMember.RoleLevel == constant.GroupAdmin) {
return nil, errs.ErrNoPermission.WrapMsg("no group owner or admin")
isOwnerOrAdmin := opMember.RoleLevel == constant.GroupOwner || opMember.RoleLevel == constant.GroupAdmin
// 4个群权限字段始终只有群主/管理员可修改
requestsPermField := req.AllowSendMsg != nil ||
req.AllowPinMsg != nil ||
req.AllowAddMember != nil ||
req.AllowEditGroupInfo != nil
if requestsPermField && !isOwnerOrAdmin {
return nil, errs.ErrNoPermission.WrapMsg("only owner or admin can change group permission settings")
}
// 其他字段:按 AllowEditGroupInfo 决定是否允许普通成员操作
if !isOwnerOrAdmin {
grp, err := s.db.TakeGroup(ctx, req.GroupID)
if err != nil {
return nil, err
}
if grp.AllowEditGroupInfo == model.GroupPermAdminOnly {
return nil, errs.ErrNoPermission.WrapMsg("only owner or admin can edit group info")
}
}
if err := s.PopulateGroupMember(ctx, opMember); err != nil {

@ -59,9 +59,7 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
data.MsgData.ContentType >= constant.NotificationBegin {
return nil
}
if err := m.webhookBeforeSendSingleMsg(ctx, &m.config.WebhooksConfig.BeforeSendSingleMsg, data); err != nil {
return err
}
// 先做本地轻量级拦截(黑名单 + 消息接收权限),避免不必要的 webhook 触发
black, err := m.FriendLocalCache.IsBlack(ctx, data.MsgData.SendID, data.MsgData.RecvID)
if err != nil {
return err
@ -69,6 +67,33 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if black {
return servererrs.ErrBlockedByPeer.Wrap()
}
// 校验接收方消息接收权限MsgReceiveSetting
// 0=所有人可发送1=仅好友可发送2=所有人不可发送
recvUserInfo, err := m.UserLocalCache.GetUserInfo(ctx, data.MsgData.RecvID)
if err != nil {
return err
}
switch recvUserInfo.MsgReceiveSetting {
case 2: // MsgReceiveSettingNobody
return servererrs.ErrMsgReceiveNotAllowed.Wrap()
case 1: // MsgReceiveSettingFriends
isFriend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.RecvID, data.MsgData.SendID)
if err != nil {
return err
}
if !isFriend {
return servererrs.ErrMsgReceiveNotAllowed.Wrap()
}
// 已确认是好友,触发 webhook 后放行,不做 FriendVerify 冗余查询
if err := m.webhookBeforeSendSingleMsg(ctx, &m.config.WebhooksConfig.BeforeSendSingleMsg, data); err != nil {
return err
}
return nil
}
// MsgReceiveSetting==0所有人可发触发 webhook再按全局 FriendVerify 兜底
if err := m.webhookBeforeSendSingleMsg(ctx, &m.config.WebhooksConfig.BeforeSendSingleMsg, data); err != nil {
return err
}
if m.config.RpcConfig.FriendVerify {
friend, err := m.FriendLocalCache.IsFriend(ctx, data.MsgData.SendID, data.MsgData.RecvID)
if err != nil {
@ -77,7 +102,6 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if !friend {
return servererrs.ErrNotPeersFriend.Wrap()
}
return nil
}
return nil
case constant.ReadGroupChatType:
@ -124,6 +148,10 @@ func (m *msgServer) messageVerification(ctx context.Context, data *msg.SendMsgRe
if groupInfo.Status == constant.GroupStatusMuted && groupMemberInfo.RoleLevel != constant.GroupAdmin {
return servererrs.ErrMutedGroup.Wrap()
}
// AllowSendMsg == 1 时仅群主/管理员可发消息
if groupInfo.AllowSendMsg == 1 && groupMemberInfo.RoleLevel != constant.GroupAdmin {
return servererrs.ErrNoPermission.WrapMsg("only owner or admin can send messages in this group")
}
}
return nil
default:

@ -39,12 +39,13 @@ type Config struct {
type rtcServer struct {
rtc.UnimplementedRtcServiceServer
config *Config
db controller.RtcDatabase
roomClient *lksdk.RoomServiceClient
msgClient *rpcli.MsgClient
userClient *rpcli.UserClient
tokenExpiry time.Duration
config *Config
db controller.RtcDatabase
roomClient *lksdk.RoomServiceClient
msgClient *rpcli.MsgClient
userClient *rpcli.UserClient
relationClient *rpcli.RelationClient
tokenExpiry time.Duration
}
// Start initialises the RTC gRPC service and registers it with the gRPC server.
@ -69,6 +70,11 @@ func Start(ctx context.Context, cfg *Config, client discovery.SvcDiscoveryRegist
return err
}
friendConn, err := client.GetConn(ctx, cfg.Share.RpcRegisterName.Friend)
if err != nil {
return err
}
lk := cfg.RpcConfig.LiveKit
roomClient := lksdk.NewRoomServiceClient(lk.InternalAddress, lk.APIKey, lk.APISecret)
@ -78,12 +84,13 @@ func Start(ctx context.Context, cfg *Config, client discovery.SvcDiscoveryRegist
}
s := &rtcServer{
config: cfg,
db: controller.NewRtcDatabase(signalDB),
roomClient: roomClient,
msgClient: rpcli.NewMsgClient(msgConn),
userClient: rpcli.NewUserClient(userConn),
tokenExpiry: tokenExpiry,
config: cfg,
db: controller.NewRtcDatabase(signalDB),
roomClient: roomClient,
msgClient: rpcli.NewMsgClient(msgConn),
userClient: rpcli.NewUserClient(userConn),
relationClient: rpcli.NewRelationClient(friendConn),
tokenExpiry: tokenExpiry,
}
rtc.RegisterRtcServiceServer(server, s)

@ -99,6 +99,18 @@ func (s *rtcServer) handleInvite(ctx context.Context, req *rtc.SignalInviteReq,
inv.InviterUserID = req.UserID
inv.InitiateTime = time.Now().UnixMilli()
// 校验每位被邀请者的通话接受权限1-to-1 场景:有任一被邀请者拒绝则直接返错
for _, inviteeID := range inv.InviteeUserIDList {
allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID)
if err != nil {
log.ZError(ctx, "handleInvite: isCallAllowed failed", err, "inviteeID", inviteeID)
return nil, err
}
if !allowed {
return nil, errs.ErrNoPermission.WrapMsg("the invitee does not accept calls from you", "inviteeID", inviteeID)
}
}
if _, err := s.roomClient.CreateRoom(ctx, &livekit.CreateRoomRequest{Name: inv.RoomID}); err != nil {
log.ZError(ctx, "handleInvite", err, "r", err.Error())
return nil, errs.WrapMsg(err, "LiveKit CreateRoom failed", "roomID", inv.RoomID)
@ -157,6 +169,15 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
content := marshalSignalReq(signalReq)
for _, inviteeID := range inv.InviteeUserIDList {
allowed, err := s.isCallAllowed(ctx, req.UserID, inviteeID)
if err != nil {
log.ZWarn(ctx, "handleInviteInGroup: isCallAllowed failed, skipping invitee", err, "inviteeID", inviteeID)
continue
}
if !allowed {
log.ZInfo(ctx, "handleInviteInGroup: skipping invitee (call setting blocked)", "inviteeID", inviteeID)
continue
}
if err := s.sendSignalingNotification(ctx, req.UserID, inviteeID, int32(constant.ReadGroupChatType), req.OfflinePushInfo, content); err != nil {
log.ZWarn(ctx, "sendSignalingNotification to group invitee failed", err, "inviteeID", inviteeID)
}
@ -169,6 +190,30 @@ func (s *rtcServer) handleInviteInGroup(ctx context.Context, req *rtc.SignalInvi
}, nil
}
// isCallAllowed 判断 inviterID 是否被允许向 inviteeID 发起音视频通话。
// 规则:
// - CallAcceptSettingPublic(0) → 所有人均可
// - CallAcceptSettingFriends(1) → 仅当 inviterID 在 inviteeID 好友列表中
// - CallAcceptSettingNobody(2) → 任何人均不可
func (s *rtcServer) isCallAllowed(ctx context.Context, inviterID, inviteeID string) (bool, error) {
userInfo, err := s.userClient.GetUserInfo(ctx, inviteeID)
if err != nil {
return false, err
}
switch userInfo.CallAcceptSetting {
case model.CallAcceptSettingNobody:
return false, nil
case model.CallAcceptSettingFriends:
isFriend, err := s.relationClient.IsFriend(ctx, inviteeID, inviterID)
if err != nil {
return false, err
}
return isFriend, nil
default: // CallAcceptSettingPublic
return true, nil
}
}
// handleAccept processes a call acceptance.
func (s *rtcServer) handleAccept(ctx context.Context, req *rtc.SignalAcceptReq, signalReq *rtc.SignalReq) (*rtc.SignalAcceptResp, error) {
inv := req.Invitation

@ -35,6 +35,7 @@ import (
"github.com/openimsdk/protocol/group"
friendpb "github.com/openimsdk/protocol/relation"
"github.com/openimsdk/tools/db/redisutil"
"github.com/openimsdk/tools/mcontext"
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
"github.com/openimsdk/open-im-server/v3/pkg/common/convert"
@ -149,10 +150,50 @@ func (s *userServer) GetDesignateUsers(ctx context.Context, req *pbuser.GetDesig
return nil, servererrs.ErrUserBlocked.WrapMsg("user is banned", "userIDs", bannedIDs)
}
resp.UsersInfo = convert.UsersDB2Pb(users)
pbUsers := convert.UsersDB2Pb(users)
viewerID := mcontext.GetOpUserID(ctx)
if err := s.applyPhoneVisibility(ctx, viewerID, pbUsers, users); err != nil {
return nil, err
}
resp.UsersInfo = pbUsers
return resp, nil
}
// applyPhoneVisibility 根据 phone_visibility 和好友关系决定是否下发明文手机号。
// pbUsers 与 dbUsers 下标一一对应。
func (s *userServer) applyPhoneVisibility(ctx context.Context, viewerID string, pbUsers []*sdkws.UserInfo, dbUsers []*tablerelation.User) error {
for i, db := range dbUsers {
pb := pbUsers[i]
if db.Phone == "" {
// 未设置手机号,直接跳过
continue
}
switch db.PhoneVisibility {
case tablerelation.PhoneVisibilityPublic:
// 所有人可见,保留 phone 字段(已由 UserDB2Pb 填充)
case tablerelation.PhoneVisibilityHidden:
// 完全隐藏:即使本人也不通过此接口暴露,客户端自行从个人设置接口获取
pb.Phone = ""
case tablerelation.PhoneVisibilityFriends:
// 仅好友可见
if viewerID == db.UserID {
// 本人始终可见
break
}
isFriend, err := s.relationClient.IsFriend(ctx, viewerID, db.UserID)
if err != nil {
return err
}
if !isFriend {
pb.Phone = ""
}
default:
pb.Phone = ""
}
}
return nil
}
// deprecated:
// UpdateUserInfo
func (s *userServer) UpdateUserInfo(ctx context.Context, req *pbuser.UpdateUserInfoReq) (resp *pbuser.UpdateUserInfoResp, err error) {
@ -237,6 +278,82 @@ func (s *userServer) SetGlobalRecvMessageOpt(ctx context.Context, req *pbuser.Se
return resp, nil
}
// SetPhoneVisibility 设置手机号及其可见性0=所有人1=仅好友2=隐藏)。
// 只允许本人或管理员操作。
func (s *userServer) SetPhoneVisibility(ctx context.Context, req *pbuser.SetPhoneVisibilityReq) (*pbuser.SetPhoneVisibilityResp, error) {
if req.UserID == "" {
return nil, errs.ErrArgs.WrapMsg("userID is required")
}
if req.PhoneVisibility < 0 || req.PhoneVisibility > 2 {
return nil, errs.ErrArgs.WrapMsg("phoneVisibility must be 0, 1 or 2")
}
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
return nil, err
}
if _, err := s.db.FindWithError(ctx, []string{req.UserID}); err != nil {
return nil, err
}
m := map[string]any{
"phone_visibility": req.PhoneVisibility,
}
if req.Phone != "" {
m["phone"] = req.Phone
}
if err := s.db.UpdateByMap(ctx, req.UserID, m); err != nil {
return nil, err
}
s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserID)
return &pbuser.SetPhoneVisibilityResp{}, nil
}
// SetCallAcceptSetting 设置音视频通话接受权限0=所有人1=仅好友2=不接受任何通话)。
// 只允许本人或管理员操作。
func (s *userServer) SetCallAcceptSetting(ctx context.Context, req *pbuser.SetCallAcceptSettingReq) (*pbuser.SetCallAcceptSettingResp, error) {
if req.UserID == "" {
return nil, errs.ErrArgs.WrapMsg("userID is required")
}
if req.CallAcceptSetting < 0 || req.CallAcceptSetting > 2 {
return nil, errs.ErrArgs.WrapMsg("callAcceptSetting must be 0, 1 or 2")
}
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
return nil, err
}
if _, err := s.db.FindWithError(ctx, []string{req.UserID}); err != nil {
return nil, err
}
if err := s.db.UpdateByMap(ctx, req.UserID, map[string]any{
"call_accept_setting": req.CallAcceptSetting,
}); err != nil {
return nil, err
}
s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserID)
return &pbuser.SetCallAcceptSettingResp{}, nil
}
// SetMsgReceiveSetting 设置会话消息接收权限0=所有人1=仅好友2=所有人不可发送)。
// 只允许本人或管理员操作。
func (s *userServer) SetMsgReceiveSetting(ctx context.Context, req *pbuser.SetMsgReceiveSettingReq) (*pbuser.SetMsgReceiveSettingResp, error) {
if req.UserID == "" {
return nil, errs.ErrArgs.WrapMsg("userID is required")
}
if req.MsgReceiveSetting < 0 || req.MsgReceiveSetting > 2 {
return nil, errs.ErrArgs.WrapMsg("msgReceiveSetting must be 0, 1 or 2")
}
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
return nil, err
}
if _, err := s.db.FindWithError(ctx, []string{req.UserID}); err != nil {
return nil, err
}
if err := s.db.UpdateByMap(ctx, req.UserID, map[string]any{
"msg_receive_setting": req.MsgReceiveSetting,
}); err != nil {
return nil, err
}
s.friendNotificationSender.UserInfoUpdatedNotification(ctx, req.UserID)
return &pbuser.SetMsgReceiveSettingResp{}, nil
}
func (s *userServer) AccountCheck(ctx context.Context, req *pbuser.AccountCheckReq) (resp *pbuser.AccountCheckResp, err error) {
resp = &pbuser.AccountCheckResp{}
if datautil.Duplicate(req.CheckUserIDs) {

@ -31,6 +31,10 @@ func UserDB2Pb(user *relationtb.User) *sdkws.UserInfo {
CreateTime: user.CreateTime.UnixMilli(),
AppMangerLevel: user.AppMangerLevel,
GlobalRecvMsgOpt: user.GlobalRecvMsgOpt,
Phone: user.Phone,
PhoneVisibility: user.PhoneVisibility,
CallAcceptSetting: user.CallAcceptSetting,
MsgReceiveSetting: user.MsgReceiveSetting,
}
}
@ -90,6 +94,18 @@ func UserPb2DBMapEx(user *sdkws.UserInfoWithEx) map[string]any {
if user.GlobalRecvMsgOpt != nil {
val["global_recv_msg_opt"] = user.GlobalRecvMsgOpt.Value
}
if user.Phone != nil {
val["phone"] = user.Phone.Value
}
if user.PhoneVisibility != nil {
val["phone_visibility"] = user.PhoneVisibility.Value
}
if user.CallAcceptSetting != nil {
val["call_accept_setting"] = user.CallAcceptSetting.Value
}
if user.MsgReceiveSetting != nil {
val["msg_receive_setting"] = user.MsgReceiveSetting.Value
}
return val
}

@ -76,6 +76,7 @@ const (
MutedInGroup = 1402 // Member muted in the group
MutedGroup = 1403 // Group is muted
MsgAlreadyRevoke = 1404 // Message already revoked
MsgReceiveNotAllowed = 1405 // Recipient does not allow receiving messages from this sender
// Token error codes.
TokenExpiredError = 1501

@ -59,6 +59,7 @@ var (
ErrMutedInGroup = errs.NewCodeError(MutedInGroup, "MutedInGroup")
ErrMutedGroup = errs.NewCodeError(MutedGroup, "MutedGroup")
ErrMsgAlreadyRevoke = errs.NewCodeError(MsgAlreadyRevoke, "MsgAlreadyRevoke")
ErrMsgReceiveNotAllowed = errs.NewCodeError(MsgReceiveNotAllowed, "MsgReceiveNotAllowed")
ErrConnOverMaxNumLimit = errs.NewCodeError(ConnOverMaxNumLimit, "ConnOverMaxNumLimit")

@ -18,6 +18,13 @@ import (
"time"
)
// GroupPermission 群组操作权限枚举。
// 0=全员可操作默认1=仅群主/管理员可操作
const (
GroupPermAllMember = int32(0) // 全员均可
GroupPermAdminOnly = int32(1) // 仅群主/管理员
)
type Group struct {
GroupID string `bson:"group_id"`
GroupName string `bson:"group_name"`
@ -34,4 +41,12 @@ type Group struct {
ApplyMemberFriend int32 `bson:"apply_member_friend"`
NotificationUpdateTime time.Time `bson:"notification_update_time"`
NotificationUserID string `bson:"notification_user_id"`
// AllowSendMsg 0=全员可发消息 1=仅群主/管理员可发消息
AllowSendMsg int32 `bson:"allow_send_msg"`
// AllowPinMsg 0=全员可置顶消息 1=仅群主/管理员可置顶消息
AllowPinMsg int32 `bson:"allow_pin_msg"`
// AllowAddMember 0=全员可拉人入群 1=仅群主/管理员可拉人入群
AllowAddMember int32 `bson:"allow_add_member"`
// AllowEditGroupInfo 0=全员可编辑群资料 1=仅群主/管理员可编辑群资料
AllowEditGroupInfo int32 `bson:"allow_edit_group_info"`
}

@ -18,6 +18,30 @@ import (
"time"
)
// PhoneVisibility 手机号可见性枚举。
// 0=所有人可见, 1=仅好友可见, 2=完全隐藏
const (
PhoneVisibilityPublic int32 = 0
PhoneVisibilityFriends int32 = 1
PhoneVisibilityHidden int32 = 2
)
// CallAcceptSetting 音视频通话接受权限枚举。
// 0=所有人可发起, 1=仅好友可发起, 2=不接受任何通话
const (
CallAcceptSettingPublic int32 = 0
CallAcceptSettingFriends int32 = 1
CallAcceptSettingNobody int32 = 2
)
// MsgReceiveSetting 会话消息接收权限枚举。
// 0=所有人可发送, 1=仅好友可发送, 2=所有人不可发送
const (
MsgReceiveSettingPublic int32 = 0
MsgReceiveSettingFriends int32 = 1
MsgReceiveSettingNobody int32 = 2
)
type User struct {
UserID string `bson:"user_id"`
Nickname string `bson:"nickname"`
@ -26,6 +50,14 @@ type User struct {
AppMangerLevel int32 `bson:"app_manger_level"`
GlobalRecvMsgOpt int32 `bson:"global_recv_msg_opt"`
CreateTime time.Time `bson:"create_time"`
// Phone 用户手机号(明文,仅服务端留存,下发时按 PhoneVisibility 过滤)
Phone string `bson:"phone"`
// PhoneVisibility 0=所有人可见 1=仅好友可见 2=隐藏
PhoneVisibility int32 `bson:"phone_visibility"`
// CallAcceptSetting 0=所有人可发起 1=仅好友可发起 2=不接受任何通话
CallAcceptSetting int32 `bson:"call_accept_setting"`
// MsgReceiveSetting 0=所有人可发送 1=仅好友可发送 2=所有人不可发送
MsgReceiveSetting int32 `bson:"msg_receive_setting"`
}
func (u *User) GetNickname() string {

@ -21,3 +21,15 @@ func (x *RelationClient) GetFriendsInfo(ctx context.Context, ownerUserID string,
req := &relation.GetFriendInfoReq{OwnerUserID: ownerUserID, FriendUserIDs: friendUserIDs}
return extractField(ctx, x.FriendClient.GetFriendInfo, req, (*relation.GetFriendInfoResp).GetFriendInfos)
}
// IsFriend checks whether userID2 is in userID1's friend list.
func (x *RelationClient) IsFriend(ctx context.Context, ownerUserID, friendUserID string) (bool, error) {
resp, err := x.FriendClient.IsFriend(ctx, &relation.IsFriendReq{
UserID1: ownerUserID,
UserID2: friendUserID,
})
if err != nil {
return false, err
}
return resp.InUser1Friends, nil
}

Loading…
Cancel
Save