You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
7.7 KiB
203 lines
7.7 KiB
// Copyright © 2023 OpenIM SDK. 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 conversation_msg
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"github.com/openimsdk/openim-sdk-core/v3/internal/util"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/common"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/constant"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/db/model_struct"
|
|
"github.com/openimsdk/openim-sdk-core/v3/pkg/utils"
|
|
"github.com/openimsdk/openim-sdk-core/v3/sdk_struct"
|
|
"github.com/openimsdk/tools/utils/timeutil"
|
|
|
|
"github.com/jinzhu/copier"
|
|
pbMsg "github.com/openimsdk/protocol/msg"
|
|
"github.com/openimsdk/protocol/sdkws"
|
|
"github.com/openimsdk/tools/log"
|
|
)
|
|
|
|
func (c *Conversation) doRevokeMsg(ctx context.Context, msg *sdkws.MsgData) {
|
|
var tips sdkws.RevokeMsgTips
|
|
if err := utils.UnmarshalNotificationElem(msg.Content, &tips); err != nil {
|
|
log.ZError(ctx, "unmarshal failed", err, "msg", msg)
|
|
return
|
|
}
|
|
log.ZDebug(ctx, "do revokeMessage", "tips", &tips)
|
|
c.revokeMessage(ctx, &tips)
|
|
}
|
|
|
|
func (c *Conversation) revokeMessage(ctx context.Context, tips *sdkws.RevokeMsgTips) {
|
|
revokedMsg, err := c.db.GetMessageBySeq(ctx, tips.ConversationID, tips.Seq)
|
|
if err != nil {
|
|
log.ZError(ctx, "GetMessageBySeq failed", err, "tips", &tips)
|
|
return
|
|
}
|
|
var revokerRole int32
|
|
var revokerNickname string
|
|
if tips.IsAdminRevoke || tips.SesstionType == constant.SingleChatType {
|
|
_, userName, err := c.getUserNameAndFaceURL(ctx, tips.RevokerUserID)
|
|
if err != nil {
|
|
log.ZError(ctx, "GetUserNameAndFaceURL failed", err, "tips", &tips)
|
|
} else {
|
|
log.ZDebug(ctx, "revoker user name", "userName", userName)
|
|
}
|
|
revokerNickname = userName
|
|
} else if tips.SesstionType == constant.SuperGroupChatType {
|
|
conversation, err := c.db.GetConversation(ctx, tips.ConversationID)
|
|
if err != nil {
|
|
log.ZError(ctx, "GetConversation failed", err, "conversationID", tips.ConversationID)
|
|
return
|
|
}
|
|
groupMember, err := c.db.GetGroupMemberInfoByGroupIDUserID(ctx, conversation.GroupID, tips.RevokerUserID)
|
|
if err != nil {
|
|
log.ZError(ctx, "GetGroupMemberInfoByGroupIDUserID failed", err, "tips", &tips)
|
|
} else {
|
|
log.ZDebug(ctx, "revoker member name", "groupMember", groupMember)
|
|
revokerRole = groupMember.RoleLevel
|
|
revokerNickname = groupMember.Nickname
|
|
}
|
|
}
|
|
m := sdk_struct.MessageRevoked{
|
|
RevokerID: tips.RevokerUserID,
|
|
RevokerRole: revokerRole,
|
|
ClientMsgID: revokedMsg.ClientMsgID,
|
|
RevokerNickname: revokerNickname,
|
|
RevokeTime: tips.RevokeTime,
|
|
SourceMessageSendTime: revokedMsg.SendTime,
|
|
SourceMessageSendID: revokedMsg.SendID,
|
|
SourceMessageSenderNickname: revokedMsg.SenderNickname,
|
|
SessionType: tips.SesstionType,
|
|
Seq: tips.Seq,
|
|
Ex: revokedMsg.Ex,
|
|
IsAdminRevoke: tips.IsAdminRevoke,
|
|
}
|
|
// log.ZDebug(ctx, "callback revokeMessage", "m", m)
|
|
var n sdk_struct.NotificationElem
|
|
n.Detail = utils.StructToJsonString(m)
|
|
if err := c.db.UpdateMessageBySeq(ctx, tips.ConversationID, &model_struct.LocalChatLog{Seq: tips.Seq,
|
|
Content: utils.StructToJsonString(n), ContentType: constant.RevokeNotification}); err != nil {
|
|
log.ZError(ctx, "UpdateMessageBySeq failed", err, "tips", &tips)
|
|
return
|
|
}
|
|
conversation, err := c.db.GetConversation(ctx, tips.ConversationID)
|
|
if err != nil {
|
|
log.ZError(ctx, "GetConversation failed", err, "tips", &tips)
|
|
return
|
|
}
|
|
var latestMsg sdk_struct.MsgStruct
|
|
utils.JsonStringToStruct(conversation.LatestMsg, &latestMsg)
|
|
log.ZDebug(ctx, "latestMsg", "latestMsg", &latestMsg, "seq", tips.Seq)
|
|
if latestMsg.Seq <= tips.Seq {
|
|
var newLatesetMsg sdk_struct.MsgStruct
|
|
msgs, err := c.db.GetMessageListNoTime(ctx, tips.ConversationID, 1, false)
|
|
if err != nil || len(msgs) == 0 {
|
|
log.ZError(ctx, "GetMessageListNoTime failed", err, "tips", &tips)
|
|
return
|
|
}
|
|
log.ZDebug(ctx, "latestMsg is revoked", "seq", tips.Seq, "msg", msgs[0])
|
|
copier.Copy(&newLatesetMsg, msgs[0])
|
|
err = c.msgConvert(&newLatesetMsg)
|
|
if err != nil {
|
|
log.ZError(ctx, "parsing data error", err, latestMsg)
|
|
} else {
|
|
log.ZDebug(ctx, "revoke update conversatoin", "msg", utils.StructToJsonString(newLatesetMsg))
|
|
if err := c.db.UpdateColumnsConversation(ctx, tips.ConversationID, map[string]interface{}{"latest_msg": utils.StructToJsonString(newLatesetMsg),
|
|
"latest_msg_send_time": newLatesetMsg.SendTime}); err != nil {
|
|
log.ZError(ctx, "UpdateColumnsConversation failed", err, "newLatesetMsg", newLatesetMsg)
|
|
} else {
|
|
c.doUpdateConversation(common.Cmd2Value{Value: common.UpdateConNode{Action: constant.ConChange, Args: []string{tips.ConversationID}}})
|
|
}
|
|
}
|
|
}
|
|
c.msgListener().OnNewRecvMessageRevoked(utils.StructToJsonString(m))
|
|
msgList, err := c.db.SearchAllMessageByContentType(ctx, conversation.ConversationID, constant.Quote)
|
|
if err != nil {
|
|
log.ZError(ctx, "SearchAllMessageByContentType failed", err, "tips", &tips)
|
|
return
|
|
}
|
|
for _, v := range msgList {
|
|
c.quoteMsgRevokeHandle(ctx, tips.ConversationID, v, m)
|
|
}
|
|
}
|
|
|
|
func (c *Conversation) quoteMsgRevokeHandle(ctx context.Context, conversationID string, v *model_struct.LocalChatLog, revokedMsg sdk_struct.MessageRevoked) {
|
|
s := sdk_struct.MsgStruct{}
|
|
_ = utils.JsonStringToStruct(v.Content, &s.QuoteElem)
|
|
|
|
if s.QuoteElem.QuoteMessage == nil {
|
|
return
|
|
}
|
|
if s.QuoteElem.QuoteMessage.ClientMsgID != revokedMsg.ClientMsgID {
|
|
return
|
|
}
|
|
s.QuoteElem.QuoteMessage.Content = utils.StructToJsonString(revokedMsg)
|
|
s.QuoteElem.QuoteMessage.ContentType = constant.RevokeNotification
|
|
v.Content = utils.StructToJsonString(s.QuoteElem)
|
|
if err := c.db.UpdateMessageBySeq(ctx, conversationID, v); err != nil {
|
|
log.ZError(ctx, "UpdateMessage failed", err, "v", v)
|
|
}
|
|
}
|
|
|
|
func (c *Conversation) revokeOneMessage(ctx context.Context, conversationID, clientMsgID string) error {
|
|
conversation, err := c.db.GetConversation(ctx, conversationID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
message, err := c.db.GetMessage(ctx, conversationID, clientMsgID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if message.Status != constant.MsgStatusSendSuccess {
|
|
return errors.New("only send success message can be revoked")
|
|
}
|
|
switch conversation.ConversationType {
|
|
case constant.SingleChatType:
|
|
if message.SendID != c.loginUserID {
|
|
return errors.New("only send by yourself message can be revoked")
|
|
}
|
|
case constant.SuperGroupChatType:
|
|
if message.SendID != c.loginUserID {
|
|
groupAdmins, err := c.db.GetGroupMemberOwnerAndAdminDB(ctx, conversation.GroupID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var isAdmin bool
|
|
for _, member := range groupAdmins {
|
|
if member.UserID == c.loginUserID {
|
|
isAdmin = true
|
|
break
|
|
}
|
|
}
|
|
if !isAdmin {
|
|
return errors.New("only group admin can revoke message")
|
|
}
|
|
}
|
|
}
|
|
if err := util.ApiPost(ctx, constant.RevokeMsgRouter, pbMsg.RevokeMsgReq{ConversationID: conversationID, Seq: message.Seq, UserID: c.loginUserID}, nil); err != nil {
|
|
return err
|
|
}
|
|
c.revokeMessage(ctx, &sdkws.RevokeMsgTips{
|
|
ConversationID: conversationID,
|
|
Seq: message.Seq,
|
|
RevokerUserID: c.loginUserID,
|
|
RevokeTime: timeutil.GetCurrentTimestampBySecond(),
|
|
SesstionType: conversation.ConversationType,
|
|
ClientMsgID: clientMsgID,
|
|
})
|
|
return nil
|
|
}
|
|
|