diff --git a/README.md b/README.md index 609841aaa..eb1adc3f0 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 a633b2353..f0f9ae395 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/public/model" @@ -9,6 +12,42 @@ import ( "github.com/mattermost/mattermost/server/public/shared/mlog" ) +// UserHasBeenCreated is invoked after a user was created. +func (p *Plugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { + 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 + } + + for _, message := range p.getWelcomeMessages() { + if data.User.IsGuest() && !message.IncludeGuests { + continue + } + + 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()) + } + } +} + // 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 +61,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 78c88158e..f3f6a9d99 100644 --- a/server/message_template.go +++ b/server/message_template.go @@ -11,3 +11,11 @@ type MessageTemplate struct { DirectMessage *model.Channel UserDisplayName string } + +// 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 + UserDisplayName string +} diff --git a/server/plugin.go b/server/plugin.go index b11646cab..255d62757 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 dbc550405..03d9d6e9d 100644 --- a/server/welcomebot.go +++ b/server/welcomebot.go @@ -8,6 +8,7 @@ import ( "time" "github.com/mattermost/mattermost/server/public/model" + "github.com/pkg/errors" ) func (p *Plugin) constructMessageTemplate(userID, teamID string) *MessageTemplate { @@ -45,6 +46,27 @@ func (p *Plugin) constructMessageTemplate(userID, teamID string) *MessageTemplat return data } +func (p *Plugin) getGlobalMessageTemplateData(userID string) (*GlobalMessageTemplate, error) { + data := &GlobalMessageTemplate{} + var appErr *model.AppError + + if len(userID) > 0 { + 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, 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, nil +} + func (p *Plugin) getSiteURL() string { siteURL := "http://localhost:8065" @@ -133,7 +155,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 { @@ -202,7 +224,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 {