[MM-20684] Slash Command Autocomplete (#14557)
* [MM-20684] Initial implementation of the Command Autocomplete (#13602) * Implement Autocomplete Data * Change CommandName to Trigger * Fix Autocomplete test * Make stylistic changes * Rename a bunch of fields and methods * Fix variable names, safer type assertions * [MM-20684] plugin autocomplete implementation (#14259) * Add an endpoint for command autocomplete suggestions * Add full Suggestion to the AutocompleteSugestion struct * Add Dynamic Argument support * Tidy up things * Fix missed test case * Add support of the named arguments * Update autocomplete API Fix review issues Implement dynamic args as a local request * Fix ineffassign * Add support of the uppercase letters in arguments * Add support of the optional arguments * Remove ineffectual assignment * Add support for icons (#14489) * Address couple of nits * Add comment to IconData * Add types to all consts Co-authored-by: mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
e8daab6b84
Коммит
43e606173b
@@ -23,6 +23,7 @@ func (api *API) InitCommand() {
|
||||
api.BaseRoutes.Command.Handle("", api.ApiSessionRequired(deleteCommand)).Methods("DELETE")
|
||||
|
||||
api.BaseRoutes.Team.Handle("/commands/autocomplete", api.ApiSessionRequired(listAutocompleteCommands)).Methods("GET")
|
||||
api.BaseRoutes.Team.Handle("/commands/autocomplete_suggestions", api.ApiSessionRequired(listCommandAutocompleteSuggestions)).Methods("GET")
|
||||
api.BaseRoutes.Command.Handle("/regen_token", api.ApiSessionRequired(regenCommandToken)).Methods("PUT")
|
||||
}
|
||||
|
||||
@@ -369,6 +370,39 @@ func listAutocompleteCommands(c *Context, w http.ResponseWriter, r *http.Request
|
||||
w.Write([]byte(model.CommandListToJson(commands)))
|
||||
}
|
||||
|
||||
func listCommandAutocompleteSuggestions(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequireTeamId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
if !c.App.SessionHasPermissionToTeam(*c.App.Session(), c.Params.TeamId, model.PERMISSION_VIEW_TEAM) {
|
||||
c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
|
||||
return
|
||||
}
|
||||
|
||||
roleId := model.SYSTEM_USER_ROLE_ID
|
||||
if c.IsSystemAdmin() {
|
||||
roleId = model.SYSTEM_ADMIN_ROLE_ID
|
||||
}
|
||||
|
||||
userInput := r.URL.Query().Get("user_input")
|
||||
if userInput == "" {
|
||||
c.SetInvalidParam("userInput")
|
||||
return
|
||||
}
|
||||
userInput = strings.TrimPrefix(userInput, "/")
|
||||
|
||||
commands, err := c.App.ListAutocompleteCommands(c.Params.TeamId, c.App.T)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
suggestions := c.App.GetSuggestions(commands, userInput, roleId)
|
||||
|
||||
w.Write(model.AutocompleteSuggestionsToJSON(suggestions))
|
||||
}
|
||||
|
||||
func regenCommandToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequireCommandId()
|
||||
if c.Err != nil {
|
||||
|
||||
@@ -407,6 +407,96 @@ func TestListAutocompleteCommands(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestListCommandAutocompleteSuggestions(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
Client := th.Client
|
||||
|
||||
newCmd := &model.Command{
|
||||
CreatorId: th.BasicUser.Id,
|
||||
TeamId: th.BasicTeam.Id,
|
||||
URL: "http://nowhere.com",
|
||||
Method: model.COMMAND_METHOD_POST,
|
||||
Trigger: "custom_command"}
|
||||
|
||||
_, resp := th.SystemAdminClient.CreateCommand(newCmd)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
t.Run("ListAutocompleteSuggestionsOnly", func(t *testing.T) {
|
||||
suggestions, resp := th.SystemAdminClient.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
foundEcho := false
|
||||
foundShrug := false
|
||||
foundCustom := false
|
||||
for _, command := range suggestions {
|
||||
if command.Suggestion == "echo" {
|
||||
foundEcho = true
|
||||
}
|
||||
if command.Suggestion == "shrug" {
|
||||
foundShrug = true
|
||||
}
|
||||
if command.Suggestion == "custom_command" {
|
||||
foundCustom = true
|
||||
}
|
||||
}
|
||||
require.True(t, foundEcho, "Couldn't find echo command")
|
||||
require.True(t, foundShrug, "Couldn't find shrug command")
|
||||
require.False(t, foundCustom, "Should not list the custom command")
|
||||
})
|
||||
|
||||
t.Run("ListAutocompleteSuggestionsOnlyWithInput", func(t *testing.T) {
|
||||
suggestions, resp := th.SystemAdminClient.ListCommandAutocompleteSuggestions("/e", th.BasicTeam.Id)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
foundEcho := false
|
||||
foundShrug := false
|
||||
for _, command := range suggestions {
|
||||
if command.Suggestion == "echo" {
|
||||
foundEcho = true
|
||||
}
|
||||
if command.Suggestion == "shrug" {
|
||||
foundShrug = true
|
||||
}
|
||||
}
|
||||
require.True(t, foundEcho, "Couldn't find echo command")
|
||||
require.False(t, foundShrug, "Should not list the shrug command")
|
||||
})
|
||||
|
||||
t.Run("RegularUserCanListOnlySystemCommands", func(t *testing.T) {
|
||||
suggestions, resp := Client.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
foundEcho := false
|
||||
foundCustom := false
|
||||
for _, suggestion := range suggestions {
|
||||
if suggestion.Suggestion == "echo" {
|
||||
foundEcho = true
|
||||
}
|
||||
if suggestion.Suggestion == "custom_command" {
|
||||
foundCustom = true
|
||||
}
|
||||
}
|
||||
require.True(t, foundEcho, "Couldn't find echo command")
|
||||
require.False(t, foundCustom, "Should not list the custom command")
|
||||
})
|
||||
|
||||
t.Run("NoMember", func(t *testing.T) {
|
||||
Client.Logout()
|
||||
user := th.CreateUser()
|
||||
th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
|
||||
Client.Login(user.Email, user.Password)
|
||||
_, resp := Client.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
|
||||
CheckForbiddenStatus(t, resp)
|
||||
})
|
||||
|
||||
t.Run("NotLoggedIn", func(t *testing.T) {
|
||||
Client.Logout()
|
||||
_, resp := Client.ListCommandAutocompleteSuggestions("/", th.BasicTeam.Id)
|
||||
CheckUnauthorizedStatus(t, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetCommand(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
Ссылка в новой задаче
Block a user