From 05fc7c92f612fd4f42b7c6cbd993103b9f08f985 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Sun, 6 Oct 2024 13:27:01 -0500 Subject: [PATCH 1/5] fix: the scheduler for the mattermost remote The scheduler would never trigger, because the MM remote never populated the list of rooms the bot can talk in. The bot should now support the output_rooms option in rules. --- remote/mattermost/remote.go | 57 ++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/remote/mattermost/remote.go b/remote/mattermost/remote.go index d008e369..f276d0af 100644 --- a/remote/mattermost/remote.go +++ b/remote/mattermost/remote.go @@ -53,7 +53,7 @@ func (c *Client) Reaction(_ models.Message, rule models.Rule, _ *models.Bot) { } } -func (c *Client) Read(inputMsgs chan<- models.Message, _ map[string]models.Rule, _ *models.Bot) { +func (c *Client) Read(inputMsgs chan<- models.Message, _ map[string]models.Rule, bot *models.Bot) { api := c.new() ctx := context.Background() @@ -68,6 +68,30 @@ func (c *Client) Read(inputMsgs chan<- models.Message, _ map[string]models.Rule, c.BotID = user.Username + go func(b *models.Bot) { + rooms := make(map[string]string) + + teams, _, err := api.GetTeamsForUser(ctx, user.Id, "") + if err != nil { + log.Fatal().Err(err) + } + + for _, team := range teams { + r, _, err := api.GetChannelsForTeamForUser(ctx, team.Id, user.Id, false, "") + if err != nil { + log.Fatal().Err(err) + } + for _, i := range r { + teamRoom := fmt.Sprintf("%s/%s", team.Name, i.Name) + rooms[teamRoom] = i.Id + } + } + bot.Rooms = rooms + }(bot) + + foo, _ := json.MarshalIndent(bot.Rooms, "", " ") + fmt.Println(string(foo)) + url := "wss://" + c.Server if c.Insecure { url = "ws://" + c.Server @@ -163,7 +187,7 @@ func populateMessage( return message } -func (c *Client) Send(message models.Message, _ *models.Bot) { +func (c *Client) Send(message models.Message, bot *models.Bot) { api := c.new() ctx := context.Background() @@ -176,11 +200,30 @@ func (c *Client) Send(message models.Message, _ *models.Bot) { c.BotID = user.Username } - post := &model.Post{} - post.ChannelId = message.ChannelID - post.Message = message.Output + if err := send(api, message); err != nil { + log.Error().Err(err) + } + +} + +func send(api *model.Client4, message models.Message) error { - if _, _, err := api.CreatePost(ctx, post); err != nil { - log.Error().Err(err).Msg("failed to create post") + ctx := context.Background() + if message.DirectMessageOnly { + // TODO impliment + } else { + if len(message.OutputToRooms) > 0 { + post := &model.Post{} + post.Message = message.Output + for _, roomID := range message.OutputToRooms { + post.ChannelId = roomID + log.Debug().Msgf("Posting to %s, message: %v", post.ChannelId, post.Message) + _, _, err := api.CreatePost(ctx, post) + return err + + } + } } + + return nil } From 9c206e160c103ec98e60407f6ee1c9d702bca172 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Mon, 7 Oct 2024 09:04:17 -0500 Subject: [PATCH 2/5] fix: MM handle direct messages and output to users --- remote/mattermost/remote.go | 134 +++++++++++++++++++++++++++++------- 1 file changed, 108 insertions(+), 26 deletions(-) diff --git a/remote/mattermost/remote.go b/remote/mattermost/remote.go index f276d0af..379d183d 100644 --- a/remote/mattermost/remote.go +++ b/remote/mattermost/remote.go @@ -5,7 +5,9 @@ package mattermost import ( "context" "encoding/json" + "fmt" "strconv" + "strings" "github.com/mattermost/mattermost/server/public/model" "github.com/rs/zerolog/log" @@ -27,8 +29,6 @@ var _ remote.Remote = (*Client)(nil) // instantiate a new mattermost client. func (c *Client) new() *model.Client4 { - log.Info().Msgf("%#v", c) - url := "https://" + c.Server if c.Insecure { url = "http://" + c.Server @@ -89,9 +89,6 @@ func (c *Client) Read(inputMsgs chan<- models.Message, _ map[string]models.Rule, bot.Rooms = rooms }(bot) - foo, _ := json.MarshalIndent(bot.Rooms, "", " ") - fmt.Println(string(foo)) - url := "wss://" + c.Server if c.Insecure { url = "ws://" + c.Server @@ -191,39 +188,124 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { api := c.new() ctx := context.Background() - if user, resp, err := api.GetUser(ctx, "me", ""); err != nil { + user, _, err := api.GetUser(ctx, "me", "") + if err != nil { log.Fatal().Msgf("could not login, %s", err) - } else { - log.Info().Interface("user", user.Username).Interface("resp", resp).Msg("") - log.Info().Msg("logged in to mattermost") + } + log.Info().Msg("logged in to mattermost") + + c.BotID = user.Username + + post := &model.Post{} + post.Message = message.Output + + if message.DirectMessageOnly { + target := message.Vars["_user.id"] + log.Info().Msgf("Creating direct message between %s, and %s", + target, c.BotID) + directChannel, _, err := api.CreateDirectChannel(ctx, + user.Id, target) + if err != nil { + log.Error().Msgf("%v", err) + return + } - c.BotID = user.Username + post.ChannelId = directChannel.Id + if _, resp, err := api.CreatePost(ctx, post); err != nil { + log.Error().Err(err) + } else { + log.Debug().Interface("responce", resp).Msg("") + } + + return } - if err := send(api, message); err != nil { - log.Error().Err(err) + if len(message.OutputToRooms) > 0 { + for _, roomID := range message.OutputToRooms { + post.ChannelId = roomID + log.Debug().Msgf("Posting message: %v, to room %v", + post.Message, post.ChannelId) + if _, _, err := api.CreatePost(ctx, post); err != nil { + log.Error().Err(err) + } + + } + } + + if len(message.OutputToUsers) > 0 { + for _, u := range message.OutputToUsers { + log.Info().Msgf("Getting user id for %s", u) + target, err := getUserID(api, u) + log.Info().Msgf("Creating direct message between %s, and %s", + target, c.BotID) + directChannel, _, err := api.CreateDirectChannel(ctx, + user.Id, target) + if err != nil { + log.Error().Err(err) + break + } + + post.ChannelId = directChannel.Id + if _, resp, err := api.CreatePost(ctx, post); err != nil { + log.Error().Err(err) + } else { + log.Debug().Interface("responce", resp).Msg("") + } + + } + } + + if len(message.OutputToRooms) == 0 && len(message.OutputToUsers) == 0 { + post := &model.Post{} + post.ChannelId = message.ChannelID + post.Message = message.Output + + if _, _, err := api.CreatePost(ctx, post); err != nil { + log.Error().Err(err).Msg("failed to create post") + } } } -func send(api *model.Client4, message models.Message) error { +func getUserID(api *model.Client4, username string) (string, error) { + log.Info().Msgf("Getting user id for %s", username) ctx := context.Background() - if message.DirectMessageOnly { - // TODO impliment - } else { - if len(message.OutputToRooms) > 0 { - post := &model.Post{} - post.Message = message.Output - for _, roomID := range message.OutputToRooms { - post.ChannelId = roomID - log.Debug().Msgf("Posting to %s, message: %v", post.ChannelId, post.Message) - _, _, err := api.CreatePost(ctx, post) - return err - } - } + // trim any leading '@' from the provided username + username = strings.TrimPrefix(username, "@") + + user, _, err := api.GetUserByUsername(ctx, username, "") + if err != nil { + return "", nil + + } + return user.Id, nil +} + +func (c Client) sendDirectMessage(api *model.Client4, message models.Message) error { + userID := message.Vars["_user.id"] + ctx := context.Background() + log.Info().Msgf("Creating direct message between %s, and %s", + userID, c.BotID) + directChannel, _, err := api.CreateDirectChannel(ctx, + userID, c.BotID) + if err != nil { + log.Error().Msgf("%v", err) + return err } + post := &model.Post{} + post.Message = message.Output + post.ChannelId = directChannel.Id + return nil +} + +func (c Client) sendMessage(api *model.Client4, ctx context.Context, post *model.Post) error { + if _, resp, err := api.CreatePost(ctx, post); err != nil { + log.Error().Err(err) + } else { + log.Debug().Interface("responce", resp).Msg("") + } return nil } From c4f382c1075e3767797e135f057d5d22966d30a9 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Tue, 8 Oct 2024 17:12:57 -0500 Subject: [PATCH 3/5] chore: pull the direct message logic into function Helps simplify the code to call the function once instead of running through all the steps to create a direct message every time. --- remote/mattermost/remote.go | 79 +++++++++++++++---------------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/remote/mattermost/remote.go b/remote/mattermost/remote.go index 379d183d..e3028d3e 100644 --- a/remote/mattermost/remote.go +++ b/remote/mattermost/remote.go @@ -194,39 +194,28 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { } log.Info().Msg("logged in to mattermost") - c.BotID = user.Username + c.BotID = user.Id post := &model.Post{} post.Message = message.Output if message.DirectMessageOnly { - target := message.Vars["_user.id"] - log.Info().Msgf("Creating direct message between %s, and %s", - target, c.BotID) - directChannel, _, err := api.CreateDirectChannel(ctx, - user.Id, target) + post.UserId = message.Vars["_user.id"] + err = c.sendDirectMessage(api, ctx, post) if err != nil { log.Error().Msgf("%v", err) return } - - post.ChannelId = directChannel.Id - if _, resp, err := api.CreatePost(ctx, post); err != nil { - log.Error().Err(err) - } else { - log.Debug().Interface("responce", resp).Msg("") - } - return } if len(message.OutputToRooms) > 0 { for _, roomID := range message.OutputToRooms { post.ChannelId = roomID - log.Debug().Msgf("Posting message: %v, to room %v", - post.Message, post.ChannelId) - if _, _, err := api.CreatePost(ctx, post); err != nil { - log.Error().Err(err) + + err = sendMessage(api, ctx, post) + if err != nil { + log.Error().Err(err).Msgf("Unable to post message to %v", roomID) } } @@ -234,23 +223,11 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { if len(message.OutputToUsers) > 0 { for _, u := range message.OutputToUsers { - log.Info().Msgf("Getting user id for %s", u) - target, err := getUserID(api, u) - log.Info().Msgf("Creating direct message between %s, and %s", - target, c.BotID) - directChannel, _, err := api.CreateDirectChannel(ctx, - user.Id, target) + post.UserId, err = getUserID(api, u) if err != nil { log.Error().Err(err) - break - } - - post.ChannelId = directChannel.Id - if _, resp, err := api.CreatePost(ctx, post); err != nil { - log.Error().Err(err) - } else { - log.Debug().Interface("responce", resp).Msg("") } + c.sendDirectMessage(api, ctx, post) } } @@ -268,7 +245,8 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { } func getUserID(api *model.Client4, username string) (string, error) { - log.Info().Msgf("Getting user id for %s", username) + + log.Debug().Msgf("Getting user id for %s", username) ctx := context.Background() @@ -277,33 +255,40 @@ func getUserID(api *model.Client4, username string) (string, error) { user, _, err := api.GetUserByUsername(ctx, username, "") if err != nil { - return "", nil + log.Error().Err(err).Msg("Error retreving user id") + return "", err } + + log.Debug().Msgf("%s user id is %s", username, user.Id) return user.Id, nil } -func (c Client) sendDirectMessage(api *model.Client4, message models.Message) error { - userID := message.Vars["_user.id"] - ctx := context.Background() - log.Info().Msgf("Creating direct message between %s, and %s", - userID, c.BotID) - directChannel, _, err := api.CreateDirectChannel(ctx, - userID, c.BotID) +func (c Client) sendDirectMessage(api *model.Client4, ctx context.Context, post *model.Post) error { + + if post.UserId == "" { + err := fmt.Errorf("No user id in the post, unable to create a direct message") + log.Error().Err(err).Msg("Unable to create direct message channel") + return err + } + + log.Debug().Msgf("Creating direct message between %s, and %s", post.UserId, c.BotID) + + directChannel, resp, err := api.CreateDirectChannel(ctx, post.UserId, c.BotID) if err != nil { - log.Error().Msgf("%v", err) + log.Error().Interface("resp", resp).Err(err).Msg("Unable to create direct message channel") return err } - post := &model.Post{} - post.Message = message.Output post.ChannelId = directChannel.Id - return nil + + return sendMessage(api, ctx, post) } -func (c Client) sendMessage(api *model.Client4, ctx context.Context, post *model.Post) error { +func sendMessage(api *model.Client4, ctx context.Context, post *model.Post) error { if _, resp, err := api.CreatePost(ctx, post); err != nil { - log.Error().Err(err) + log.Error().Err(err).Msg("Unable to post message") + return err } else { log.Debug().Interface("responce", resp).Msg("") } From 998576aa7d1203e7f21c369f41119e7d98de5be2 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Fri, 11 Oct 2024 18:11:40 -0500 Subject: [PATCH 4/5] chore: fix some golang-ci linter issues stuff like cuddled assignements, unnessisary new lines, and putting the context argument first in function parameters --- remote/mattermost/remote.go | 41 +++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/remote/mattermost/remote.go b/remote/mattermost/remote.go index e3028d3e..64225a6c 100644 --- a/remote/mattermost/remote.go +++ b/remote/mattermost/remote.go @@ -81,12 +81,14 @@ func (c *Client) Read(inputMsgs chan<- models.Message, _ map[string]models.Rule, if err != nil { log.Fatal().Err(err) } + for _, i := range r { teamRoom := fmt.Sprintf("%s/%s", team.Name, i.Name) rooms[teamRoom] = i.Id } } - bot.Rooms = rooms + + b.Rooms = rooms }(bot) url := "wss://" + c.Server @@ -184,7 +186,7 @@ func populateMessage( return message } -func (c *Client) Send(message models.Message, bot *models.Bot) { +func (c *Client) Send(message models.Message, _ *models.Bot) { api := c.new() ctx := context.Background() @@ -192,20 +194,22 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { if err != nil { log.Fatal().Msgf("could not login, %s", err) } + log.Info().Msg("logged in to mattermost") c.BotID = user.Id - post := &model.Post{} post.Message = message.Output if message.DirectMessageOnly { post.UserId = message.Vars["_user.id"] - err = c.sendDirectMessage(api, ctx, post) + err = c.sendDirectMessage(ctx, api, post) + if err != nil { log.Error().Msgf("%v", err) return } + return } @@ -213,11 +217,10 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { for _, roomID := range message.OutputToRooms { post.ChannelId = roomID - err = sendMessage(api, ctx, post) + err = sendMessage(ctx, api, post) if err != nil { log.Error().Err(err).Msgf("Unable to post message to %v", roomID) } - } } @@ -227,8 +230,10 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { if err != nil { log.Error().Err(err) } - c.sendDirectMessage(api, ctx, post) + if err = c.sendDirectMessage(ctx, api, post); err != nil { + log.Error().Err(err) + } } } @@ -241,11 +246,9 @@ func (c *Client) Send(message models.Message, bot *models.Bot) { log.Error().Err(err).Msg("failed to create post") } } - } func getUserID(api *model.Client4, username string) (string, error) { - log.Debug().Msgf("Getting user id for %s", username) ctx := context.Background() @@ -257,18 +260,18 @@ func getUserID(api *model.Client4, username string) (string, error) { if err != nil { log.Error().Err(err).Msg("Error retreving user id") return "", err - } log.Debug().Msgf("%s user id is %s", username, user.Id) + return user.Id, nil } -func (c Client) sendDirectMessage(api *model.Client4, ctx context.Context, post *model.Post) error { - +func (c Client) sendDirectMessage(ctx context.Context, api *model.Client4, post *model.Post) error { if post.UserId == "" { - err := fmt.Errorf("No user id in the post, unable to create a direct message") + err := fmt.Errorf("no user id in the post, unable to create a direct message") log.Error().Err(err).Msg("Unable to create direct message channel") + return err } @@ -282,15 +285,17 @@ func (c Client) sendDirectMessage(api *model.Client4, ctx context.Context, post post.ChannelId = directChannel.Id - return sendMessage(api, ctx, post) + return sendMessage(ctx, api, post) } -func sendMessage(api *model.Client4, ctx context.Context, post *model.Post) error { - if _, resp, err := api.CreatePost(ctx, post); err != nil { +func sendMessage(ctx context.Context, api *model.Client4, post *model.Post) error { + _, resp, err := api.CreatePost(ctx, post) + if err != nil { log.Error().Err(err).Msg("Unable to post message") return err - } else { - log.Debug().Interface("responce", resp).Msg("") } + + log.Debug().Interface("response", resp).Msg("") + return nil } From ee6722b5ceb45c493864f0f620d003128c50688a Mon Sep 17 00:00:00 2001 From: James Conroy Date: Tue, 29 Oct 2024 16:46:40 -0500 Subject: [PATCH 5/5] chore: start log messages lowercase Sentence case is not consistent with the rest of the log messages, lowercase is preferred. Co-authored-by: david may <1301201+wass3r@users.noreply.github.com> --- remote/mattermost/remote.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/remote/mattermost/remote.go b/remote/mattermost/remote.go index 64225a6c..02ff7408 100644 --- a/remote/mattermost/remote.go +++ b/remote/mattermost/remote.go @@ -219,7 +219,7 @@ func (c *Client) Send(message models.Message, _ *models.Bot) { err = sendMessage(ctx, api, post) if err != nil { - log.Error().Err(err).Msgf("Unable to post message to %v", roomID) + log.Error().Err(err).Msgf("unable to post message to %v", roomID) } } } @@ -249,7 +249,7 @@ func (c *Client) Send(message models.Message, _ *models.Bot) { } func getUserID(api *model.Client4, username string) (string, error) { - log.Debug().Msgf("Getting user id for %s", username) + log.Debug().Msgf("getting user id for %s", username) ctx := context.Background() @@ -258,7 +258,7 @@ func getUserID(api *model.Client4, username string) (string, error) { user, _, err := api.GetUserByUsername(ctx, username, "") if err != nil { - log.Error().Err(err).Msg("Error retreving user id") + log.Error().Err(err).Msg("error retreving user id") return "", err } @@ -270,16 +270,16 @@ func getUserID(api *model.Client4, username string) (string, error) { func (c Client) sendDirectMessage(ctx context.Context, api *model.Client4, post *model.Post) error { if post.UserId == "" { err := fmt.Errorf("no user id in the post, unable to create a direct message") - log.Error().Err(err).Msg("Unable to create direct message channel") + log.Error().Err(err).Msg("unable to create direct message channel") return err } - log.Debug().Msgf("Creating direct message between %s, and %s", post.UserId, c.BotID) + log.Debug().Msgf("creating direct message between %s, and %s", post.UserId, c.BotID) directChannel, resp, err := api.CreateDirectChannel(ctx, post.UserId, c.BotID) if err != nil { - log.Error().Interface("resp", resp).Err(err).Msg("Unable to create direct message channel") + log.Error().Interface("resp", resp).Err(err).Msg("unable to create direct message channel") return err } @@ -291,7 +291,7 @@ func (c Client) sendDirectMessage(ctx context.Context, api *model.Client4, post func sendMessage(ctx context.Context, api *model.Client4, post *model.Post) error { _, resp, err := api.CreatePost(ctx, post) if err != nil { - log.Error().Err(err).Msg("Unable to post message") + log.Error().Err(err).Msg("unable to post message") return err }