From 5e6b1f83d1a9c6cdcb991b21592f7b62c11e00b8 Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Tue, 29 Jun 2021 13:21:45 -0700 Subject: [PATCH 01/17] adding new slash command options and updated README.md with their roles --- README.md | 13 ++ server/command.go | 367 +++++++++++++++++++++++++++++++++++++++++++--- server/hooks.go | 65 ++++++-- server/plugin.go | 1 + 4 files changed, 413 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 033f2d31a..766ff0eab 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,19 @@ type MessageTemplate struct { } ``` +## How to Dynamically Assign Team Messages + +This plugin also allows system admins and team admins to change the team message of an appropriate team through a slash command, rather than adjusting the config.json. + +We have provided three options that are formatted identically to the channel welcomes: +- `/welcomebot get_team_welcome` - prints the current team's welcome message if either the dynamic message exists, or the config.json message exists. +- `/welcomebot set_team_welcome [welcome message]` - sets the current team's welcome message to the one defined in the slash command. +- `/welcomebot delete_team_welcome` - deletes the current team's welcome message. This however does NOT delete any messages set inside of the config.json. + +For saving these messages, they are stored as KV pairs. Team message pairs have the prefix `teammsg_` to distinguish them from the `chanmsg_` pairs. + +The dynamic messages take priority in the case that a team has both a config.json message, and a dynamic one assigned. This is to leverage the ease of deleting KV pairs, compared to editing the config.json in real-time. + ## Development This plugin contains a server and webapp portion. diff --git a/server/command.go b/server/command.go index 15c270a7e..5182799b1 100644 --- a/server/command.go +++ b/server/command.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "net/http" "strings" "github.com/mattermost/mattermost-server/v5/plugin" @@ -14,6 +15,9 @@ const commandHelp = `* |/welcomebot preview [team-name] | - preview the welcome * |/welcomebot set_channel_welcome [welcome-message]| - set the welcome message for the given channel. Direct channels are not supported. * |/welcomebot get_channel_welcome| - print the welcome message set for the given channel (if any) * |/welcomebot delete_channel_welcome| - delete the welcome message for the given channel (if any) +* |/welcomebot set_team_welcome [welcome-message]| - set a brief text welcome message for your given team. +* |/welcomebot get_team_welcome| - print the welcome message set for the given team (if any) +* |/welcomebot delete_team_welcome| - delete the dynamic welcome message for the given team (if any) ` const ( @@ -23,6 +27,13 @@ const ( commandTriggerGetChannelWelcome = "get_channel_welcome" commandTriggerDeleteChannelWelcome = "delete_channel_welcome" commandTriggerHelp = "help" + commandTriggerSetTeamWelcome = "set_team_welcome" + commandTriggerGetTeamWelcome = "get_team_welcome" + commandTriggerDeleteTeamWelcome = "delete_team_welcome" + + // Error Message Constants + teamRetrievalErr = "error occurred while retrieving the welcome message for the team: `%s`" + unsetMessageError = "welcome message has not been set yet" ) func getCommand() *model.Command { @@ -31,7 +42,7 @@ func getCommand() *model.Command { DisplayName: "welcomebot", Description: "Welcome Bot helps add new team members to channels.", AutoComplete: true, - AutoCompleteDesc: "Available commands: preview, help, list, set_channel_welcome, get_channel_welcome, delete_channel_welcome", + AutoCompleteDesc: "Available commands: preview, help, list, set_channel_welcome, get_channel_welcome, delete_channel_welcome, set_team_welcome, get_team_welcome, delete_team_welcome", AutoCompleteHint: "[command]", AutocompleteData: getAutocompleteData(), } @@ -57,6 +68,39 @@ func (p *Plugin) hasSysadminRole(userID string) (bool, error) { return true, nil } +func (p *Plugin) hasTeamAdminRole(userID string, teamID string) (bool, error) { + teamMember, appErr := p.API.GetTeamMember(teamID, userID) + if appErr != nil { + return false, appErr + } + if !strings.Contains(teamMember.Roles, "team_admin") { + return false, nil + } + return true, nil +} + +func (p *Plugin) hasChannelAdminRole(userID string, channelID string) (bool, error) { + channelMember, appErr := p.API.GetChannelMember(channelID, userID) + if appErr != nil { + return false, appErr + } + if !strings.Contains(channelMember.Roles, "channel_admin") { + return false, nil + } + return true, nil +} + +func (p *Plugin) checkIfTownSquare(channelID string) (bool, error) { + channel, channelErr := p.API.GetChannel(channelID) + if channelErr != nil { + return false, channelErr + } + if channel.DisplayName != "Town Square" { + return false, nil + } + return true, nil +} + func (p *Plugin) validateCommand(action string, parameters []string) string { switch action { case commandTriggerPreview: @@ -79,40 +123,160 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { if len(parameters) > 0 { return "`delete_channel_welcome` command does not accept any extra parameters" } + case commandTriggerSetTeamWelcome: + if len(parameters) == 0 { + return "`" + commandTriggerSetTeamWelcome + "` command requires the message to be provided" + } + case commandTriggerGetTeamWelcome: + if len(parameters) > 0 { + return "`" + commandTriggerGetTeamWelcome + "` command does not accept any extra parameters" + } + case commandTriggerDeleteTeamWelcome: + if len(parameters) > 0 { + return "`" + commandTriggerDeleteTeamWelcome + "` command does not accept any extra parameters" + } } return "" } -func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) { - found := false - for _, message := range p.getWelcomeMessages() { - if message.TeamName == teamName { - if err := p.previewWelcomeMessage(teamName, args, *message); err != nil { - p.postCommandResponse(args, "error occurred while processing greeting for team `%s`: `%s`", teamName, err) - return - } +func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) bool { + _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId) + if teamMemberErr != nil { + if teamMemberErr.StatusCode == http.StatusNotFound { + p.postCommandResponse(args, "You are not a member of that team.") + return false + } + p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamMemberErr) + return false + } + doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, teamID) + + return doesUserHavePrivileges +} + +func (p *Plugin) checkForProperPrivileges(args *model.CommandArgs, userID string, teamID string) bool { + isSysadmin, sysAdminError := p.hasSysadminRole(userID) + isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) + + if sysAdminError != nil { + p.postCommandResponse(args, "error occurred while getting the System Admin Role `%s`: `%s`", teamID, sysAdminError) + return false + } + if teamAdminError != nil { + p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamAdminError) + return false + } + if !isSysadmin && !isTeamAdmin { + p.postCommandResponse(args, "You do not have the proper privileges to control this Team's welcome messages.") + return false + } + return true +} + +func (p *Plugin) showDynamicMessages(args *model.CommandArgs) bool { + // Checking dynamic welcome messages + teamsList, teamErr := p.API.GetTeams() + if teamErr != nil { + p.postCommandResponse(args, "Error occurred while getting list of teams: %s", teamErr) + return false + } - found = true + var dynamicTeamWelcome []string + + for _, team := range teamsList { + key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, team.Id) + teamMessage, appErr := p.API.KVGet(key) + if appErr != nil { + p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", appErr) + return false + } + if teamMessage != nil { + dynamicTeamWelcome = append(dynamicTeamWelcome, team.DisplayName) } } - if !found { - p.postCommandResponse(args, "team `%s` has not been found", teamName) + if len(dynamicTeamWelcome) == 0 { + return false } + + var str strings.Builder + str.WriteString("Teams for which welcome messages are defined:") + for _, team := range dynamicTeamWelcome { + str.WriteString(fmt.Sprintf("\n * %s", team)) + } + p.postCommandResponse(args, str.String()) + + return true +} + +func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) { + // Retrieve Team to check if a message already exists within the KV pair set + team, err := p.API.GetTeamByName(teamName) + if err != nil { + p.postCommandResponse(args, teamRetrievalErr, err) + return + } + teamID := team.Id + + validPrivileges := p.validatePreviewPrivileges(teamID, args) + if !validPrivileges { + return + } + + key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamID) + data, appErr := p.API.KVGet(key) + if appErr != nil { + p.postCommandResponse(args, teamRetrievalErr, appErr) + return + } + + if len(data) == 0 { + // no dynamic message is set so we check the config for a message + found := false + for _, message := range p.getWelcomeMessages() { + if message.TeamName == teamName { + if err := p.previewWelcomeMessage(teamName, args, *message); err != nil { + p.postCommandResponse(args, "error occurred while processing greeting for team `%s`: `%s`", teamName, err) + return + } + found = true + } + } + if !found { + p.postCommandResponse(args, "team `%s` has not been found", teamName) + } + return + } + // Create ephemeral team welcome message + p.postCommandResponse(args, string(data)) } func (p *Plugin) executeCommandList(args *model.CommandArgs) { - wecomeMessages := p.getWelcomeMessages() + isSysadmin, sysAdminError := p.hasSysadminRole(args.UserId) + if sysAdminError != nil { + p.postCommandResponse(args, "error occurred while getting the System Admin Role `%s`: `%s`", args.TeamId, sysAdminError) + return + } + if !isSysadmin { + p.postCommandResponse(args, "Only a System Admin can view all teams with welcome messages.") + return + } + + welcomeMessages := p.getWelcomeMessages() - if len(wecomeMessages) == 0 { + if len(welcomeMessages) == 0 { + success := p.showDynamicMessages(args) + if success { + return + } p.postCommandResponse(args, "There are no welcome messages defined") return } // Deduplicate entries teams := make(map[string]struct{}) - for _, message := range wecomeMessages { + for _, message := range welcomeMessages { teams[message.TeamName] = struct{}{} } @@ -121,6 +285,31 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) { for team := range teams { str.WriteString(fmt.Sprintf("\n * %s", team)) } + + // go through each key value pair and discern the teams with set values + page := 0 + keys, err := p.API.KVList(page, 200) + if err != nil { + p.postCommandResponse(args, "Issue grabbing messages for teams.") + return + } + for len(keys) != 0 { + // retrieve id inside of kv pair + for _, key := range keys { + id := strings.ReplaceAll(key, welcomebotTeamWelcomeKey, "") + team, getTeamErr := p.API.GetTeam(id) + if getTeamErr != nil { + continue // the key is not corresponding to a team + } + str.WriteString(fmt.Sprintf("\n * %s", team.Name)) + } + page++ + keys, err = p.API.KVList(page, 200) + if err != nil { + p.postCommandResponse(args, "Issue grabbing messages for teams.") + return + } + } p.postCommandResponse(args, str.String()) } @@ -131,7 +320,7 @@ func (p *Plugin) executeCommandSetWelcome(args *model.CommandArgs) { return } - if channelInfo.Type == model.CHANNEL_DIRECT { + if channelInfo.Type == model.CHANNEL_PRIVATE { p.postCommandResponse(args, "welcome messages are not supported for direct channels") return } @@ -188,6 +377,121 @@ func (p *Plugin) executeCommandDeleteWelcome(args *model.CommandArgs) { p.postCommandResponse(args, "welcome message has been deleted") } +func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { + doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, args.TeamId) + if !doesUserHavePrivileges { + return + } + + // Fields will consume ALL whitespace, so plain re-joining of the + // parameters slice will not produce the same message + message := strings.SplitN(args.Command, "set_team_welcome", 2)[1] + message = strings.TrimSpace(message) + + key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, args.TeamId) + if appErr := p.API.KVSet(key, []byte(message)); appErr != nil { + p.postCommandResponse(args, "error occurred while storing the welcome message for the team: `%s`", appErr) + return + } + + p.postCommandResponse(args, "stored the welcome message:\n%s", message) +} + +func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { + doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, args.TeamId) + if !doesUserHavePrivileges { + return + } + key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, args.TeamId) + data, appErr := p.API.KVGet(key) + + if appErr != nil { + p.postCommandResponse(args, teamRetrievalErr, appErr) + return + } + + if data == nil { + p.postCommandResponse(args, unsetMessageError) + return + } + + if appErr := p.API.KVDelete(key); appErr != nil { + p.postCommandResponse(args, "error occurred while deleting the welcome message for the team: `%s`", appErr) + return + } + + p.postCommandResponse(args, "welcome message has been deleted") +} + +func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { + doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, args.TeamId) + if !doesUserHavePrivileges { + return + } + + key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, args.TeamId) + data, appErr := p.API.KVGet(key) + if appErr != nil { + p.postCommandResponse(args, teamRetrievalErr, appErr) + return + } + + // retrieve team name through the teamid + team, err := p.API.GetTeam(args.TeamId) + if err != nil { + p.postCommandResponse(args, err.Error()) + return + } + + if data == nil { + for _, message := range p.getWelcomeMessages() { + if message.TeamName == team.Name { + if err := p.previewWelcomeMessage(team.Name, args, *message); err != nil { + p.postCommandResponse(args, "error occurred while processing greeting for team `%s`: `%s`", team.Name, err) + } + return + } + } + // if KV do not have message, and Config.json does not have message, then there is no message. Display Error case. + p.postCommandResponse(args, unsetMessageError) + return + } + p.postCommandResponse(args, string(data)) +} + +func (p *Plugin) verifyUser(args *model.CommandArgs) bool { + isSysadmin, err := p.hasSysadminRole(args.UserId) + if err != nil { + p.postCommandResponse(args, "authorization failed: %s", err) + return true + } + isTeamAdmin, teamAdminErr := p.hasTeamAdminRole(args.UserId, args.TeamId) + if teamAdminErr != nil { + p.postCommandResponse(args, "Team admin authorization failed: %s", teamAdminErr) + return true + } + isChannelAdmin, channelAdminErr := p.hasChannelAdminRole(args.UserId, args.ChannelId) + if channelAdminErr != nil { + p.postCommandResponse(args, "Channel admin authorization failed: %s", channelAdminErr) + return true + } + if !isSysadmin && !isTeamAdmin && !isChannelAdmin { + p.postCommandResponse(args, "/welcomebot commands can only be executed by the user with a system admin role, team admin role, or channel admin role") + return true + } + + isTownSquare, channelErr := p.checkIfTownSquare(args.ChannelId) + if channelErr != nil { + p.postCommandResponse(args, "Channel authorization failed: %s", channelAdminErr) + return true + } + if !isSysadmin && !isTeamAdmin && isChannelAdmin && isTownSquare { + p.postCommandResponse(args, "/welcomebot commands cannot be executed by a channel admin in Town Square") + return true + } + return false +} + func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { split := strings.Fields(args.Command) command := split[0] @@ -209,13 +513,8 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo return &model.CommandResponse{}, nil } - isSysadmin, err := p.hasSysadminRole(args.UserId) - if err != nil { - p.postCommandResponse(args, "authorization failed: %s", err) - return &model.CommandResponse{}, nil - } - if !isSysadmin { - p.postCommandResponse(args, "/welcomebot commands can only be executed by the user with system admin role") + errorOccurred := p.verifyUser(args) + if errorOccurred { return &model.CommandResponse{}, nil } @@ -236,6 +535,15 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo case commandTriggerDeleteChannelWelcome: p.executeCommandDeleteWelcome(args) return &model.CommandResponse{}, nil + case commandTriggerSetTeamWelcome: + p.executeCommandSetTeamWelcome(args) + return &model.CommandResponse{}, nil + case commandTriggerGetTeamWelcome: + p.executeCommandGetTeamWelcome(args) + return &model.CommandResponse{}, nil + case commandTriggerDeleteTeamWelcome: + p.executeCommandDeleteTeamWelcome(args) + return &model.CommandResponse{}, nil case commandTriggerHelp: fallthrough case "": @@ -250,7 +558,8 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo func getAutocompleteData() *model.AutocompleteData { welcomebot := model.NewAutocompleteData("welcomebot", "[command]", - "Available commands: preview, help, list, set_channel_welcome, get_channel_welcome, delete_channel_welcome") + "Available commands: preview, help, list, set_channel_welcome, get_channel_welcome, delete_channel_welcome, "+ + commandTriggerSetTeamWelcome+", "+commandTriggerGetTeamWelcome+", "+commandTriggerDeleteTeamWelcome) preview := model.NewAutocompleteData("preview", "[team-name]", "Preview the welcome message for the given team name") preview.AddTextArgument("Team name to preview welcome message", "[team-name]", "") @@ -269,5 +578,15 @@ func getAutocompleteData() *model.AutocompleteData { deleteChannelWelcome := model.NewAutocompleteData("delete_channel_welcome", "", "Delete the welcome message for the channel") welcomebot.AddCommand(deleteChannelWelcome) + setTeamWelcome := model.NewAutocompleteData(commandTriggerSetTeamWelcome, "[welcome-message]", "Set the welcome message for the team") + setChannelWelcome.AddTextArgument("Welcome message for the current team", "[welcome-message]", "") + welcomebot.AddCommand(setTeamWelcome) + + getTeamWelcome := model.NewAutocompleteData(commandTriggerGetTeamWelcome, "", "Print the welcome message for the team") + welcomebot.AddCommand(getTeamWelcome) + + deleteTeamWelcome := model.NewAutocompleteData(commandTriggerDeleteTeamWelcome, "", "Delete the welcome message for the team. Configuration based messages are not affected by this.") + welcomebot.AddCommand(deleteTeamWelcome) + return welcomebot } diff --git a/server/hooks.go b/server/hooks.go index 981d2d541..b7323fc6c 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -17,26 +17,65 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb return } - for _, message := range p.getWelcomeMessages() { - if message.TeamName == data.Team.Name { - go p.processWelcomeMessage(*data, *message) + key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamMember.TeamId) + teamMessage, appErr := p.API.KVGet(key) + if appErr != nil { + mlog.Error( + "error occurred while retrieving the welcome message", + mlog.String("teamId", teamMember.TeamId), + mlog.Err(appErr), + ) + return + } + + if teamMessage == nil { + // No dynamic welcome message for the given team, so we check if one as been set in the config.json + for _, message := range p.getWelcomeMessages() { + if message.TeamName == data.Team.Name { + go p.processWelcomeMessage(*data, *message) + } } + return + } + + // We send a DM and an opportunistic ephemeral message to the channel. See + // the discussion at the link below for more details: + // https://github.com/mattermost/mattermost-plugin-welcomebot/pull/31#issuecomment-611691023 + teamAddMessage := "# Welcome to the " + data.Team.DisplayName + " team!! \n\n" + postDM := &model.Post{ + UserId: p.botUserID, + ChannelId: data.DirectMessage.Id, + Message: teamAddMessage + string(teamMessage), + } + if _, appErr := p.API.CreatePost(postDM); appErr != nil { + mlog.Error("failed to post welcome message to the channel", + mlog.String("channelId", data.DirectMessage.Id), + mlog.Err(appErr), + ) } + + postChannel := &model.Post{ + UserId: p.botUserID, + ChannelId: teamMember.TeamId, + Message: string(teamMessage), + } + time.Sleep(1 * time.Second) + _ = p.API.SendEphemeralPost(teamMember.UserId, postChannel) } // UserHasJoinedChannel is invoked after the membership has been committed to // the database. If actor is not nil, the user was invited to the channel by // the actor. -func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.ChannelMember, _ *model.User) { - if channelInfo, appErr := p.API.GetChannel(channelMember.ChannelId); appErr != nil { +func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.ChannelMember, actor *model.User) { + channelInfo, appErr := p.API.GetChannel(channelMember.ChannelId) + if appErr != nil { + fmt.Print("CHANNEL NAME: " + channelInfo.Name) mlog.Error( "error occurred while checking the type of the chanel", mlog.String("channelId", channelMember.ChannelId), mlog.Err(appErr), ) return - } else if channelInfo.Type == model.CHANNEL_PRIVATE { - return } key := fmt.Sprintf("%s%s", welcomebotChannelWelcomeKey, channelMember.ChannelId) @@ -68,10 +107,12 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch // We send a DM and an opportunistic ephemeral message to the channel. See // the discussion at the link below for more details: // https://github.com/mattermost/mattermost-plugin-welcomebot/pull/31#issuecomment-611691023 + channelAddMessage := "# Welcome to the " + channelInfo.DisplayName + " channel. \n\n" + postDM := &model.Post{ UserId: p.botUserID, ChannelId: dmChannel.Id, - Message: string(data), + Message: channelAddMessage + string(data), } if _, appErr := p.API.CreatePost(postDM); appErr != nil { mlog.Error("failed to post welcome message to the channel", @@ -85,6 +126,12 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch ChannelId: channelMember.ChannelId, Message: string(data), } - time.Sleep(1 * time.Second) + + if actor.Id == channelMember.UserId { + time.Sleep(3 * time.Second) + } else { + time.Sleep(15 * time.Second) + } + _ = p.API.SendEphemeralPost(channelMember.UserId, postChannel) } diff --git a/server/plugin.go b/server/plugin.go index b48ba8760..81ca3c3d5 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -14,6 +14,7 @@ const ( botDescription = "A bot account created by the Welcomebot plugin." welcomebotChannelWelcomeKey = "chanmsg_" + welcomebotTeamWelcomeKey = "teammsg_" ) // Plugin represents the welcome bot plugin From 7c18f2e1c680eac6d8d8669828d8e4f60fd67a47 Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Tue, 29 Jun 2021 13:36:41 -0700 Subject: [PATCH 02/17] removing unecessary import --- server/command.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/command.go b/server/command.go index 5182799b1..56c41d49e 100644 --- a/server/command.go +++ b/server/command.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "net/http" "strings" "github.com/mattermost/mattermost-server/v5/plugin" @@ -143,7 +142,7 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) bool { _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId) if teamMemberErr != nil { - if teamMemberErr.StatusCode == http.StatusNotFound { + if teamMemberErr.StatusCode == 404 { p.postCommandResponse(args, "You are not a member of that team.") return false } From 8eb4b00d97f8b511a62174071c18fbd141eec828 Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Tue, 20 Jul 2021 15:53:22 -0600 Subject: [PATCH 03/17] Changes per PR with Mattermost people --- README.md | 2 - server/command.go | 167 +++++++++++++++++++++------------------- server/configuration.go | 16 ++++ server/hooks.go | 38 ++++----- 4 files changed, 117 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 766ff0eab..c14adf9ee 100644 --- a/README.md +++ b/README.md @@ -209,8 +209,6 @@ We have provided three options that are formatted identically to the channel wel For saving these messages, they are stored as KV pairs. Team message pairs have the prefix `teammsg_` to distinguish them from the `chanmsg_` pairs. -The dynamic messages take priority in the case that a team has both a config.json message, and a dynamic one assigned. This is to leverage the ease of deleting KV pairs, compared to editing the config.json in real-time. - ## Development This plugin contains a server and webapp portion. diff --git a/server/command.go b/server/command.go index 56c41d49e..fc767d99c 100644 --- a/server/command.go +++ b/server/command.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "reflect" "strings" "github.com/mattermost/mattermost-server/v5/plugin" @@ -31,7 +32,6 @@ const ( commandTriggerDeleteTeamWelcome = "delete_team_welcome" // Error Message Constants - teamRetrievalErr = "error occurred while retrieving the welcome message for the team: `%s`" unsetMessageError = "welcome message has not been set yet" ) @@ -61,7 +61,7 @@ func (p *Plugin) hasSysadminRole(userID string) (bool, error) { if appErr != nil { return false, appErr } - if !strings.Contains(user.Roles, "system_admin") { + if !strings.Contains(user.Roles, model.PERMISSIONS_SYSTEM_ADMIN) { return false, nil } return true, nil @@ -72,7 +72,7 @@ func (p *Plugin) hasTeamAdminRole(userID string, teamID string) (bool, error) { if appErr != nil { return false, appErr } - if !strings.Contains(teamMember.Roles, "team_admin") { + if !strings.Contains(teamMember.Roles, model.PERMISSIONS_TEAM_ADMIN) { return false, nil } return true, nil @@ -83,7 +83,7 @@ func (p *Plugin) hasChannelAdminRole(userID string, channelID string) (bool, err if appErr != nil { return false, appErr } - if !strings.Contains(channelMember.Roles, "channel_admin") { + if !strings.Contains(channelMember.Roles, model.PERMISSIONS_CHANNEL_ADMIN) { return false, nil } return true, nil @@ -94,7 +94,7 @@ func (p *Plugin) checkIfTownSquare(channelID string) (bool, error) { if channelErr != nil { return false, channelErr } - if channel.DisplayName != "Town Square" { + if channel.Name != model.DEFAULT_CHANNEL { return false, nil } return true, nil @@ -149,12 +149,13 @@ func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArg p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamMemberErr) return false } - doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, teamID) + doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, teamID) return doesUserHavePrivileges } -func (p *Plugin) checkForProperPrivileges(args *model.CommandArgs, userID string, teamID string) bool { +// checks if the user has System or Team Admin access to the given team +func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, teamID string) bool { isSysadmin, sysAdminError := p.hasSysadminRole(userID) isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) @@ -173,47 +174,35 @@ func (p *Plugin) checkForProperPrivileges(args *model.CommandArgs, userID string return true } -func (p *Plugin) showDynamicMessages(args *model.CommandArgs) bool { - // Checking dynamic welcome messages +// This retrives a map of team Ids with their respective welcome message +func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string]string { teamsList, teamErr := p.API.GetTeams() if teamErr != nil { p.postCommandResponse(args, "Error occurred while getting list of teams: %s", teamErr) - return false + return make(map[string]string) } - var dynamicTeamWelcome []string + teamsAndKVWelcomeMessagesMap := make(map[string]string) for _, team := range teamsList { key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, team.Id) teamMessage, appErr := p.API.KVGet(key) if appErr != nil { p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", appErr) - return false + return make(map[string]string) } if teamMessage != nil { - dynamicTeamWelcome = append(dynamicTeamWelcome, team.DisplayName) + teamsAndKVWelcomeMessagesMap[team.Id] = string(teamMessage) } } - - if len(dynamicTeamWelcome) == 0 { - return false - } - - var str strings.Builder - str.WriteString("Teams for which welcome messages are defined:") - for _, team := range dynamicTeamWelcome { - str.WriteString(fmt.Sprintf("\n * %s", team)) - } - p.postCommandResponse(args, str.String()) - - return true + return teamsAndKVWelcomeMessagesMap } func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) { // Retrieve Team to check if a message already exists within the KV pair set team, err := p.API.GetTeamByName(teamName) if err != nil { - p.postCommandResponse(args, teamRetrievalErr, err) + p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", err) return } teamID := team.Id @@ -226,7 +215,7 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamID) data, appErr := p.API.KVGet(key) if appErr != nil { - p.postCommandResponse(args, teamRetrievalErr, appErr) + p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", appErr) return } @@ -262,53 +251,24 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) { return } - welcomeMessages := p.getWelcomeMessages() - - if len(welcomeMessages) == 0 { - success := p.showDynamicMessages(args) - if success { - return - } + welcomeMessagesFromConfig := p.getWelcomeMessages() + welcomeMessagesFromKVsMap := p.getTeamKVWelcomeMessagesMap(args) + if len(welcomeMessagesFromConfig) == 0 && len(welcomeMessagesFromKVsMap) == 0 { p.postCommandResponse(args, "There are no welcome messages defined") return } // Deduplicate entries teams := make(map[string]struct{}) - for _, message := range welcomeMessages { + for _, message := range welcomeMessagesFromConfig { teams[message.TeamName] = struct{}{} } var str strings.Builder - str.WriteString("Teams for which welcome messages are defined:") - for team := range teams { + teamsWithWelcomeMessages := p.getUniqueTeamsWithWelcomeMsgSlice(teams, welcomeMessagesFromKVsMap) + for _, team := range teamsWithWelcomeMessages { str.WriteString(fmt.Sprintf("\n * %s", team)) } - - // go through each key value pair and discern the teams with set values - page := 0 - keys, err := p.API.KVList(page, 200) - if err != nil { - p.postCommandResponse(args, "Issue grabbing messages for teams.") - return - } - for len(keys) != 0 { - // retrieve id inside of kv pair - for _, key := range keys { - id := strings.ReplaceAll(key, welcomebotTeamWelcomeKey, "") - team, getTeamErr := p.API.GetTeam(id) - if getTeamErr != nil { - continue // the key is not corresponding to a team - } - str.WriteString(fmt.Sprintf("\n * %s", team.Name)) - } - page++ - keys, err = p.API.KVList(page, 200) - if err != nil { - p.postCommandResponse(args, "Issue grabbing messages for teams.") - return - } - } p.postCommandResponse(args, str.String()) } @@ -377,7 +337,7 @@ func (p *Plugin) executeCommandDeleteWelcome(args *model.CommandArgs) { } func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { - doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, args.TeamId) + doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, args.TeamId) if !doesUserHavePrivileges { return } @@ -387,7 +347,7 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { message := strings.SplitN(args.Command, "set_team_welcome", 2)[1] message = strings.TrimSpace(message) - key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, args.TeamId) + key := makeTeamWelcomeMessageKey(args.TeamId) if appErr := p.API.KVSet(key, []byte(message)); appErr != nil { p.postCommandResponse(args, "error occurred while storing the welcome message for the team: `%s`", appErr) return @@ -397,20 +357,16 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { } func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { - doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, args.TeamId) + doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, args.TeamId) if !doesUserHavePrivileges { return } - key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, args.TeamId) - data, appErr := p.API.KVGet(key) - if appErr != nil { - p.postCommandResponse(args, teamRetrievalErr, appErr) - return - } + key := makeTeamWelcomeMessageKey(args.TeamId) + _, appErr := p.GetTeamWelcomeMessageFromKV(args.TeamId) - if data == nil { - p.postCommandResponse(args, unsetMessageError) + if appErr != nil { + p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", appErr) return } @@ -423,15 +379,14 @@ func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { } func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { - doesUserHavePrivileges := p.checkForProperPrivileges(args, args.UserId, args.TeamId) + doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, args.TeamId) if !doesUserHavePrivileges { return } - key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, args.TeamId) - data, appErr := p.API.KVGet(key) + data, appErr := p.GetTeamWelcomeMessageFromKV(args.TeamId) if appErr != nil { - p.postCommandResponse(args, teamRetrievalErr, appErr) + p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", appErr) return } @@ -458,7 +413,7 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { p.postCommandResponse(args, string(data)) } -func (p *Plugin) verifyUser(args *model.CommandArgs) bool { +func (p *Plugin) checkCommandPermission(args *model.CommandArgs) bool { isSysadmin, err := p.hasSysadminRole(args.UserId) if err != nil { p.postCommandResponse(args, "authorization failed: %s", err) @@ -512,8 +467,8 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo return &model.CommandResponse{}, nil } - errorOccurred := p.verifyUser(args) - if errorOccurred { + err := p.checkCommandPermission(args) + if err { return &model.CommandResponse{}, nil } @@ -555,6 +510,56 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo return &model.CommandResponse{}, nil } +func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcome map[string]struct{}, teamsWithKVWelcome map[string]string) []string { + var uniqueTeams []string + var allTeamNames []string + // Place all keys into one list + teamsWithConfigWelcomeKeys := convertStringMapIntoKeySlice(teamsWithConfigWelcome) + teamIDsWithKVWelcomeKeys := convertStringMapIntoKeySlice(teamsWithKVWelcome) + + // Convert the ids into team names before combining into 1 large list + teamsWithKVWelcomeKeys := []string{} + for _, id := range teamIDsWithKVWelcomeKeys { + team, err := p.API.GetTeam(id) + if err != nil { + continue + } + teamsWithKVWelcomeKeys = append(teamsWithKVWelcomeKeys, team.Name) + } + allTeamNames = append(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys...) + + // Leverage the unique priniciple of keys in a map to store unique values as they are encountered + checkMap := make(map[string]int) + for _, teamName := range allTeamNames { + checkMap[teamName] = 0 + } + + // Iterate through each pair in the checkMap to create a list of all unique pairs. + for teamName := range checkMap { + uniqueTeams = append(uniqueTeams, teamName) + } + return uniqueTeams + +} + +// Takes maps whose keys are strings, and whose values are anything. +func convertStringMapIntoKeySlice(mapInput interface{}) []string { + // need to check that input is a map or a slice before continuing + reflectValue := reflect.ValueOf(mapInput) + switch reflectValue.Kind() { + case reflect.Map: + default: + return nil + } + // Grabs all keys and makes a list of the keys. + keys := make([]string, 0, len(reflectValue.MapKeys())) + for _, keyReflectValue := range reflectValue.MapKeys() { + key := keyReflectValue.Interface().(string) + keys = append(keys, key) + } + return keys +} + func getAutocompleteData() *model.AutocompleteData { welcomebot := model.NewAutocompleteData("welcomebot", "[command]", "Available commands: preview, help, list, set_channel_welcome, get_channel_welcome, delete_channel_welcome, "+ diff --git a/server/configuration.go b/server/configuration.go index edf93ca5f..c49f4b484 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -1,5 +1,11 @@ package main +import ( + "fmt" + + "github.com/mattermost/mattermost-server/v5/model" +) + const ( actionTypeAutomatic = "automatic" actionTypeButton = "button" @@ -64,3 +70,13 @@ func (p *Plugin) OnConfigurationChange() error { return nil } + +// Takes a teamID to construct the correct key, and then retrieve the necessary value from the pair stored in the DB +func (p *Plugin) GetTeamWelcomeMessageFromKV(teamID string) ([]byte, *model.AppError) { + key := makeTeamWelcomeMessageKey(teamID) + return p.API.KVGet(key) +} + +func makeTeamWelcomeMessageKey(teamID string) string { + return fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamID) +} diff --git a/server/hooks.go b/server/hooks.go index b7323fc6c..cbcc20a4b 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "time" "github.com/mattermost/mattermost-server/v5/mlog" "github.com/mattermost/mattermost-server/v5/model" @@ -17,8 +16,7 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb return } - key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamMember.TeamId) - teamMessage, appErr := p.API.KVGet(key) + teamMessage, appErr := p.GetTeamWelcomeMessageFromKV(teamMember.TeamId) if appErr != nil { mlog.Error( "error occurred while retrieving the welcome message", @@ -53,14 +51,6 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb mlog.Err(appErr), ) } - - postChannel := &model.Post{ - UserId: p.botUserID, - ChannelId: teamMember.TeamId, - Message: string(teamMessage), - } - time.Sleep(1 * time.Second) - _ = p.API.SendEphemeralPost(teamMember.UserId, postChannel) } // UserHasJoinedChannel is invoked after the membership has been committed to @@ -69,13 +59,14 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.ChannelMember, actor *model.User) { channelInfo, appErr := p.API.GetChannel(channelMember.ChannelId) if appErr != nil { - fmt.Print("CHANNEL NAME: " + channelInfo.Name) mlog.Error( "error occurred while checking the type of the chanel", mlog.String("channelId", channelMember.ChannelId), mlog.Err(appErr), ) return + } else if channelInfo.Type == model.CHANNEL_PRIVATE { + return } key := fmt.Sprintf("%s%s", welcomebotChannelWelcomeKey, channelMember.ChannelId) @@ -121,17 +112,18 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch ) } - postChannel := &model.Post{ - UserId: p.botUserID, - ChannelId: channelMember.ChannelId, - Message: string(data), - } + // Commented out in case we do not want the user immediately greeted with an ephemeral message + // postChannel := &model.Post{ + // UserId: p.botUserID, + // ChannelId: channelMember.ChannelId, + // Message: string(data), + // } - if actor.Id == channelMember.UserId { - time.Sleep(3 * time.Second) - } else { - time.Sleep(15 * time.Second) - } + // if actor.Id == channelMember.UserId { + // time.Sleep(3 * time.Second) + // } else { + // time.Sleep(15 * time.Second) + // } - _ = p.API.SendEphemeralPost(channelMember.UserId, postChannel) + // _ = p.API.SendEphemeralPost(channelMember.UserId, postChannel) } From 1f9dcd8686dffc3195b8d987df2fd2004efb7131 Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Tue, 20 Jul 2021 16:00:47 -0600 Subject: [PATCH 04/17] fixing linter issues --- server/command.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/command.go b/server/command.go index fc767d99c..3cfaae5cb 100644 --- a/server/command.go +++ b/server/command.go @@ -512,7 +512,6 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcome map[string]struct{}, teamsWithKVWelcome map[string]string) []string { var uniqueTeams []string - var allTeamNames []string // Place all keys into one list teamsWithConfigWelcomeKeys := convertStringMapIntoKeySlice(teamsWithConfigWelcome) teamIDsWithKVWelcomeKeys := convertStringMapIntoKeySlice(teamsWithKVWelcome) @@ -526,7 +525,7 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcome map[st } teamsWithKVWelcomeKeys = append(teamsWithKVWelcomeKeys, team.Name) } - allTeamNames = append(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys...) + allTeamNames := append(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys...) // Leverage the unique priniciple of keys in a map to store unique values as they are encountered checkMap := make(map[string]int) @@ -539,7 +538,6 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcome map[st uniqueTeams = append(uniqueTeams, teamName) } return uniqueTeams - } // Takes maps whose keys are strings, and whose values are anything. From c7899d86d21be174efe77da8cc846b15af54541d Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Mon, 9 Aug 2021 12:43:10 -0600 Subject: [PATCH 05/17] fixed grammar, and unecessary user messages to conform to Peer review --- server/command.go | 18 +++++++++--------- server/hooks.go | 5 ++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/server/command.go b/server/command.go index 3cfaae5cb..e185bb212 100644 --- a/server/command.go +++ b/server/command.go @@ -32,7 +32,7 @@ const ( commandTriggerDeleteTeamWelcome = "delete_team_welcome" // Error Message Constants - unsetMessageError = "welcome message has not been set yet" + unsetMessageError = "welcome message has not been set" ) func getCommand() *model.Command { @@ -112,15 +112,15 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { } case commandTriggerSetChannelWelcome: if len(parameters) == 0 { - return "`set_channel_welcome` command requires the message to be provided" + return "`" + commandTriggerSetChannelWelcome + "` command requires the message to be provided" } case commandTriggerGetChannelWelcome: if len(parameters) > 0 { - return "`get_channel_welcome` command does not accept any extra parameters" + return "`" + commandTriggerGetChannelWelcome + "` command does not accept any extra parameters" } case commandTriggerDeleteChannelWelcome: if len(parameters) > 0 { - return "`delete_channel_welcome` command does not accept any extra parameters" + return "`" + commandTriggerDeleteChannelWelcome + "` command does not accept any extra parameters" } case commandTriggerSetTeamWelcome: if len(parameters) == 0 { @@ -160,7 +160,7 @@ func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, tea isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) if sysAdminError != nil { - p.postCommandResponse(args, "error occurred while getting the System Admin Role `%s`: `%s`", teamID, sysAdminError) + p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", sysAdminError) return false } if teamAdminError != nil { @@ -174,7 +174,7 @@ func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, tea return true } -// This retrives a map of team Ids with their respective welcome message +// This retrieves a map of team Ids with their respective welcome message func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string]string { teamsList, teamErr := p.API.GetTeams() if teamErr != nil { @@ -295,7 +295,7 @@ func (p *Plugin) executeCommandSetWelcome(args *model.CommandArgs) { return } - p.postCommandResponse(args, "stored the welcome message:\n%s", message) + p.postCommandResponse(args, "stored the channel welcome message:\n%s", message) } func (p *Plugin) executeCommandGetWelcome(args *model.CommandArgs) { @@ -353,7 +353,7 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { return } - p.postCommandResponse(args, "stored the welcome message:\n%s", message) + p.postCommandResponse(args, "stored the team welcome message:\n%s", message) } func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { @@ -375,7 +375,7 @@ func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { return } - p.postCommandResponse(args, "welcome message has been deleted") + p.postCommandResponse(args, "team welcome message has been deleted") } func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { diff --git a/server/hooks.go b/server/hooks.go index cbcc20a4b..e7876203c 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -27,7 +27,7 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb } if teamMessage == nil { - // No dynamic welcome message for the given team, so we check if one as been set in the config.json + // No dynamic welcome message for the given team, so we check if one has been set in the config.json for _, message := range p.getWelcomeMessages() { if message.TeamName == data.Team.Name { go p.processWelcomeMessage(*data, *message) @@ -39,11 +39,10 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb // We send a DM and an opportunistic ephemeral message to the channel. See // the discussion at the link below for more details: // https://github.com/mattermost/mattermost-plugin-welcomebot/pull/31#issuecomment-611691023 - teamAddMessage := "# Welcome to the " + data.Team.DisplayName + " team!! \n\n" postDM := &model.Post{ UserId: p.botUserID, ChannelId: data.DirectMessage.Id, - Message: teamAddMessage + string(teamMessage), + Message: string(teamMessage), } if _, appErr := p.API.CreatePost(postDM); appErr != nil { mlog.Error("failed to post welcome message to the channel", From 1b04b6f01f14459468f959738ea4fbbf0c8c5dee Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Tue, 17 Aug 2021 09:59:23 -0600 Subject: [PATCH 06/17] changed signatures to be more idiomatic. Removed unecessary paragraph from README.md --- README.md | 4 ++-- server/command.go | 52 +++++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c14adf9ee..a7473b9dd 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ type MessageTemplate struct { } ``` -## How to Dynamically Assign Team Messages + ## Development diff --git a/server/command.go b/server/command.go index e185bb212..2bc504ab4 100644 --- a/server/command.go +++ b/server/command.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "reflect" "strings" @@ -139,19 +140,19 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { return "" } -func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) bool { +func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) (bool, error) { _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId) if teamMemberErr != nil { if teamMemberErr.StatusCode == 404 { p.postCommandResponse(args, "You are not a member of that team.") - return false + return false, teamMemberErr } p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamMemberErr) - return false + return false, teamMemberErr } doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, teamID) - return doesUserHavePrivileges + return doesUserHavePrivileges, nil } // checks if the user has System or Team Admin access to the given team @@ -207,7 +208,7 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) } teamID := team.Id - validPrivileges := p.validatePreviewPrivileges(teamID, args) + validPrivileges, _ := p.validatePreviewPrivileges(teamID, args) if !validPrivileges { return } @@ -413,37 +414,40 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { p.postCommandResponse(args, string(data)) } -func (p *Plugin) checkCommandPermission(args *model.CommandArgs) bool { +func (p *Plugin) checkCommandPermission(args *model.CommandArgs) (bool, error) { isSysadmin, err := p.hasSysadminRole(args.UserId) if err != nil { p.postCommandResponse(args, "authorization failed: %s", err) - return true + return true, err } isTeamAdmin, teamAdminErr := p.hasTeamAdminRole(args.UserId, args.TeamId) if teamAdminErr != nil { p.postCommandResponse(args, "Team admin authorization failed: %s", teamAdminErr) - return true + return true, teamAdminErr } isChannelAdmin, channelAdminErr := p.hasChannelAdminRole(args.UserId, args.ChannelId) if channelAdminErr != nil { p.postCommandResponse(args, "Channel admin authorization failed: %s", channelAdminErr) - return true + return true, channelAdminErr } if !isSysadmin && !isTeamAdmin && !isChannelAdmin { - p.postCommandResponse(args, "/welcomebot commands can only be executed by the user with a system admin role, team admin role, or channel admin role") - return true - } - - isTownSquare, channelErr := p.checkIfTownSquare(args.ChannelId) - if channelErr != nil { - p.postCommandResponse(args, "Channel authorization failed: %s", channelAdminErr) - return true - } - if !isSysadmin && !isTeamAdmin && isChannelAdmin && isTownSquare { - p.postCommandResponse(args, "/welcomebot commands cannot be executed by a channel admin in Town Square") - return true - } - return false + errMsg := "/welcomebot commands can only be executed by the user with a system admin role, team admin role, or channel admin role" + p.postCommandResponse(args, errMsg) + return true, errors.New(errMsg) + } + + // Commented Out In case for future iterations of welcome bot we want to restrict channel welcome messages for town square. + // isTownSquare, channelErr := p.checkIfTownSquare(args.ChannelId) + // if channelErr != nil { + // p.postCommandResponse(args, "Channel authorization failed: %s", channelAdminErr) + // return true, channelErr + // } + // if !isSysadmin && !isTeamAdmin && isChannelAdmin && isTownSquare { + // errMsg := "/welcomebot commands cannot be executed by a channel admin in Town Square" + // p.postCommandResponse(args, errMsg) + // return true, errors.New(errMsg) + // } + return false, nil } func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) { @@ -467,7 +471,7 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo return &model.CommandResponse{}, nil } - err := p.checkCommandPermission(args) + err, _ := p.checkCommandPermission(args) if err { return &model.CommandResponse{}, nil } From 04e2dcdebe4f1fffdd6e2fb82acff13083a30c2f Mon Sep 17 00:00:00 2001 From: "caleb.maftei" Date: Tue, 17 Aug 2021 10:13:05 -0600 Subject: [PATCH 07/17] fixing linter issues with an unused function --- server/command.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/server/command.go b/server/command.go index 2bc504ab4..505d54e48 100644 --- a/server/command.go +++ b/server/command.go @@ -90,16 +90,17 @@ func (p *Plugin) hasChannelAdminRole(userID string, channelID string) (bool, err return true, nil } -func (p *Plugin) checkIfTownSquare(channelID string) (bool, error) { - channel, channelErr := p.API.GetChannel(channelID) - if channelErr != nil { - return false, channelErr - } - if channel.Name != model.DEFAULT_CHANNEL { - return false, nil - } - return true, nil -} +// Commented out for simplicity of welcome bot. Once restriction is wanted, this can be uncommented. +// func (p *Plugin) checkIfTownSquare(channelID string) (bool, error) { +// channel, channelErr := p.API.GetChannel(channelID) +// if channelErr != nil { +// return false, channelErr +// } +// if channel.Name != model.DEFAULT_CHANNEL { +// return false, nil +// } +// return true, nil +// } func (p *Plugin) validateCommand(action string, parameters []string) string { switch action { From 8383b93be504124cbe0d2956ac1f8a23e5275e12 Mon Sep 17 00:00:00 2001 From: raghav aggarwal Date: Tue, 16 Apr 2024 15:50:35 +0530 Subject: [PATCH 08/17] MM-381: review fixes fro CalebMaftei --- README.md | 6 ++---- server/command.go | 8 ++++---- server/configuration.go | 2 +- server/hooks.go | 26 +++++++++----------------- 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 1eec167bb..c9f147661 100644 --- a/README.md +++ b/README.md @@ -203,17 +203,15 @@ type MessageTemplate struct { } ``` - - ## Development This plugin contains a server and webapp portion. diff --git a/server/command.go b/server/command.go index 47f82dde7..a763bfb14 100644 --- a/server/command.go +++ b/server/command.go @@ -61,7 +61,7 @@ func (p *Plugin) hasSysadminRole(userID string) (bool, error) { if appErr != nil { return false, appErr } - if !strings.Contains(user.Roles, model.PERMISSIONS_SYSTEM_ADMIN) { + if !strings.Contains(user.Roles, model.PermissionsSystemAdmin) { return false, nil } return true, nil @@ -72,7 +72,7 @@ func (p *Plugin) hasTeamAdminRole(userID string, teamID string) (bool, error) { if appErr != nil { return false, appErr } - if !strings.Contains(teamMember.Roles, model.PERMISSIONS_TEAM_ADMIN) { + if !strings.Contains(teamMember.Roles, model.PermissionsTeamAdmin) { return false, nil } return true, nil @@ -83,7 +83,7 @@ func (p *Plugin) hasChannelAdminRole(userID string, channelID string) (bool, err if appErr != nil { return false, appErr } - if !strings.Contains(channelMember.Roles, model.PERMISSIONS_CHANNEL_ADMIN) { + if !strings.Contains(channelMember.Roles, model.PermissionsChannelAdmin) { return false, nil } return true, nil @@ -280,7 +280,7 @@ func (p *Plugin) executeCommandSetWelcome(args *model.CommandArgs) { return } - if channelInfo.Type == model.CHANNEL_PRIVATE { + if channelInfo.Type == model.ChannelTypePrivate { p.postCommandResponse(args, "welcome messages are not supported for direct channels") return } diff --git a/server/configuration.go b/server/configuration.go index 0bacac868..12d5b6541 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/mattermost/mattermost-server/v5/model" + "github.com/mattermost/mattermost-server/v6/model" ) const ( diff --git a/server/hooks.go b/server/hooks.go index 1f9abcacb..d0a45296b 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" @@ -97,12 +98,10 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch // We send a DM and an opportunistic ephemeral message to the channel. See // the discussion at the link below for more details: // https://github.com/mattermost/mattermost-plugin-welcomebot/pull/31#issuecomment-611691023 - channelAddMessage := "# Welcome to the " + channelInfo.DisplayName + " channel. \n\n" - postDM := &model.Post{ UserId: p.botUserID, ChannelId: dmChannel.Id, - Message: channelAddMessage + string(data), + Message: string(data), } if _, appErr := p.API.CreatePost(postDM); appErr != nil { mlog.Error("failed to post welcome message to the channel", @@ -111,18 +110,11 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch ) } - // Commented out in case we do not want the user immediately greeted with an ephemeral message - // postChannel := &model.Post{ - // UserId: p.botUserID, - // ChannelId: channelMember.ChannelId, - // Message: string(data), - // } - - // if actor.Id == channelMember.UserId { - // time.Sleep(3 * time.Second) - // } else { - // time.Sleep(15 * time.Second) - // } - - // _ = p.API.SendEphemeralPost(channelMember.UserId, postChannel) + postChannel := &model.Post{ + UserId: p.botUserID, + ChannelId: channelMember.ChannelId, + Message: string(data), + } + time.Sleep(1 * time.Second) + _ = p.API.SendEphemeralPost(channelMember.UserId, postChannel) } From a648fbba1663675cdc051928908f64f325945e8a Mon Sep 17 00:00:00 2001 From: raghav aggarwal Date: Thu, 18 Apr 2024 20:06:24 +0530 Subject: [PATCH 09/17] MM-381: review fixes --- README.md | 2 +- server/command.go | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c9f147661..183a7954e 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ type MessageTemplate struct { This plugin also allows system admins and team admins to change the team message of an appropriate team through a slash command, rather than adjusting the config.json. We have provided three options that are formatted identically to the channel welcomes: -- `/welcomebot get_team_welcome` - prints the current team's welcome message if either the dynamic message exists, or the config.json message exists. +- `/welcomebot get_team_welcome` - prints the current team's welcome message if the dynamic message or the config.json message exists. - `/welcomebot set_team_welcome [welcome message]` - sets the current team's welcome message to the one defined in the slash command. - `/welcomebot delete_team_welcome` - deletes the current team's welcome message. This however does NOT delete any messages set inside of the config.json. diff --git a/server/command.go b/server/command.go index a763bfb14..961fe764c 100644 --- a/server/command.go +++ b/server/command.go @@ -3,11 +3,13 @@ package main import ( "errors" "fmt" + "net/http" "reflect" "strings" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" + "github.com/mattermost/mattermost-server/v6/shared/mlog" ) const commandHelp = `* |/welcomebot preview [team-name] | - preview the welcome message for the given team name. The current user's username will be used to render the template. @@ -15,7 +17,7 @@ const commandHelp = `* |/welcomebot preview [team-name] | - preview the welcome * |/welcomebot set_channel_welcome [welcome-message]| - set the welcome message for the given channel. Direct channels are not supported. * |/welcomebot get_channel_welcome| - print the welcome message set for the given channel (if any) * |/welcomebot delete_channel_welcome| - delete the welcome message for the given channel (if any) -* |/welcomebot set_team_welcome [welcome-message]| - set a brief text welcome message for your given team. +* |/welcomebot set_team_welcome [welcome-message]| - set a brief welcome message for your current team. * |/welcomebot get_team_welcome| - print the welcome message set for the given team (if any) * |/welcomebot delete_team_welcome| - delete the dynamic welcome message for the given team (if any) ` @@ -141,13 +143,20 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { } func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) (bool, error) { - _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId) - if teamMemberErr != nil { - if teamMemberErr.StatusCode == 404 { + if _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId); teamMemberErr != nil { + if teamMemberErr.StatusCode == http.StatusNotFound { p.postCommandResponse(args, "You are not a member of that team.") + mlog.Error("The user is not a member of the team", + mlog.String("userId", args.UserId), + mlog.String("teamId", teamID), + ) return false, teamMemberErr } p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamMemberErr) + mlog.Error("error occurred while getting the Team Admin Role", + mlog.String("teamId", teamID), + mlog.Err(teamMemberErr), + ) return false, teamMemberErr } doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, teamID) @@ -158,12 +167,11 @@ func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArg // checks if the user has System or Team Admin access to the given team func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, teamID string) bool { isSysadmin, sysAdminError := p.hasSysadminRole(userID) - isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) - if sysAdminError != nil { p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", sysAdminError) return false } + isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) if teamAdminError != nil { p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamAdminError) return false @@ -179,7 +187,7 @@ func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, tea func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string]string { teamsList, teamErr := p.API.GetTeams() if teamErr != nil { - p.postCommandResponse(args, "Error occurred while getting list of teams: %s", teamErr) + p.postCommandResponse(args, "Error occurred while getting list of the teams: %s", teamErr) return make(map[string]string) } @@ -208,7 +216,11 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) } teamID := team.Id - validPrivileges, _ := p.validatePreviewPrivileges(teamID, args) + validPrivileges, nerr := p.validatePreviewPrivileges(teamID, args) + if nerr != nil { + p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", nerr) + return + } if !validPrivileges { return } @@ -226,7 +238,7 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) for _, message := range p.getWelcomeMessages() { if message.TeamName == teamName { if err := p.previewWelcomeMessage(teamName, args, *message); err != nil { - p.postCommandResponse(args, "error occurred while processing greeting for team `%s`: `%s`", teamName, err) + p.postCommandResponse(args, "error occurred while processing the greeting for the team `%s`: `%s`", teamName, err) return } found = true @@ -248,13 +260,13 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) { return } if !isSysadmin { - p.postCommandResponse(args, "Only a System Admin can view all teams with welcome messages.") + p.postCommandResponse(args, "only a System Admin can view all welcome messages of teams.") return } welcomeMessagesFromConfig := p.getWelcomeMessages() - welcomeMessagesFromKVsMap := p.getTeamKVWelcomeMessagesMap(args) - if len(welcomeMessagesFromConfig) == 0 && len(welcomeMessagesFromKVsMap) == 0 { + welcomeMessagesFromKVSMap := p.getTeamKVWelcomeMessagesMap(args) + if len(welcomeMessagesFromConfig) == 0 && len(welcomeMessagesFromKVSMap) == 0 { p.postCommandResponse(args, "There are no welcome messages defined") return } @@ -266,7 +278,7 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) { } var str strings.Builder - teamsWithWelcomeMessages := p.getUniqueTeamsWithWelcomeMsgSlice(teams, welcomeMessagesFromKVsMap) + teamsWithWelcomeMessages := p.getUniqueTeamsWithWelcomeMsgSlice(teams, welcomeMessagesFromKVSMap) for _, team := range teamsWithWelcomeMessages { str.WriteString(fmt.Sprintf("\n * %s", team)) } @@ -579,9 +591,11 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(setChannelWelcome) getChannelWelcome := model.NewAutocompleteData("get_channel_welcome", "", "Print the welcome message set for the channel") + getChannelWelcome.AddTextArgument("Name of the channel to get welcome message", "[channel-name]", "") welcomebot.AddCommand(getChannelWelcome) deleteChannelWelcome := model.NewAutocompleteData("delete_channel_welcome", "", "Delete the welcome message for the channel") + deleteChannelWelcome.AddTextArgument("Name of the channel to delete welcome message", "[channel-name]", "") welcomebot.AddCommand(deleteChannelWelcome) setTeamWelcome := model.NewAutocompleteData(commandTriggerSetTeamWelcome, "[welcome-message]", "Set the welcome message for the team") @@ -589,9 +603,11 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(setTeamWelcome) getTeamWelcome := model.NewAutocompleteData(commandTriggerGetTeamWelcome, "", "Print the welcome message for the team") + getTeamWelcome.AddTextArgument("Name of the team to get welcome message", "[team-name]", "") welcomebot.AddCommand(getTeamWelcome) deleteTeamWelcome := model.NewAutocompleteData(commandTriggerDeleteTeamWelcome, "", "Delete the welcome message for the team. Configuration based messages are not affected by this.") + deleteTeamWelcome.AddTextArgument("Name of the team to delete welcome message", "[team-name]", "") welcomebot.AddCommand(deleteTeamWelcome) return welcomebot From 8045973321969276808c30e08961b47007577efc Mon Sep 17 00:00:00 2001 From: raghav aggarwal Date: Thu, 18 Apr 2024 20:38:59 +0530 Subject: [PATCH 10/17] MM-381: review fixes for grammar --- server/command.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/command.go b/server/command.go index 961fe764c..401da17a3 100644 --- a/server/command.go +++ b/server/command.go @@ -591,11 +591,11 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(setChannelWelcome) getChannelWelcome := model.NewAutocompleteData("get_channel_welcome", "", "Print the welcome message set for the channel") - getChannelWelcome.AddTextArgument("Name of the channel to get welcome message", "[channel-name]", "") + getChannelWelcome.AddTextArgument("Channel name to get welcome message", "[channel-name]", "") welcomebot.AddCommand(getChannelWelcome) deleteChannelWelcome := model.NewAutocompleteData("delete_channel_welcome", "", "Delete the welcome message for the channel") - deleteChannelWelcome.AddTextArgument("Name of the channel to delete welcome message", "[channel-name]", "") + deleteChannelWelcome.AddTextArgument("Channel name to delete welcome message", "[channel-name]", "") welcomebot.AddCommand(deleteChannelWelcome) setTeamWelcome := model.NewAutocompleteData(commandTriggerSetTeamWelcome, "[welcome-message]", "Set the welcome message for the team") @@ -603,11 +603,11 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(setTeamWelcome) getTeamWelcome := model.NewAutocompleteData(commandTriggerGetTeamWelcome, "", "Print the welcome message for the team") - getTeamWelcome.AddTextArgument("Name of the team to get welcome message", "[team-name]", "") + getTeamWelcome.AddTextArgument("Team name to get welcome message", "[team-name]", "") welcomebot.AddCommand(getTeamWelcome) deleteTeamWelcome := model.NewAutocompleteData(commandTriggerDeleteTeamWelcome, "", "Delete the welcome message for the team. Configuration based messages are not affected by this.") - deleteTeamWelcome.AddTextArgument("Name of the team to delete welcome message", "[team-name]", "") + deleteTeamWelcome.AddTextArgument("Team name to delete welcome message", "[team-name]", "") welcomebot.AddCommand(deleteTeamWelcome) return welcomebot From 983f8cadbb0a634e2a759b9f995059c57bac9843 Mon Sep 17 00:00:00 2001 From: raghav aggarwal Date: Fri, 19 Apr 2024 20:26:27 +0530 Subject: [PATCH 11/17] MM-381: review fixes --- server/command.go | 195 ++++++++++++++++++++++------------------------ 1 file changed, 92 insertions(+), 103 deletions(-) diff --git a/server/command.go b/server/command.go index 401da17a3..65800fca1 100644 --- a/server/command.go +++ b/server/command.go @@ -9,7 +9,6 @@ import ( "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/plugin" - "github.com/mattermost/mattermost-server/v6/shared/mlog" ) const commandHelp = `* |/welcomebot preview [team-name] | - preview the welcome message for the given team name. The current user's username will be used to render the template. @@ -35,6 +34,7 @@ const ( // Error Message Constants unsetMessageError = "welcome message has not been set" + pluginPermissionError = "/welcomebot commands can only be executed by the user with a system admin role, team admin role, or channel admin role" ) func getCommand() *model.Command { @@ -91,18 +91,6 @@ func (p *Plugin) hasChannelAdminRole(userID string, channelID string) (bool, err return true, nil } -// Commented out for simplicity of welcome bot. Once restriction is wanted, this can be uncommented. -// func (p *Plugin) checkIfTownSquare(channelID string) (bool, error) { -// channel, channelErr := p.API.GetChannel(channelID) -// if channelErr != nil { -// return false, channelErr -// } -// if channel.Name != model.DEFAULT_CHANNEL { -// return false, nil -// } -// return true, nil -// } - func (p *Plugin) validateCommand(action string, parameters []string) string { switch action { case commandTriggerPreview: @@ -146,17 +134,11 @@ func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArg if _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId); teamMemberErr != nil { if teamMemberErr.StatusCode == http.StatusNotFound { p.postCommandResponse(args, "You are not a member of that team.") - mlog.Error("The user is not a member of the team", - mlog.String("userId", args.UserId), - mlog.String("teamId", teamID), - ) + p.API.LogInfo("The user is not a member of the team. UserID: `%s` TeamID: `%s`", args.UserId, teamID) return false, teamMemberErr } - p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamMemberErr) - mlog.Error("error occurred while getting the Team Admin Role", - mlog.String("teamId", teamID), - mlog.Err(teamMemberErr), - ) + p.postCommandResponse(args, "error occurred while getting the Team Admin Role. Team: `%s` Error: `%s`", teamID, teamMemberErr.Error()) + p.API.LogError("error occurred while getting the Team Admin Role. TeamID: `%s` Error: `%s`", teamID ,teamMemberErr.Error()) return false, teamMemberErr } doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, teamID) @@ -168,18 +150,24 @@ func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArg func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, teamID string) bool { isSysadmin, sysAdminError := p.hasSysadminRole(userID) if sysAdminError != nil { - p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", sysAdminError) + p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", sysAdminError.Error()) + p.API.LogError("error occurred while getting the System Admin Role. Error: `%s`", sysAdminError.Error()) return false } + isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) if teamAdminError != nil { - p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamAdminError) + p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamAdminError.Error()) + p.API.LogError("error occurred while getting the Team Admin Role. TeamID: `%s` Error: `%s`", teamID, teamAdminError.Error()) return false } + if !isSysadmin && !isTeamAdmin { p.postCommandResponse(args, "You do not have the proper privileges to control this Team's welcome messages.") + p.API.LogInfo("User does not have the proper privileges to control the Team's welcome messages. UserID: `%s` TeamID: `%s`", userID, teamID) return false } + return true } @@ -187,7 +175,8 @@ func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, tea func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string]string { teamsList, teamErr := p.API.GetTeams() if teamErr != nil { - p.postCommandResponse(args, "Error occurred while getting list of the teams: %s", teamErr) + p.postCommandResponse(args, "Error occurred while getting list of the teams: %s", teamErr.Error()) + p.API.LogError("Error occurred while getting list of the teams. Error: `%s`", teamErr.Error()) return make(map[string]string) } @@ -198,6 +187,7 @@ func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string teamMessage, appErr := p.API.KVGet(key) if appErr != nil { p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", appErr) + p.API.LogError("Error occurred while retrieving the welcome messages from KV store. Error: `%s`", appErr.Error()) return make(map[string]string) } if teamMessage != nil { @@ -211,14 +201,16 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) // Retrieve Team to check if a message already exists within the KV pair set team, err := p.API.GetTeamByName(teamName) if err != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", err) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", err.Error()) + p.API.LogError("Error occurred while retrieving the the team data. TeamName: `%s` Error: `%s`", teamName, err.Error()) return } teamID := team.Id validPrivileges, nerr := p.validatePreviewPrivileges(teamID, args) if nerr != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", nerr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team.: `%s`", nerr.Error()) + p.API.LogError("Error occurred while retrieving validating preview privilege for the team. TeamID: `%s` Error: `%s`", teamID, nerr.Error()) return } if !validPrivileges { @@ -228,39 +220,40 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamID) data, appErr := p.API.KVGet(key) if appErr != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", appErr.Error()) + p.API.LogError("Error occured while retrieving team welcome message from KV store. TeamID: `%s` Error: `%s`", teamID, appErr.Error()) + return + } + + if len(data) != 0 { + // Create ephemeral team welcome message + p.postCommandResponse(args, string(data)) return } - if len(data) == 0 { - // no dynamic message is set so we check the config for a message - found := false - for _, message := range p.getWelcomeMessages() { - if message.TeamName == teamName { - if err := p.previewWelcomeMessage(teamName, args, *message); err != nil { - p.postCommandResponse(args, "error occurred while processing the greeting for the team `%s`: `%s`", teamName, err) - return - } - found = true + // no dynamic message is set so we check the config for a message + for _, message := range p.getWelcomeMessages() { + if message.TeamName == teamName { + if err := p.previewWelcomeMessage(teamName, args, *message); err != nil { + p.postCommandResponse(args, "Error occurred while processing the greeting for the team `%s`: `%s`", teamName, err.Error()) + return } + return } - if !found { - p.postCommandResponse(args, "team `%s` has not been found", teamName) - } - return } - // Create ephemeral team welcome message - p.postCommandResponse(args, string(data)) + p.postCommandResponse(args, "team `%s` has not been found", teamName) } func (p *Plugin) executeCommandList(args *model.CommandArgs) { isSysadmin, sysAdminError := p.hasSysadminRole(args.UserId) if sysAdminError != nil { - p.postCommandResponse(args, "error occurred while getting the System Admin Role `%s`: `%s`", args.TeamId, sysAdminError) + p.postCommandResponse(args, "Error occurred while getting the System Admin Role `%s`: `%s`", args.TeamId, sysAdminError.Error()) + p.API.LogError("Error occurred while getting the System Admin Role `%s`: `%s`", args.TeamId, sysAdminError.Error()) return } + if !isSysadmin { - p.postCommandResponse(args, "only a System Admin can view all welcome messages of teams.") + p.postCommandResponse(args, "Only a System Admin can view all welcome messages of teams.") return } @@ -288,12 +281,12 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) { func (p *Plugin) executeCommandSetWelcome(args *model.CommandArgs) { channelInfo, appErr := p.API.GetChannel(args.ChannelId) if appErr != nil { - p.postCommandResponse(args, "error occurred while checking the type of the chanelId `%s`: `%s`", args.ChannelId, appErr) + p.postCommandResponse(args, "Error occurred while checking the type of the chanelId `%s`: `%s`", args.ChannelId, appErr) return } if channelInfo.Type == model.ChannelTypePrivate { - p.postCommandResponse(args, "welcome messages are not supported for direct channels") + p.postCommandResponse(args, "Welcome messages are not supported for direct channels") return } @@ -304,23 +297,23 @@ func (p *Plugin) executeCommandSetWelcome(args *model.CommandArgs) { key := fmt.Sprintf("%s%s", welcomebotChannelWelcomeKey, args.ChannelId) if appErr := p.API.KVSet(key, []byte(message)); appErr != nil { - p.postCommandResponse(args, "error occurred while storing the welcome message for the chanel: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while storing the welcome message for the chanel: `%s`", appErr) return } - p.postCommandResponse(args, "stored the channel welcome message:\n%s", message) + p.postCommandResponse(args, "Stored the channel welcome message:\n%s", message) } func (p *Plugin) executeCommandGetWelcome(args *model.CommandArgs) { key := fmt.Sprintf("%s%s", welcomebotChannelWelcomeKey, args.ChannelId) data, appErr := p.API.KVGet(key) if appErr != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the chanel: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the chanel: `%s`", appErr) return } if data == nil { - p.postCommandResponse(args, "welcome message has not been set yet") + p.postCommandResponse(args, "Welcome message has not been set yet") return } @@ -332,21 +325,21 @@ func (p *Plugin) executeCommandDeleteWelcome(args *model.CommandArgs) { data, appErr := p.API.KVGet(key) if appErr != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the chanel: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the chanel: `%s`", appErr) return } if data == nil { - p.postCommandResponse(args, "welcome message has not been set yet") + p.postCommandResponse(args, "Welcome message has not been set yet") return } if appErr := p.API.KVDelete(key); appErr != nil { - p.postCommandResponse(args, "error occurred while deleting the welcome message for the chanel: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while deleting the welcome message for the chanel: `%s`", appErr) return } - p.postCommandResponse(args, "welcome message has been deleted") + p.postCommandResponse(args, "Welcome message has been deleted") } func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { @@ -357,16 +350,20 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { // Fields will consume ALL whitespace, so plain re-joining of the // parameters slice will not produce the same message - message := strings.SplitN(args.Command, "set_team_welcome", 2)[1] - message = strings.TrimSpace(message) + subCommands := strings.SplitN(args.Command, "set_team_welcome", 2) + if len(subCommands) != 2 { + p.postCommandResponse(args, "Error occurred while extracting the welcome message from the command") + return + } + message := strings.TrimSpace(subCommands[1]) key := makeTeamWelcomeMessageKey(args.TeamId) if appErr := p.API.KVSet(key, []byte(message)); appErr != nil { - p.postCommandResponse(args, "error occurred while storing the welcome message for the team: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while storing the welcome message for the team: `%s`", appErr) return } - p.postCommandResponse(args, "stored the team welcome message:\n%s", message) + p.postCommandResponse(args, "Stored the team welcome message:\n%s", message) } func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { @@ -377,18 +374,17 @@ func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { key := makeTeamWelcomeMessageKey(args.TeamId) _, appErr := p.GetTeamWelcomeMessageFromKV(args.TeamId) - if appErr != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", appErr) return } if appErr := p.API.KVDelete(key); appErr != nil { - p.postCommandResponse(args, "error occurred while deleting the welcome message for the team: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while deleting the welcome message for the team: `%s`", appErr) return } - p.postCommandResponse(args, "team welcome message has been deleted") + p.postCommandResponse(args, "Team welcome message has been deleted") } func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { @@ -399,7 +395,7 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { data, appErr := p.GetTeamWelcomeMessageFromKV(args.TeamId) if appErr != nil { - p.postCommandResponse(args, "error occurred while retrieving the welcome message for the team: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", appErr) return } @@ -410,55 +406,48 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { return } - if data == nil { - for _, message := range p.getWelcomeMessages() { - if message.TeamName == team.Name { - if err := p.previewWelcomeMessage(team.Name, args, *message); err != nil { - p.postCommandResponse(args, "error occurred while processing greeting for team `%s`: `%s`", team.Name, err) - } - return + if data != nil { + p.postCommandResponse(args, string(data)) + return + } + + for _, message := range p.getWelcomeMessages() { + if message.TeamName == team.Name { + if err := p.previewWelcomeMessage(team.Name, args, *message); err != nil { + p.postCommandResponse(args, "Error occurred while processing greeting for team `%s`: `%s`", team.Name, err.Error()) + p.API.LogError("Error occurred while processing greeting for team. TeamName: `%s` Error : `%s`", team.Name, err.Error()) } + return } - // if KV do not have message, and Config.json does not have message, then there is no message. Display Error case. - p.postCommandResponse(args, unsetMessageError) - return } - p.postCommandResponse(args, string(data)) + // if KV do not have message, and Config.json does not have message, then there is no message. Display Error case. + p.postCommandResponse(args, unsetMessageError) } func (p *Plugin) checkCommandPermission(args *model.CommandArgs) (bool, error) { isSysadmin, err := p.hasSysadminRole(args.UserId) if err != nil { - p.postCommandResponse(args, "authorization failed: %s", err) + p.postCommandResponse(args, "Authorization failed: %s", err.Error()) return true, err } + isTeamAdmin, teamAdminErr := p.hasTeamAdminRole(args.UserId, args.TeamId) if teamAdminErr != nil { p.postCommandResponse(args, "Team admin authorization failed: %s", teamAdminErr) return true, teamAdminErr } + isChannelAdmin, channelAdminErr := p.hasChannelAdminRole(args.UserId, args.ChannelId) if channelAdminErr != nil { p.postCommandResponse(args, "Channel admin authorization failed: %s", channelAdminErr) return true, channelAdminErr } + if !isSysadmin && !isTeamAdmin && !isChannelAdmin { - errMsg := "/welcomebot commands can only be executed by the user with a system admin role, team admin role, or channel admin role" - p.postCommandResponse(args, errMsg) - return true, errors.New(errMsg) - } - - // Commented Out In case for future iterations of welcome bot we want to restrict channel welcome messages for town square. - // isTownSquare, channelErr := p.checkIfTownSquare(args.ChannelId) - // if channelErr != nil { - // p.postCommandResponse(args, "Channel authorization failed: %s", channelAdminErr) - // return true, channelErr - // } - // if !isSysadmin && !isTeamAdmin && isChannelAdmin && isTownSquare { - // errMsg := "/welcomebot commands cannot be executed by a channel admin in Town Square" - // p.postCommandResponse(args, errMsg) - // return true, errors.New(errMsg) - // } + p.postCommandResponse(args, pluginPermissionError) + return true, errors.New(pluginPermissionError) + } + return false, nil } @@ -526,11 +515,11 @@ func (p *Plugin) ExecuteCommand(_ *plugin.Context, args *model.CommandArgs) (*mo return &model.CommandResponse{}, nil } -func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcome map[string]struct{}, teamsWithKVWelcome map[string]string) []string { +func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map[string]struct{}, teamsWithKVWelcomeMsg map[string]string) []string { var uniqueTeams []string // Place all keys into one list - teamsWithConfigWelcomeKeys := convertStringMapIntoKeySlice(teamsWithConfigWelcome) - teamIDsWithKVWelcomeKeys := convertStringMapIntoKeySlice(teamsWithKVWelcome) + teamsWithConfigWelcomeKeys := convertStringMapIntoKeySlice(teamsWithConfigWelcomeMsg) + teamIDsWithKVWelcomeKeys := convertStringMapIntoKeySlice(teamsWithKVWelcomeMsg) // Convert the ids into team names before combining into 1 large list teamsWithKVWelcomeKeys := []string{} @@ -544,13 +533,13 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcome map[st allTeamNames := append(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys...) // Leverage the unique priniciple of keys in a map to store unique values as they are encountered - checkMap := make(map[string]int) + teamNameMap := make(map[string]int) for _, teamName := range allTeamNames { - checkMap[teamName] = 0 + teamNameMap[teamName] = 0 } // Iterate through each pair in the checkMap to create a list of all unique pairs. - for teamName := range checkMap { + for teamName := range teamNameMap { uniqueTeams = append(uniqueTeams, teamName) } return uniqueTeams @@ -591,11 +580,11 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(setChannelWelcome) getChannelWelcome := model.NewAutocompleteData("get_channel_welcome", "", "Print the welcome message set for the channel") - getChannelWelcome.AddTextArgument("Channel name to get welcome message", "[channel-name]", "") + getChannelWelcome.AddTextArgument("Channel name to get the welcome message", "[channel-name]", "") welcomebot.AddCommand(getChannelWelcome) deleteChannelWelcome := model.NewAutocompleteData("delete_channel_welcome", "", "Delete the welcome message for the channel") - deleteChannelWelcome.AddTextArgument("Channel name to delete welcome message", "[channel-name]", "") + deleteChannelWelcome.AddTextArgument("Channel name to delete the welcome message", "[channel-name]", "") welcomebot.AddCommand(deleteChannelWelcome) setTeamWelcome := model.NewAutocompleteData(commandTriggerSetTeamWelcome, "[welcome-message]", "Set the welcome message for the team") @@ -603,11 +592,11 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(setTeamWelcome) getTeamWelcome := model.NewAutocompleteData(commandTriggerGetTeamWelcome, "", "Print the welcome message for the team") - getTeamWelcome.AddTextArgument("Team name to get welcome message", "[team-name]", "") + getTeamWelcome.AddTextArgument("Team name to get the welcome message", "[team-name]", "") welcomebot.AddCommand(getTeamWelcome) deleteTeamWelcome := model.NewAutocompleteData(commandTriggerDeleteTeamWelcome, "", "Delete the welcome message for the team. Configuration based messages are not affected by this.") - deleteTeamWelcome.AddTextArgument("Team name to delete welcome message", "[team-name]", "") + deleteTeamWelcome.AddTextArgument("Team name to delete the welcome message", "[team-name]", "") welcomebot.AddCommand(deleteTeamWelcome) return welcomebot From 6bdfa932281654045f4ebc4ad0a30dea47812831 Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Mon, 6 May 2024 14:00:11 +0530 Subject: [PATCH 12/17] Review fixes --- server/command.go | 106 +++++++++++++++++++++++----------------------- server/hooks.go | 16 +++---- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/server/command.go b/server/command.go index 65800fca1..e6f7ea773 100644 --- a/server/command.go +++ b/server/command.go @@ -33,7 +33,7 @@ const ( commandTriggerDeleteTeamWelcome = "delete_team_welcome" // Error Message Constants - unsetMessageError = "welcome message has not been set" + unsetMessageError = "welcome message has not been set" pluginPermissionError = "/welcomebot commands can only be executed by the user with a system admin role, team admin role, or channel admin role" ) @@ -70,9 +70,9 @@ func (p *Plugin) hasSysadminRole(userID string) (bool, error) { } func (p *Plugin) hasTeamAdminRole(userID string, teamID string) (bool, error) { - teamMember, appErr := p.API.GetTeamMember(teamID, userID) - if appErr != nil { - return false, appErr + teamMember, err := p.client.Team.GetMember(teamID, userID) + if err != nil { + return false, err } if !strings.Contains(teamMember.Roles, model.PermissionsTeamAdmin) { return false, nil @@ -81,9 +81,9 @@ func (p *Plugin) hasTeamAdminRole(userID string, teamID string) (bool, error) { } func (p *Plugin) hasChannelAdminRole(userID string, channelID string) (bool, error) { - channelMember, appErr := p.API.GetChannelMember(channelID, userID) - if appErr != nil { - return false, appErr + channelMember, err := p.client.Channel.GetMember(channelID, userID) + if err != nil { + return false, err } if !strings.Contains(channelMember.Roles, model.PermissionsChannelAdmin) { return false, nil @@ -131,15 +131,15 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { } func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) (bool, error) { - if _, teamMemberErr := p.API.GetTeamMember(teamID, args.UserId); teamMemberErr != nil { - if teamMemberErr.StatusCode == http.StatusNotFound { + if _, err := p.API.GetTeamMember(teamID, args.UserId); err != nil { + if err.StatusCode == http.StatusNotFound { p.postCommandResponse(args, "You are not a member of that team.") - p.API.LogInfo("The user is not a member of the team. UserID: `%s` TeamID: `%s`", args.UserId, teamID) - return false, teamMemberErr + p.client.Log.Info("The user is not a member of the team.", "UserID", args.UserId, "TeamID", teamID) + return false, err } - p.postCommandResponse(args, "error occurred while getting the Team Admin Role. Team: `%s` Error: `%s`", teamID, teamMemberErr.Error()) - p.API.LogError("error occurred while getting the Team Admin Role. TeamID: `%s` Error: `%s`", teamID ,teamMemberErr.Error()) - return false, teamMemberErr + p.postCommandResponse(args, "error occurred while getting the Team Admin Role. Team: `%s` Error: `%s`", teamID, err.Error()) + p.client.Log.Error("Error occurred while getting the Team Admin Role.", "TeamID", teamID, "Error", err.Error()) + return false, err } doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, teamID) @@ -148,23 +148,23 @@ func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArg // checks if the user has System or Team Admin access to the given team func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, teamID string) bool { - isSysadmin, sysAdminError := p.hasSysadminRole(userID) - if sysAdminError != nil { - p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", sysAdminError.Error()) - p.API.LogError("error occurred while getting the System Admin Role. Error: `%s`", sysAdminError.Error()) + isSysadmin, err := p.hasSysadminRole(userID) + if err != nil { + p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", err.Error()) + p.client.Log.Error("Error occurred while getting the System Admin Role.", "Error", err.Error()) return false } - isTeamAdmin, teamAdminError := p.hasTeamAdminRole(userID, teamID) - if teamAdminError != nil { - p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, teamAdminError.Error()) - p.API.LogError("error occurred while getting the Team Admin Role. TeamID: `%s` Error: `%s`", teamID, teamAdminError.Error()) + isTeamAdmin, err := p.hasTeamAdminRole(userID, teamID) + if err != nil { + p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, err.Error()) + p.client.Log.Error("Error occurred while getting the Team Admin Role.", "TeamID", teamID, "Error", err.Error()) return false } if !isSysadmin && !isTeamAdmin { p.postCommandResponse(args, "You do not have the proper privileges to control this Team's welcome messages.") - p.API.LogInfo("User does not have the proper privileges to control the Team's welcome messages. UserID: `%s` TeamID: `%s`", userID, teamID) + p.client.Log.Info("User does not have the proper privileges to control the Team's welcome messages.", "UserID", userID, "TeamID", teamID) return false } @@ -173,10 +173,10 @@ func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, tea // This retrieves a map of team Ids with their respective welcome message func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string]string { - teamsList, teamErr := p.API.GetTeams() - if teamErr != nil { - p.postCommandResponse(args, "Error occurred while getting list of the teams: %s", teamErr.Error()) - p.API.LogError("Error occurred while getting list of the teams. Error: `%s`", teamErr.Error()) + teamsList, err := p.client.Team.List() + if err != nil { + p.postCommandResponse(args, "Error occurred while getting list of the teams: %s", err.Error()) + p.client.Log.Error("Error occurred while getting list of the teams", "Error", err.Error()) return make(map[string]string) } @@ -184,14 +184,14 @@ func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string for _, team := range teamsList { key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, team.Id) - teamMessage, appErr := p.API.KVGet(key) - if appErr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", appErr) - p.API.LogError("Error occurred while retrieving the welcome messages from KV store. Error: `%s`", appErr.Error()) + var teamMessage string + if err := p.client.KV.Get(key, teamMessage); err != nil { + p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", err) + p.client.Log.Error("Error occurred while retrieving the welcome messages from KV store.", "Error", err.Error()) return make(map[string]string) } - if teamMessage != nil { - teamsAndKVWelcomeMessagesMap[team.Id] = string(teamMessage) + if teamMessage != "" { + teamsAndKVWelcomeMessagesMap[team.Id] = teamMessage } } return teamsAndKVWelcomeMessagesMap @@ -199,18 +199,18 @@ func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) { // Retrieve Team to check if a message already exists within the KV pair set - team, err := p.API.GetTeamByName(teamName) + team, err := p.client.Team.GetByName(teamName) if err != nil { p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", err.Error()) - p.API.LogError("Error occurred while retrieving the the team data. TeamName: `%s` Error: `%s`", teamName, err.Error()) + p.client.Log.Error("Error occurred while retrieving the the team data.", "TeamName", teamName, "Error", err.Error()) return } teamID := team.Id - validPrivileges, nerr := p.validatePreviewPrivileges(teamID, args) - if nerr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team.: `%s`", nerr.Error()) - p.API.LogError("Error occurred while retrieving validating preview privilege for the team. TeamID: `%s` Error: `%s`", teamID, nerr.Error()) + validPrivileges, err := p.validatePreviewPrivileges(teamID, args) + if err != nil { + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team.: `%s`", err.Error()) + p.client.Log.Error("Error occurred while retrieving validating preview privilege for the team.", "TeamID", teamID, "Error", err.Error()) return } if !validPrivileges { @@ -218,16 +218,16 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) } key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, teamID) - data, appErr := p.API.KVGet(key) - if appErr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", appErr.Error()) - p.API.LogError("Error occured while retrieving team welcome message from KV store. TeamID: `%s` Error: `%s`", teamID, appErr.Error()) + var data string + if err = p.client.KV.Get(key, data); err != nil { + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", err.Error()) + p.client.Log.Error("Error occured while retrieving team welcome message from KV store.", "TeamID", teamID, "Error", err.Error()) return } - if len(data) != 0 { + if data != "" { // Create ephemeral team welcome message - p.postCommandResponse(args, string(data)) + p.postCommandResponse(args, data) return } @@ -248,7 +248,7 @@ func (p *Plugin) executeCommandList(args *model.CommandArgs) { isSysadmin, sysAdminError := p.hasSysadminRole(args.UserId) if sysAdminError != nil { p.postCommandResponse(args, "Error occurred while getting the System Admin Role `%s`: `%s`", args.TeamId, sysAdminError.Error()) - p.API.LogError("Error occurred while getting the System Admin Role `%s`: `%s`", args.TeamId, sysAdminError.Error()) + p.client.Log.Error("Error occurred while getting the System Admin Role", "TeamID", args.TeamId, "Error", sysAdminError.Error()) return } @@ -350,7 +350,7 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { // Fields will consume ALL whitespace, so plain re-joining of the // parameters slice will not produce the same message - subCommands := strings.SplitN(args.Command, "set_team_welcome", 2) + subCommands := strings.SplitN(args.Command, commandTriggerSetTeamWelcome, 2) if len(subCommands) != 2 { p.postCommandResponse(args, "Error occurred while extracting the welcome message from the command") return @@ -358,7 +358,7 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { message := strings.TrimSpace(subCommands[1]) key := makeTeamWelcomeMessageKey(args.TeamId) - if appErr := p.API.KVSet(key, []byte(message)); appErr != nil { + if isValueSet, appErr := p.client.KV.Set(key, []byte(message), nil); !isValueSet { p.postCommandResponse(args, "Error occurred while storing the welcome message for the team: `%s`", appErr) return } @@ -379,8 +379,8 @@ func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { return } - if appErr := p.API.KVDelete(key); appErr != nil { - p.postCommandResponse(args, "Error occurred while deleting the welcome message for the team: `%s`", appErr) + if err := p.client.KV.Delete(key); err != nil { + p.postCommandResponse(args, "Error occurred while deleting the welcome message for the team: `%s`", err) return } @@ -400,7 +400,7 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { } // retrieve team name through the teamid - team, err := p.API.GetTeam(args.TeamId) + team, err := p.client.Team.Get(args.TeamId) if err != nil { p.postCommandResponse(args, err.Error()) return @@ -415,7 +415,7 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { if message.TeamName == team.Name { if err := p.previewWelcomeMessage(team.Name, args, *message); err != nil { p.postCommandResponse(args, "Error occurred while processing greeting for team `%s`: `%s`", team.Name, err.Error()) - p.API.LogError("Error occurred while processing greeting for team. TeamName: `%s` Error : `%s`", team.Name, err.Error()) + p.client.Log.Error("Error occurred while processing greeting for team.", "TeamName", team.Name, "Error", err.Error()) } return } @@ -524,7 +524,7 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map // Convert the ids into team names before combining into 1 large list teamsWithKVWelcomeKeys := []string{} for _, id := range teamIDsWithKVWelcomeKeys { - team, err := p.API.GetTeam(id) + team, err := p.client.Team.Get(id) if err != nil { continue } diff --git a/server/hooks.go b/server/hooks.go index d0a45296b..10b4ae542 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -45,10 +45,10 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb ChannelId: data.DirectMessage.Id, Message: string(teamMessage), } - if _, appErr := p.API.CreatePost(postDM); appErr != nil { + if err := p.client.Post.CreatePost(postDM); err != nil { mlog.Error("failed to post welcome message to the channel", mlog.String("channelId", data.DirectMessage.Id), - mlog.Err(appErr), + mlog.Err(err), ) } } @@ -57,12 +57,12 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb // the database. If actor is not nil, the user was invited to the channel by // the actor. func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.ChannelMember, actor *model.User) { - channelInfo, appErr := p.API.GetChannel(channelMember.ChannelId) - if appErr != nil { + channelInfo, err := p.client.Channel.Get(channelMember.ChannelId) + if err != nil { mlog.Error( "error occurred while checking the type of the chanel", mlog.String("channelId", channelMember.ChannelId), - mlog.Err(appErr), + mlog.Err(err), ) return } else if channelInfo.Type == model.ChannelTypePrivate { @@ -85,12 +85,12 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch return } - dmChannel, err := p.API.GetDirectChannel(channelMember.UserId, p.botUserID) - if err != nil { + dmChannel, appErr := p.API.GetDirectChannel(channelMember.UserId, p.botUserID) + if appErr != nil { mlog.Error( "error occurred while creating direct channel to the user", mlog.String("UserId", channelMember.UserId), - mlog.Err(err), + mlog.Err(appErr), ) return } From 71a69f8c2d7381de0e98009558cfd1dc5dc6ef2d Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Tue, 23 Jul 2024 20:00:55 +0530 Subject: [PATCH 13/17] Fix lint errors --- server/configuration.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/configuration.go b/server/configuration.go index 12d5b6541..1545029ac 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/mattermost/mattermost-server/v6/model" + "github.com/mattermost/mattermost/server/public/model" ) const ( From 38609874524efdf16306e5949424236502663748 Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Tue, 23 Jul 2024 20:17:04 +0530 Subject: [PATCH 14/17] Fix lint errors --- server/command.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/command.go b/server/command.go index 971fccd34..b3a342294 100644 --- a/server/command.go +++ b/server/command.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "reflect" + "slices" "strings" "github.com/mattermost/mattermost/server/public/model" @@ -35,7 +36,7 @@ const ( // Error Message Constants unsetMessageError = "welcome message has not been set" - pluginPermissionError = "The `/welcomebot %s` commands can only be executed by the user with a system admin role, team admin role, or channel admin role" + pluginPermissionError = "`/welcomebot %s` commands can only be executed by the user with a system admin role, team admin role, or channel admin role" ) func getCommand() *model.Command { @@ -222,7 +223,7 @@ func (p *Plugin) executeCommandPreview(teamName string, args *model.CommandArgs) var data string if err = p.client.KV.Get(key, data); err != nil { p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", err.Error()) - p.client.Log.Error("Error occured while retrieving team welcome message from KV store.", "TeamID", teamID, "Error", err.Error()) + p.client.Log.Error("Error occurred while retrieving team welcome message from KV store.", "TeamID", teamID, "Error", err.Error()) return } @@ -531,7 +532,7 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map } teamsWithKVWelcomeKeys = append(teamsWithKVWelcomeKeys, team.Name) } - allTeamNames := append(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys...) + allTeamNames := slices.Concat(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys) // Leverage the unique priniciple of keys in a map to store unique values as they are encountered teamNameMap := make(map[string]int) From e6fd92c42bb2d5d39c85731b9290cf4fdc1e0564 Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Tue, 23 Jul 2024 20:30:41 +0530 Subject: [PATCH 15/17] Fix lint errors --- server/command.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/command.go b/server/command.go index b3a342294..c8eb954bf 100644 --- a/server/command.go +++ b/server/command.go @@ -532,6 +532,7 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map } teamsWithKVWelcomeKeys = append(teamsWithKVWelcomeKeys, team.Name) } + allTeamNames := slices.Concat(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys) // Leverage the unique priniciple of keys in a map to store unique values as they are encountered From 87b4165719e39da3fa98d4fa2078a61e6ae0e6a9 Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Tue, 23 Jul 2024 20:43:46 +0530 Subject: [PATCH 16/17] FIx lint error --- server/command.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/command.go b/server/command.go index c8eb954bf..25140b4e2 100644 --- a/server/command.go +++ b/server/command.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "reflect" - "slices" "strings" "github.com/mattermost/mattermost/server/public/model" @@ -533,7 +532,8 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map teamsWithKVWelcomeKeys = append(teamsWithKVWelcomeKeys, team.Name) } - allTeamNames := slices.Concat(teamsWithConfigWelcomeKeys, teamsWithKVWelcomeKeys) + allTeamNames := teamsWithConfigWelcomeKeys + allTeamNames = append(allTeamNames, teamsWithKVWelcomeKeys...) // Leverage the unique priniciple of keys in a map to store unique values as they are encountered teamNameMap := make(map[string]int) From 7d22f27c520528432429de6d10fa82baa9e25b52 Mon Sep 17 00:00:00 2001 From: raghavaggarwal2308 Date: Tue, 6 Aug 2024 17:17:50 +0530 Subject: [PATCH 17/17] Review fixes --- server/command.go | 80 ++++++++++++++++++++--------------------- server/configuration.go | 11 +++--- server/hooks.go | 52 +++++++++------------------ 3 files changed, 61 insertions(+), 82 deletions(-) diff --git a/server/command.go b/server/command.go index 25140b4e2..66dd4e7ff 100644 --- a/server/command.go +++ b/server/command.go @@ -34,7 +34,7 @@ const ( commandTriggerDeleteTeamWelcome = "delete_team_welcome" // Error Message Constants - unsetMessageError = "welcome message has not been set" + unsetMessageError = "Welcome message has not been set for the team" pluginPermissionError = "`/welcomebot %s` commands can only be executed by the user with a system admin role, team admin role, or channel admin role" ) @@ -134,32 +134,31 @@ func (p *Plugin) validateCommand(action string, parameters []string) string { func (p *Plugin) validatePreviewPrivileges(teamID string, args *model.CommandArgs) (bool, error) { if _, err := p.API.GetTeamMember(teamID, args.UserId); err != nil { if err.StatusCode == http.StatusNotFound { - p.postCommandResponse(args, "You are not a member of that team.") + p.postCommandResponse(args, "You are not a member of the team.") p.client.Log.Info("The user is not a member of the team.", "UserID", args.UserId, "TeamID", teamID) return false, err } - p.postCommandResponse(args, "error occurred while getting the Team Admin Role. Team: `%s` Error: `%s`", teamID, err.Error()) - p.client.Log.Error("Error occurred while getting the Team Admin Role.", "TeamID", teamID, "Error", err.Error()) + p.postCommandResponse(args, "Error occurred while getting the Team member") + p.client.Log.Error("Error occurred while getting the Team member.", "TeamID", teamID, "Error", err.Error()) return false, err } - doesUserHavePrivileges := p.isSystemOrTeamAdmin(args, args.UserId, teamID) - return doesUserHavePrivileges, nil + return p.isSystemOrTeamAdmin(args, args.UserId, teamID), nil } // checks if the user has System or Team Admin access to the given team -func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, teamID string) bool { +func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID, teamID string) bool { isSysadmin, err := p.hasSysadminRole(userID) if err != nil { - p.postCommandResponse(args, "error occurred while getting the System Admin Role: `%s`", err.Error()) - p.client.Log.Error("Error occurred while getting the System Admin Role.", "Error", err.Error()) + p.postCommandResponse(args, "Error occurred while checking the System Admin Role.") + p.client.Log.Error("Error occurred while checking the System Admin Role.", "UserID", userID, "Error", err.Error()) return false } isTeamAdmin, err := p.hasTeamAdminRole(userID, teamID) if err != nil { - p.postCommandResponse(args, "error occurred while getting the Team Admin Role `%s`: `%s`", teamID, err.Error()) - p.client.Log.Error("Error occurred while getting the Team Admin Role.", "TeamID", teamID, "Error", err.Error()) + p.postCommandResponse(args, "Error occurred while checking the Team Admin Role for the user.") + p.client.Log.Error("Error occurred while checking the Team Admin Role for the user.", "UserID", userID, "TeamID", teamID, "Error", err.Error()) return false } @@ -172,7 +171,7 @@ func (p *Plugin) isSystemOrTeamAdmin(args *model.CommandArgs, userID string, tea return true } -// This retrieves a map of team Ids with their respective welcome message +// This retrieves a map of team IDs with their respective welcome message from the KV store func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string]string { teamsList, err := p.client.Team.List() if err != nil { @@ -187,7 +186,7 @@ func (p *Plugin) getTeamKVWelcomeMessagesMap(args *model.CommandArgs) map[string key := fmt.Sprintf("%s%s", welcomebotTeamWelcomeKey, team.Id) var teamMessage string if err := p.client.KV.Get(key, teamMessage); err != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", err) + p.postCommandResponse(args, "Error occurred while retrieving the welcome messages: %s", err.Error()) p.client.Log.Error("Error occurred while retrieving the welcome messages from KV store.", "Error", err.Error()) return make(map[string]string) } @@ -309,7 +308,7 @@ func (p *Plugin) executeCommandGetWelcome(args *model.CommandArgs) { key := fmt.Sprintf("%s%s", welcomebotChannelWelcomeKey, args.ChannelId) data, appErr := p.API.KVGet(key) if appErr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the chanel: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the chanel: `%s`", appErr.Message) return } @@ -326,7 +325,7 @@ func (p *Plugin) executeCommandDeleteWelcome(args *model.CommandArgs) { data, appErr := p.API.KVGet(key) if appErr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the chanel: `%s`", appErr) + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the chanel: `%s`", appErr.Message) return } @@ -356,11 +355,12 @@ func (p *Plugin) executeCommandSetTeamWelcome(args *model.CommandArgs) { p.postCommandResponse(args, "Error occurred while extracting the welcome message from the command") return } + message := strings.TrimSpace(subCommands[1]) key := makeTeamWelcomeMessageKey(args.TeamId) - if isValueSet, appErr := p.client.KV.Set(key, []byte(message), nil); !isValueSet { - p.postCommandResponse(args, "Error occurred while storing the welcome message for the team: `%s`", appErr) + if isValueSet, err := p.client.KV.Set(key, &message); err != nil || !isValueSet { + p.postCommandResponse(args, "Error occurred while storing the welcome message for the team: `%s`", err.Error()) return } @@ -373,15 +373,14 @@ func (p *Plugin) executeCommandDeleteTeamWelcome(args *model.CommandArgs) { return } - key := makeTeamWelcomeMessageKey(args.TeamId) - _, appErr := p.GetTeamWelcomeMessageFromKV(args.TeamId) - if appErr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", appErr) + if _, err := p.GetTeamWelcomeMessageFromKV(args.TeamId); err != nil { + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", err.Error()) return } + key := makeTeamWelcomeMessageKey(args.TeamId) if err := p.client.KV.Delete(key); err != nil { - p.postCommandResponse(args, "Error occurred while deleting the welcome message for the team: `%s`", err) + p.postCommandResponse(args, "Error occurred while deleting the welcome message for the team: `%s`", err.Error()) return } @@ -394,21 +393,21 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { return } - data, appErr := p.GetTeamWelcomeMessageFromKV(args.TeamId) - if appErr != nil { - p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", appErr) + data, err := p.GetTeamWelcomeMessageFromKV(args.TeamId) + if err != nil { + p.postCommandResponse(args, "Error occurred while retrieving the welcome message for the team: `%s`", err.Error()) return } // retrieve team name through the teamid team, err := p.client.Team.Get(args.TeamId) if err != nil { - p.postCommandResponse(args, err.Error()) + p.postCommandResponse(args, "Error occurred while retrieving the team: `%s`", err.Error()) return } - if data != nil { - p.postCommandResponse(args, string(data)) + if data != "" { + p.postCommandResponse(args, data) return } @@ -421,14 +420,15 @@ func (p *Plugin) executeCommandGetTeamWelcome(args *model.CommandArgs) { return } } - // if KV do not have message, and Config.json does not have message, then there is no message. Display Error case. + + // Show unset error message if no message is stored in KV and config.json file p.postCommandResponse(args, unsetMessageError) } func (p *Plugin) checkCommandPermission(args *model.CommandArgs, action string) (bool, error) { isSysadmin, err := p.hasSysadminRole(args.UserId) if err != nil { - p.postCommandResponse(args, "Authorization failed: %s", err.Error()) + p.postCommandResponse(args, "System admin authorization failed: %s", err.Error()) return true, err } @@ -536,15 +536,14 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map allTeamNames = append(allTeamNames, teamsWithKVWelcomeKeys...) // Leverage the unique priniciple of keys in a map to store unique values as they are encountered - teamNameMap := make(map[string]int) + teamNameMap := make(map[string]bool) for _, teamName := range allTeamNames { - teamNameMap[teamName] = 0 + if !teamNameMap[teamName] { + uniqueTeams = append(uniqueTeams, teamName) + } + teamNameMap[teamName] = true } - // Iterate through each pair in the checkMap to create a list of all unique pairs. - for teamName := range teamNameMap { - uniqueTeams = append(uniqueTeams, teamName) - } return uniqueTeams } @@ -552,11 +551,10 @@ func (p *Plugin) getUniqueTeamsWithWelcomeMsgSlice(teamsWithConfigWelcomeMsg map func convertStringMapIntoKeySlice(mapInput interface{}) []string { // need to check that input is a map or a slice before continuing reflectValue := reflect.ValueOf(mapInput) - switch reflectValue.Kind() { - case reflect.Map: - default: + if reflectValue.Kind() != reflect.Map { return nil } + // Grabs all keys and makes a list of the keys. keys := make([]string, 0, len(reflectValue.MapKeys())) for _, keyReflectValue := range reflectValue.MapKeys() { @@ -591,15 +589,13 @@ func getAutocompleteData() *model.AutocompleteData { welcomebot.AddCommand(deleteChannelWelcome) setTeamWelcome := model.NewAutocompleteData(commandTriggerSetTeamWelcome, "[welcome-message]", "Set the welcome message for the team") - setChannelWelcome.AddTextArgument("Welcome message for the current team", "[welcome-message]", "") + setTeamWelcome.AddTextArgument("Welcome message for the current team", "[welcome-message]", "") welcomebot.AddCommand(setTeamWelcome) getTeamWelcome := model.NewAutocompleteData(commandTriggerGetTeamWelcome, "", "Print the welcome message for the team") - getTeamWelcome.AddTextArgument("Team name to get the welcome message", "[team-name]", "") welcomebot.AddCommand(getTeamWelcome) deleteTeamWelcome := model.NewAutocompleteData(commandTriggerDeleteTeamWelcome, "", "Delete the welcome message for the team. Configuration based messages are not affected by this.") - deleteTeamWelcome.AddTextArgument("Team name to delete the welcome message", "[team-name]", "") welcomebot.AddCommand(deleteTeamWelcome) return welcomebot diff --git a/server/configuration.go b/server/configuration.go index 1545029ac..4b4c006b5 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -2,8 +2,6 @@ package main import ( "fmt" - - "github.com/mattermost/mattermost/server/public/model" ) const ( @@ -75,9 +73,14 @@ func (p *Plugin) OnConfigurationChange() error { } // Takes a teamID to construct the correct key, and then retrieve the necessary value from the pair stored in the DB -func (p *Plugin) GetTeamWelcomeMessageFromKV(teamID string) ([]byte, *model.AppError) { +func (p *Plugin) GetTeamWelcomeMessageFromKV(teamID string) (string, error) { key := makeTeamWelcomeMessageKey(teamID) - return p.API.KVGet(key) + var message string + if err := p.client.KV.Get(key, &message); err != nil { + return "", err + } + + return message, nil } func makeTeamWelcomeMessageKey(teamID string) string { diff --git a/server/hooks.go b/server/hooks.go index 1644fc399..71dc8d91d 100644 --- a/server/hooks.go +++ b/server/hooks.go @@ -6,7 +6,6 @@ import ( "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/plugin" - "github.com/mattermost/mattermost/server/public/shared/mlog" ) // UserHasJoinedTeam is invoked after the membership has been committed to the database. If @@ -17,19 +16,18 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb return } - teamMessage, appErr := p.GetTeamWelcomeMessageFromKV(teamMember.TeamId) - if appErr != nil { - mlog.Error( - "error occurred while retrieving the welcome message", - mlog.String("teamId", teamMember.TeamId), - mlog.Err(appErr), - ) + teamMessage, err := p.GetTeamWelcomeMessageFromKV(teamMember.TeamId) + if err != nil { + p.client.Log.Error("Error occurred while retrieving the welcome message", "TeamID", teamMember.TeamId, "Error", err.Error()) return } - if teamMessage == nil { + if teamMessage == "" { // No dynamic welcome message for the given team, so we check if one has been set in the config.json for _, message := range p.getWelcomeMessages() { + if data.User.IsGuest() && !message.IncludeGuests { + continue + } if message.TeamName == data.Team.Name { go p.processWelcomeMessage(*data, *message) } @@ -43,13 +41,10 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb postDM := &model.Post{ UserId: p.botUserID, ChannelId: data.DirectMessage.Id, - Message: string(teamMessage), + Message: teamMessage, } if err := p.client.Post.CreatePost(postDM); err != nil { - mlog.Error("failed to post welcome message to the channel", - mlog.String("channelId", data.DirectMessage.Id), - mlog.Err(err), - ) + p.client.Log.Error("failed to post welcome message to the channel", "ChannelID", data.DirectMessage.Id, "Error", err.Error()) } } @@ -59,11 +54,7 @@ func (p *Plugin) UserHasJoinedTeam(c *plugin.Context, teamMember *model.TeamMemb func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.ChannelMember, actor *model.User) { channelInfo, err := p.client.Channel.Get(channelMember.ChannelId) if err != nil { - mlog.Error( - "error occurred while checking the type of the chanel", - mlog.String("channelId", channelMember.ChannelId), - mlog.Err(err), - ) + p.client.Log.Error("Error occurred while checking the type of the chanel", "ChannelID", channelMember.ChannelId, "Error", err.Error()) return } else if channelInfo.Type == model.ChannelTypePrivate { return @@ -72,11 +63,7 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch key := fmt.Sprintf("%s%s", welcomebotChannelWelcomeKey, channelMember.ChannelId) data, appErr := p.API.KVGet(key) if appErr != nil { - mlog.Error( - "error occurred while retrieving the welcome message", - mlog.String("channelId", channelMember.ChannelId), - mlog.Err(appErr), - ) + p.client.Log.Error("Error occurred while retrieving the welcome message", "ChannelID", channelMember.ChannelId, "Error", appErr.Message) return } @@ -85,13 +72,9 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch return } - dmChannel, appErr := p.API.GetDirectChannel(channelMember.UserId, p.botUserID) - if appErr != nil { - mlog.Error( - "error occurred while creating direct channel to the user", - mlog.String("UserId", channelMember.UserId), - mlog.Err(appErr), - ) + dmChannel, err := p.client.Channel.GetDirect(channelMember.UserId, p.botUserID) + if err != nil { + p.client.Log.Error("Error occurred while creating direct channel to the user", "UserID", channelMember.UserId, "Error", err.Error()) return } @@ -103,11 +86,8 @@ func (p *Plugin) UserHasJoinedChannel(c *plugin.Context, channelMember *model.Ch ChannelId: dmChannel.Id, Message: string(data), } - if _, appErr := p.API.CreatePost(postDM); appErr != nil { - mlog.Error("failed to post welcome message to the channel", - mlog.String("channelId", dmChannel.Id), - mlog.Err(appErr), - ) + if err := p.client.Post.CreatePost(postDM); err != nil { + p.client.Log.Error("failed to post welcome message to the channel", "ChannelID", dmChannel.Id, "Error", err.Error()) } postChannel := &model.Post{