package matterclient import ( "crypto/md5" "encoding/json" "fmt" "strings" "github.com/mattermost/mattermost-server/v6/model" ) func (m *Client) parseResponse(rmsg *model.WebSocketResponse) { m.logger.Debugf("getting response: %#v", rmsg) } func (m *Client) DeleteMessage(postID string) error { _, err := m.Client.DeletePost(postID) if err != nil { return err } return nil } func (m *Client) EditMessage(postID string, text string) (string, error) { post := &model.Post{Message: text, Id: postID} res, _, err := m.Client.UpdatePost(postID, post) if err != nil { return "", err } return res.Id, nil } func (m *Client) GetFileLinks(filenames []string) []string { uriScheme := "https://" if m.NoTLS { uriScheme = "http://" } var output []string for _, f := range filenames { res, _, err := m.Client.GetFileLink(f) if err != nil { // public links is probably disabled, create the link ourselves output = append(output, uriScheme+m.Credentials.Server+model.APIURLSuffix+"/files/"+f) continue } output = append(output, res) } return output } func (m *Client) GetPosts(channelID string, limit int) *model.PostList { for { res, resp, err := m.Client.GetPostsForChannel(channelID, 0, limit, "", true) if err == nil { return res } if err := m.HandleRatelimit("GetPostsForChannel", resp); err != nil { return nil } } } func (m *Client) GetPostsSince(channelID string, time int64) *model.PostList { for { res, resp, err := m.Client.GetPostsSince(channelID, time, true) if err == nil { return res } if err := m.HandleRatelimit("GetPostsSince", resp); err != nil { return nil } } } func (m *Client) GetPublicLink(filename string) string { res, _, err := m.Client.GetFileLink(filename) if err != nil { return "" } return res } func (m *Client) GetPublicLinks(filenames []string) []string { var output []string for _, f := range filenames { res, _, err := m.Client.GetFileLink(f) if err != nil { continue } output = append(output, res) } return output } func (m *Client) PostMessage(channelID string, text string, rootID string) (string, error) { post := &model.Post{ ChannelId: channelID, Message: text, RootId: rootID, } for { res, resp, err := m.Client.CreatePost(post) if err == nil { return res.Id, nil } if err := m.HandleRatelimit("CreatePost", resp); err != nil { return "", err } } } func (m *Client) PostMessageWithFiles(channelID string, text string, rootID string, fileIds []string) (string, error) { post := &model.Post{ ChannelId: channelID, Message: text, RootId: rootID, FileIds: fileIds, } for { res, resp, err := m.Client.CreatePost(post) if err == nil { return res.Id, nil } if err := m.HandleRatelimit("CreatePost", resp); err != nil { return "", err } } } func (m *Client) SearchPosts(query string) *model.PostList { res, _, err := m.Client.SearchPosts(m.Team.ID, query, false) if err != nil { return nil } return res } // SendDirectMessage sends a direct message to specified user func (m *Client) SendDirectMessage(toUserID string, msg string, rootID string) error { return m.SendDirectMessageProps(toUserID, msg, rootID, nil) } func (m *Client) SendDirectMessageProps(toUserID string, msg string, rootID string, props map[string]interface{}) error { m.logger.Debugf("SendDirectMessage to %s, msg %s", toUserID, msg) for { // create DM channel (only happens on first message) _, resp, err := m.Client.CreateDirectChannel(m.User.Id, toUserID) if err == nil { break } if err := m.HandleRatelimit("CreateDirectChannel", resp); err != nil { m.logger.Debugf("SendDirectMessage to %#v failed: %s", toUserID, err) return err } } channelName := model.GetDMNameFromIds(toUserID, m.User.Id) // update our channels if err := m.UpdateChannels(); err != nil { m.logger.Errorf("failed to update channels: %#v", err) } // build & send the message msg = strings.ReplaceAll(msg, "\r", "") post := &model.Post{ ChannelId: m.GetChannelID(channelName, m.Team.ID), Message: msg, RootId: rootID, } post.SetProps(props) for { _, resp, err := m.Client.CreatePost(post) if err == nil { return nil } if err := m.HandleRatelimit("CreatePost", resp); err != nil { return err } } } func (m *Client) UploadFile(data []byte, channelID string, filename string) (string, error) { f, _, err := m.Client.UploadFile(data, channelID, filename) if err != nil { return "", err } return f.FileInfos[0].Id, nil } func (m *Client) parseActionPost(rmsg *Message) { // add post to cache, if it already exists don't relay this again. // this should fix reposts if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.GetData()["post"].(string)), true); ok && rmsg.Raw.EventType() != model.WebsocketEventPostDeleted { m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.GetData()["post"].(string)) rmsg.Text = "" return } var data model.Post if err := json.NewDecoder(strings.NewReader(rmsg.Raw.GetData()["post"].(string))).Decode(&data); err != nil { return } // we don't have the user, refresh the userlist if m.GetUser(data.UserId) == nil { m.logger.Infof("User '%v' is not known, ignoring message '%#v'", data.UserId, data) return } rmsg.Username = m.GetUserName(data.UserId) rmsg.Channel = m.GetChannelName(data.ChannelId) rmsg.UserID = data.UserId rmsg.Type = data.Type teamid, _ := rmsg.Raw.GetData()["team_id"].(string) // edit messsages have no team_id for some reason if teamid == "" { // we can find the team_id from the channelid teamid = m.GetChannelTeamID(data.ChannelId) rmsg.Raw.GetData()["team_id"] = teamid } if teamid != "" { rmsg.Team = m.GetTeamName(teamid) } // direct message if rmsg.Raw.GetData()["channel_type"] == "D" { rmsg.Channel = m.GetUser(data.UserId).Username } rmsg.Text = data.Message rmsg.Post = &data } func (m *Client) parseMessage(rmsg *Message) { switch rmsg.Raw.EventType() { case model.WebsocketEventPosted, model.WebsocketEventPostEdited, model.WebsocketEventPostDeleted: m.parseActionPost(rmsg) case "user_updated": if user, ok := rmsg.Raw.GetData()["user"].(*model.User); ok { m.UpdateUser(user.Id) } case "group_added": if err := m.UpdateChannels(); err != nil { m.logger.Errorf("failed to update channels: %#v", err) } } } func digestString(s string) string { return fmt.Sprintf("%x", md5.Sum([]byte(s))) //nolint:gosec }