From fd768a10be36ec31f674fa291fcbe77b78a2855c Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 21 Feb 2020 18:08:40 +0100 Subject: Mattermost media objects in both ways + user/team profile pictures from MM to Matrix --- connector/mattermost/mattermost.go | 146 +++++++++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 30 deletions(-) (limited to 'connector/mattermost') diff --git a/connector/mattermost/mattermost.go b/connector/mattermost/mattermost.go index 330026a..73ea66b 100644 --- a/connector/mattermost/mattermost.go +++ b/connector/mattermost/mattermost.go @@ -1,10 +1,12 @@ package mattermost import ( + "net/http" "fmt" _ "os" "strings" "time" + "io/ioutil" "encoding/json" "github.com/mattermost/mattermost-server/model" @@ -210,9 +212,6 @@ func (mm *Mattermost) Leave(roomId RoomID) { } func (mm *Mattermost) Send(event *Event) error { - // TODO: attachements - // TODO: verify private messages work - post := &model.Post{ Message: event.Text, } @@ -248,8 +247,30 @@ func (mm *Mattermost) Send(event *Event) error { return fmt.Errorf("Invalid target") } + if event.Attachments != nil { + post.FileIds = []string{} + for _, file := range event.Attachments { + rdr, err := file.Read() + if err != nil { + return err + } + defer rdr.Close() + data, err := ioutil.ReadAll(rdr) + if err != nil { + return err + } + up_file, err := mm.conn.UploadFile(data, post.ChannelId, file.Filename()) + if err != nil { + log.Warnf("UploadFile error: %s", err) + return err + } + post.FileIds = append(post.FileIds, up_file) + } + } + _, resp := mm.conn.Client.CreatePost(post) if resp.Error != nil { + log.Warnf("CreatePost error: %s", resp.Error) return resp.Error } return nil @@ -277,16 +298,58 @@ func (mm *Mattermost) handleConnected() { if len(strings.Split(ch.Name, "__")) == 2 { continue // This is a DM channel } + id := mm.reverseRoomId(ch.Id) - chName := ch.DisplayName - if teamName := mm.conn.GetTeamName(ch.TeamId); teamName != "" { - chName = teamName + " / " + chName - } mm.handler.Joined(id) - mm.handler.RoomInfoUpdated(id, UserID(""), &RoomInfo{ - Name: chName, + + // Update room info + room_info := &RoomInfo{ + Name: ch.DisplayName, Topic: ch.Header, - }) + } + for _, t := range mm.conn.OtherTeams { + if t.Id == ch.TeamId { + if t.Team.DisplayName != "" { + room_info.Name = t.Team.DisplayName + " / " + room_info.Name + } else { + room_info.Name = t.Team.Name + " / " + room_info.Name + } + // TODO: cache last update time so we don't do this needlessly + if t.Team.LastTeamIconUpdate > 0 { + team_img, resp := mm.conn.Client.GetTeamIcon(t.Id, "") + if resp.Error == nil { + room_info.Picture = &BlobMediaObject{ + ObjectFilename: t.Team.Name, + ObjectMimetype: http.DetectContentType(team_img), + ObjectData: team_img, + } + } else { + log.Warnf("Could not get team image: %s", resp.Error) + } + } + break + } + } + mm.handler.RoomInfoUpdated(id, UserID(""), room_info) + + // Update member list + members, resp := mm.conn.Client.GetChannelMembers(ch.Id, 0, 1000, "") + if resp.Error == nil { + for _, mem := range *members { + if mem.UserId == mm.conn.User.Id { + continue + } + user := mm.conn.GetUser(mem.UserId) + if user != nil { + mm.ensureJoined(user, id) + mm.updateUserInfo(user) + } else { + log.Warnf("Could not find joined user: %s", mem.UserId) + } + } + } else { + log.Warnf("Could not get channel members: %s", resp.Error) + } } } @@ -306,6 +369,45 @@ func (mm *Mattermost) handleLoop(msgCh chan *matterclient.Message, quitCh chan b } } +func (mm *Mattermost) updateUserInfo(user *model.User) { + userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server)) + userDisp := user.GetDisplayName(model.SHOW_NICKNAME_FULLNAME) + + if lastdn, ok := mm.userdisplaynamemap[userId]; !ok || lastdn != userDisp { + ui := &UserInfo{ + DisplayName: userDisp, + } + if user.LastPictureUpdate > 0 { + // TODO: cache last update time so we don't do this needlessly + img, resp := mm.conn.Client.GetProfileImage(user.Id, "") + if resp.Error == nil { + ui.Avatar = &BlobMediaObject{ + ObjectFilename: user.Username, + ObjectMimetype: http.DetectContentType(img), + ObjectData: img, + } + } else { + log.Warnf("Could not get profile picture: %s", resp.Error) + } + mm.handler.UserInfoUpdated(userId, ui) + mm.userdisplaynamemap[userId] = userDisp + } + } +} + +func (mm *Mattermost) ensureJoined(user *model.User, roomId RoomID) { + userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server)) + cache_key := fmt.Sprintf("%s / %s", userId, roomId) + if _, ok := mm.sentjoinedmap[cache_key]; !ok { + mm.handler.Event(&Event{ + Author: userId, + Room: roomId, + Type: EVENT_JOIN, + }) + mm.sentjoinedmap[cache_key] = true + } +} + func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { channel_name := msg.Data["channel_name"].(string) post_str := msg.Data["post"].(string) @@ -326,14 +428,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { return fmt.Errorf("Invalid user") } userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server)) - - userDisp := user.GetDisplayName(model.SHOW_NICKNAME_FULLNAME) - if lastdn, ok := mm.userdisplaynamemap[userId]; !ok || lastdn != userDisp { - mm.handler.UserInfoUpdated(userId, &UserInfo{ - DisplayName: userDisp, - }) - mm.userdisplaynamemap[userId] = userDisp - } + mm.updateUserInfo(user) // Build message event msg_ev := &Event{ @@ -347,7 +442,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { // Handle files if post.FileIds != nil && len(post.FileIds) > 0 { - msg_ev.Attachements = []MediaObject{} + msg_ev.Attachments = []MediaObject{} for _, file := range post.Metadata.Files { blob, resp := mm.conn.Client.GetFile(file.Id) if resp.Error != nil { @@ -355,7 +450,6 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { } media_object := &BlobMediaObject{ ObjectFilename: file.Name, - ObjectSize: file.Size, ObjectMimetype: file.MimeType, ObjectData: blob, } @@ -365,7 +459,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { Height: file.Height, } } - msg_ev.Attachements = append(msg_ev.Attachements, media_object) + msg_ev.Attachments = append(msg_ev.Attachments, media_object) } } @@ -384,15 +478,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { return fmt.Errorf("Invalid channel id") } - cache_key := fmt.Sprintf("%s / %s", userId, roomId) - if _, ok := mm.sentjoinedmap[cache_key]; !ok { - mm.handler.Event(&Event{ - Author: userId, - Room: roomId, - Type: EVENT_JOIN, - }) - mm.sentjoinedmap[cache_key] = true - } + mm.ensureJoined(user, roomId) if post.Type == "system_header_change" { new_header := post.Props["new_header"].(string) -- cgit v1.2.3