From 987869119793a34a26bf12f293c8c6dc22edd5b6 Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Wed, 17 Apr 2024 15:48:50 +0530 Subject: [PATCH 1/3] [MM-387] Add a global welcome message field --- README.md | 7 +++++++ server/configuration.go | 3 +++ server/hooks.go | 40 +++++++++++++++++++++++++++++++++++++- server/message_template.go | 8 ++++++++ server/welcomebot.go | 23 ++++++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c8db5f98e..3e114c04e 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ where - **ActionName**: Sets the action name used by the plugin to identify which action is taken by a user. - **ActionSuccessfulMessage**: Message posted after the user takes this action and joins the specified channels. - **ChannelsAddedTo**: List of channel names the user is added to. Must be the channel handle used in the URL, in lowercase. For example, in the following URL the **channel name** value is `my-channel`: https://example.com/my-team/channels/my-channel +- **GlobalWelcomeMessage**: The welcome message to send globally to a new user from the Welcome Bot. Adding this field will ignore the `TeamName`, `Message`, `AttachmentMessage` and `Actions` fields in the config to post a global message, irrespective of the team the user is part of. The preview of the configured messages, as well as the creation of a channel welcome message, can be done via bot commands: * `/welcomebot help` - Displays usage information. @@ -179,6 +180,12 @@ To accomplish the above, you can specify the following configuration in your `co "ChannelsAddedTo": ["escalation-process", "incidents"] } ] + }, + { + "DelayInSeconds": 5, + "GlobalWelcomeMessage": [ + "### Welcome {{.UserDisplayName}} to the Mattermost!", + ], } ] } diff --git a/server/configuration.go b/server/configuration.go index 2b8123323..ae5aef0af 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -25,6 +25,9 @@ type ConfigMessageAction struct { // ConfigMessage represents the message to send in channel type ConfigMessage struct { + // This message will send a global welcome message using the bot + GlobalWelcomeMessage []string + // This message will fire when it matches the supplied team TeamName string diff --git a/server/hooks.go b/server/hooks.go index 25b1b744e..1d199bd08 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -1,7 +1,10 @@ package main import ( + "bytes" "fmt" + "html/template" + "strings" "time" "github.com/mattermost/mattermost-server/v6/model" @@ -9,6 +12,41 @@ import ( "github.com/mattermost/mattermost-server/v6/shared/mlog" ) +// UserHasBeenCreated is invoked after a user was created. +func (p *Plugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { + data := p.constructGlobalMessageTemplate(user.Id) + if data == nil { + return + } + + for _, message := range p.getWelcomeMessages() { + if data.User.IsGuest() && !message.IncludeGuests { + continue + } + + if len(message.GlobalWelcomeMessage) > 0 { + tmpMsg, _ := template.New("Response").Parse(strings.Join(message.GlobalWelcomeMessage, "\n")) + var message bytes.Buffer + err := tmpMsg.Execute(&message, data) + if err != nil { + p.API.LogError("Failed to execute message template", "Error", err.Error()) + } + + post := &model.Post{ + Message: message.String(), + UserId: p.botUserID, + ChannelId: data.DirectMessage.Id, + } + + if _, err := p.API.CreatePost(post); err != nil { + p.API.LogError("We could not create the response post", "UserID", post.UserId, "Error", err.Error()) + } + + return + } + } +} + // UserHasJoinedTeam is invoked after the membership has been committed to the database. If // actor is not nil, the user was added to the team by the actor. func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMember, actor *model.User) { @@ -22,7 +60,7 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb continue } - if message.TeamName == data.Team.Name { + if message.TeamName == data.Team.Name && len(message.GlobalWelcomeMessage) == 0 { go p.processWelcomeMessage(*data, *message) } } diff --git a/server/message_template.go b/server/message_template.go index 717b36bc0..50cf40151 100644 --- a/server/message_template.go +++ b/server/message_template.go @@ -11,3 +11,11 @@ type MessageTemplate struct { DirectMessage *model.Channel UserDisplayName string } + +// GloablMessageTemplate represents all the data that can be used in the template for a welcomebot global message +type GloablMessageTemplate struct { + WelcomeBot *model.User + User *model.User + DirectMessage *model.Channel + UserDisplayName string +} diff --git a/server/welcomebot.go b/server/welcomebot.go index 7f65ad45f..c1a54c3f0 100644 --- a/server/welcomebot.go +++ b/server/welcomebot.go @@ -45,6 +45,29 @@ func (p *Plugin) constructMessageTemplate(userID, teamID string) *MessageTemplat return data } +func (p *Plugin) constructGlobalMessageTemplate(userID string) *GloablMessageTemplate { + data := &GloablMessageTemplate{} + var err *model.AppError + + if len(userID) > 0 { + if data.User, err = p.API.GetUser(userID); err != nil { + p.API.LogError("failed to query user", "user_id", userID) + return nil + } + } + + if data.User != nil { + if data.DirectMessage, err = p.API.GetDirectChannel(userID, p.botUserID); err != nil { + p.API.LogError("failed to query direct message channel", "user_id", userID) + return nil + } + } + + data.UserDisplayName = data.User.GetDisplayName(model.ShowNicknameFullName) + + return data +} + func (p *Plugin) getSiteURL() string { siteURL := "http://localhost:8065" From ca1edd601ac9c558657da0c0cc398e5081c0e220 Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Mon, 1 Jul 2024 14:58:07 +0530 Subject: [PATCH 2/3] [MM-387] Review fixes: Create constant and update name --- server/hooks.go | 4 ++-- server/plugin.go | 2 ++ server/welcomebot.go | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/server/hooks.go b/server/hooks.go index 1d199bd08..bd5812533 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -14,7 +14,7 @@ import ( // UserHasBeenCreated is invoked after a user was created. func (p *Plugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { - data := p.constructGlobalMessageTemplate(user.Id) + data := p.getGlobalMessageTemplateData(user.Id) if data == nil { return } @@ -25,7 +25,7 @@ func (p *Plugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { } if len(message.GlobalWelcomeMessage) > 0 { - tmpMsg, _ := template.New("Response").Parse(strings.Join(message.GlobalWelcomeMessage, "\n")) + tmpMsg, _ := template.New(templateNameResponse).Parse(strings.Join(message.GlobalWelcomeMessage, "\n")) var message bytes.Buffer err := tmpMsg.Execute(&message, data) if err != nil { diff --git a/server/plugin.go b/server/plugin.go index c13354ae7..c85c86236 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -14,6 +14,8 @@ const ( botDisplayName = "Welcomebot" botDescription = "A bot account created by the Welcomebot plugin." + templateNameResponse = "Response" + welcomebotChannelWelcomeKey = "chanmsg_" ) diff --git a/server/welcomebot.go b/server/welcomebot.go index c1a54c3f0..ae17b6fcd 100644 --- a/server/welcomebot.go +++ b/server/welcomebot.go @@ -45,7 +45,7 @@ func (p *Plugin) constructMessageTemplate(userID, teamID string) *MessageTemplat return data } -func (p *Plugin) constructGlobalMessageTemplate(userID string) *GloablMessageTemplate { +func (p *Plugin) getGlobalMessageTemplateData(userID string) *GloablMessageTemplate { data := &GloablMessageTemplate{} var err *model.AppError @@ -156,7 +156,7 @@ func (p *Plugin) renderWelcomeMessage(messageTemplate MessageTemplate, configMes } } - tmpMsg, _ := template.New("Response").Parse(strings.Join(configMessage.Message, "\n")) + tmpMsg, _ := template.New(templateNameResponse).Parse(strings.Join(configMessage.Message, "\n")) var message bytes.Buffer err := tmpMsg.Execute(&message, messageTemplate) if err != nil { @@ -225,7 +225,7 @@ func (p *Plugin) processActionMessage(messageTemplate MessageTemplate, action *A p.joinChannel(action, channelName) } - tmpMsg, _ := template.New("Response").Parse(strings.Join(configMessageAction.ActionSuccessfulMessage, "\n")) + tmpMsg, _ := template.New(templateNameResponse).Parse(strings.Join(configMessageAction.ActionSuccessfulMessage, "\n")) var message bytes.Buffer err := tmpMsg.Execute(&message, messageTemplate) if err != nil { From 8e31379b7f2fbde0e8a9074df5377b5143609fb6 Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Mon, 8 Jul 2024 16:43:20 +0530 Subject: [PATCH 3/3] [MM-387] Review fixes: Fix typo and methods --- server/hooks.go | 43 +++++++++++++++++++------------------- server/message_template.go | 4 ++-- server/welcomebot.go | 19 ++++++++--------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/server/hooks.go b/server/hooks.go index bd5812533..1dcf6a03a 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -14,8 +14,9 @@ import ( // UserHasBeenCreated is invoked after a user was created. func (p *Plugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { - data := p.getGlobalMessageTemplateData(user.Id) - if data == nil { + data, err := p.getGlobalMessageTemplateData(user.Id) + if err != nil { + p.API.LogError("Unable to get global message template data", "UserID", user.Id, "Error", err.Error()) return } @@ -24,25 +25,25 @@ func (p *Plugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { continue } - if len(message.GlobalWelcomeMessage) > 0 { - tmpMsg, _ := template.New(templateNameResponse).Parse(strings.Join(message.GlobalWelcomeMessage, "\n")) - var message bytes.Buffer - err := tmpMsg.Execute(&message, data) - if err != nil { - p.API.LogError("Failed to execute message template", "Error", err.Error()) - } - - post := &model.Post{ - Message: message.String(), - UserId: p.botUserID, - ChannelId: data.DirectMessage.Id, - } - - if _, err := p.API.CreatePost(post); err != nil { - p.API.LogError("We could not create the response post", "UserID", post.UserId, "Error", err.Error()) - } - - return + if len(message.GlobalWelcomeMessage) == 0 { + continue + } + + tmpMsg, _ := template.New(templateNameResponse).Parse(strings.Join(message.GlobalWelcomeMessage, "\n")) + var message bytes.Buffer + err := tmpMsg.Execute(&message, data) + if err != nil { + p.API.LogError("Failed to execute message template", "Error", err.Error()) + } + + post := &model.Post{ + Message: message.String(), + UserId: p.botUserID, + ChannelId: data.DirectMessage.Id, + } + + if _, err := p.API.CreatePost(post); err != nil { + p.API.LogError("We could not create the response post", "UserID", post.UserId, "Error", err.Error()) } } } diff --git a/server/message_template.go b/server/message_template.go index 50cf40151..b995b26e0 100644 --- a/server/message_template.go +++ b/server/message_template.go @@ -12,8 +12,8 @@ type MessageTemplate struct { UserDisplayName string } -// GloablMessageTemplate represents all the data that can be used in the template for a welcomebot global message -type GloablMessageTemplate struct { +// GlobalMessageTemplate represents all the data that can be used in the template for a welcomebot global message +type GlobalMessageTemplate struct { WelcomeBot *model.User User *model.User DirectMessage *model.Channel diff --git a/server/welcomebot.go b/server/welcomebot.go index ae17b6fcd..c02709fbc 100644 --- a/server/welcomebot.go +++ b/server/welcomebot.go @@ -8,6 +8,7 @@ import ( "time" "github.com/mattermost/mattermost-server/v6/model" + "github.com/pkg/errors" ) func (p *Plugin) constructMessageTemplate(userID, teamID string) *MessageTemplate { @@ -45,27 +46,25 @@ func (p *Plugin) constructMessageTemplate(userID, teamID string) *MessageTemplat return data } -func (p *Plugin) getGlobalMessageTemplateData(userID string) *GloablMessageTemplate { - data := &GloablMessageTemplate{} - var err *model.AppError +func (p *Plugin) getGlobalMessageTemplateData(userID string) (*GlobalMessageTemplate, error) { + data := &GlobalMessageTemplate{} + var appErr *model.AppError if len(userID) > 0 { - if data.User, err = p.API.GetUser(userID); err != nil { - p.API.LogError("failed to query user", "user_id", userID) - return nil + if data.User, appErr = p.API.GetUser(userID); appErr != nil { + return nil, errors.Wrap(appErr, "failed to query user") } } if data.User != nil { - if data.DirectMessage, err = p.API.GetDirectChannel(userID, p.botUserID); err != nil { - p.API.LogError("failed to query direct message channel", "user_id", userID) - return nil + if data.DirectMessage, appErr = p.API.GetDirectChannel(userID, p.botUserID); appErr != nil { + return nil, errors.Wrap(appErr, "failed to query direct message channel") } } data.UserDisplayName = data.User.GetDisplayName(model.ShowNicknameFullName) - return data + return data, nil } func (p *Plugin) getSiteURL() string {