github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/plugin_commands.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "net/http" 8 "net/url" 9 "strings" 10 11 "github.com/mattermost/mattermost-server/v5/model" 12 "github.com/pkg/errors" 13 ) 14 15 type PluginCommand struct { 16 Command *model.Command 17 PluginId string 18 } 19 20 func (a *App) RegisterPluginCommand(pluginId string, command *model.Command) error { 21 if command.Trigger == "" { 22 return errors.New("invalid command") 23 } 24 if command.AutocompleteData != nil { 25 if err := command.AutocompleteData.IsValid(); err != nil { 26 return errors.Wrap(err, "invalid autocomplete data in command") 27 } 28 } 29 30 if command.AutocompleteData == nil { 31 command.AutocompleteData = model.NewAutocompleteData(command.Trigger, command.AutoCompleteHint, command.AutoCompleteDesc) 32 } else { 33 baseURL, err := url.Parse("/plugins/" + pluginId) 34 if err != nil { 35 return errors.Wrapf(err, "Can't parse url %s", "/plugins/"+pluginId) 36 } 37 err = command.AutocompleteData.UpdateRelativeURLsForPluginCommands(baseURL) 38 if err != nil { 39 return errors.Wrap(err, "Can't update relative urls for plugin commands") 40 } 41 } 42 43 command = &model.Command{ 44 Trigger: strings.ToLower(command.Trigger), 45 TeamId: command.TeamId, 46 AutoComplete: command.AutoComplete, 47 AutoCompleteDesc: command.AutoCompleteDesc, 48 AutoCompleteHint: command.AutoCompleteHint, 49 DisplayName: command.DisplayName, 50 AutocompleteData: command.AutocompleteData, 51 AutocompleteIconData: command.AutocompleteIconData, 52 } 53 54 a.Srv().pluginCommandsLock.Lock() 55 defer a.Srv().pluginCommandsLock.Unlock() 56 57 for _, pc := range a.Srv().pluginCommands { 58 if pc.Command.Trigger == command.Trigger && pc.Command.TeamId == command.TeamId { 59 if pc.PluginId == pluginId { 60 pc.Command = command 61 return nil 62 } 63 } 64 } 65 66 a.Srv().pluginCommands = append(a.Srv().pluginCommands, &PluginCommand{ 67 Command: command, 68 PluginId: pluginId, 69 }) 70 return nil 71 } 72 73 func (a *App) UnregisterPluginCommand(pluginId, teamId, trigger string) { 74 trigger = strings.ToLower(trigger) 75 76 a.Srv().pluginCommandsLock.Lock() 77 defer a.Srv().pluginCommandsLock.Unlock() 78 79 var remaining []*PluginCommand 80 for _, pc := range a.Srv().pluginCommands { 81 if pc.Command.TeamId != teamId || pc.Command.Trigger != trigger { 82 remaining = append(remaining, pc) 83 } 84 } 85 a.Srv().pluginCommands = remaining 86 } 87 88 func (a *App) UnregisterPluginCommands(pluginId string) { 89 a.Srv().pluginCommandsLock.Lock() 90 defer a.Srv().pluginCommandsLock.Unlock() 91 92 var remaining []*PluginCommand 93 for _, pc := range a.Srv().pluginCommands { 94 if pc.PluginId != pluginId { 95 remaining = append(remaining, pc) 96 } 97 } 98 a.Srv().pluginCommands = remaining 99 } 100 101 func (a *App) PluginCommandsForTeam(teamId string) []*model.Command { 102 a.Srv().pluginCommandsLock.RLock() 103 defer a.Srv().pluginCommandsLock.RUnlock() 104 105 var commands []*model.Command 106 for _, pc := range a.Srv().pluginCommands { 107 if pc.Command.TeamId == "" || pc.Command.TeamId == teamId { 108 commands = append(commands, pc.Command) 109 } 110 } 111 return commands 112 } 113 114 // tryExecutePluginCommand attempts to run a command provided by a plugin based on the given arguments. If no such 115 // command can be found, returns nil for all arguments. 116 func (a *App) tryExecutePluginCommand(args *model.CommandArgs) (*model.Command, *model.CommandResponse, *model.AppError) { 117 parts := strings.Split(args.Command, " ") 118 trigger := parts[0][1:] 119 trigger = strings.ToLower(trigger) 120 121 var matched *PluginCommand 122 a.Srv().pluginCommandsLock.RLock() 123 for _, pc := range a.Srv().pluginCommands { 124 if (pc.Command.TeamId == "" || pc.Command.TeamId == args.TeamId) && pc.Command.Trigger == trigger { 125 matched = pc 126 break 127 } 128 } 129 a.Srv().pluginCommandsLock.RUnlock() 130 if matched == nil { 131 return nil, nil, nil 132 } 133 134 pluginsEnvironment := a.GetPluginsEnvironment() 135 if pluginsEnvironment == nil { 136 return nil, nil, nil 137 } 138 139 pluginHooks, err := pluginsEnvironment.HooksForPlugin(matched.PluginId) 140 if err != nil { 141 return matched.Command, nil, model.NewAppError("ExecutePluginCommand", "model.plugin_command.error.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) 142 } 143 144 for username, userId := range a.mentionsToTeamMembers(args.Command, args.TeamId) { 145 args.AddUserMention(username, userId) 146 } 147 148 for channelName, channelId := range a.mentionsToPublicChannels(args.Command, args.TeamId) { 149 args.AddChannelMention(channelName, channelId) 150 } 151 152 response, appErr := pluginHooks.ExecuteCommand(a.PluginContext(), args) 153 return matched.Command, response, appErr 154 }