-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add boilerplate for api, commands, kvstore access and job management #212
Changes from 8 commits
3fd287d
7b20019
a8b8f35
3da5172
4e3f0ef
03035b7
51b7bdd
83b964e
639fbcc
d1fad46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -402,3 +402,9 @@ logs-watch: | |
# Help documentation à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html | ||
help: | ||
@cat Makefile build/*.mk | grep -v '\.PHONY' | grep -v '\help:' | grep -B1 -E '^[a-zA-Z0-9_.-]+:.*' | sed -e "s/:.*//" | sed -e "s/^## //" | grep -v '\-\-' | sed '1!G;h;$$!d' | awk 'NR%2{printf "\033[36m%-30s\033[0m",$$0;next;}1' | sort | ||
|
||
mock: | ||
ifneq ($(HAS_SERVER),) | ||
go install github.com/golang/mock/[email protected] | ||
mockgen -destination=server/command/mocks/mock_commands.go -package=mocks github.com/mattermost/mattermost-plugin-starter-template/server/command Command | ||
endif |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/gorilla/mux" | ||
"github.com/mattermost/mattermost/server/public/plugin" | ||
) | ||
|
||
// ServeHTTP demonstrates a plugin that handles HTTP requests by greeting the world. | ||
BenCookie95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) { | ||
router := mux.NewRouter() | ||
|
||
// Middleware to require that the user is logged in | ||
router.Use(p.MattermostAuthorizationRequired) | ||
|
||
apiRouter := router.PathPrefix("/api/v1").Subrouter() | ||
|
||
apiRouter.HandleFunc("/hello", p.HelloWorld).Methods(http.MethodGet) | ||
|
||
router.ServeHTTP(w, r) | ||
} | ||
|
||
func (p *Plugin) MattermostAuthorizationRequired(next http.Handler) http.Handler { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be awesome to hoist this into the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that makes sense |
||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
userID := r.Header.Get("Mattermost-User-ID") | ||
if userID == "" { | ||
http.Error(w, "Not authorized", http.StatusUnauthorized) | ||
return | ||
} | ||
|
||
next.ServeHTTP(w, r) | ||
}) | ||
} | ||
|
||
func (p *Plugin) HelloWorld(w http.ResponseWriter, r *http.Request) { | ||
if _, err := w.Write([]byte("Hello, world!")); err != nil { | ||
p.API.LogError("Failed to write response", "error", err) | ||
http.Error(w, err.Error(), http.StatusInternalServerError) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package command | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/mattermost/mattermost/server/public/model" | ||
"github.com/mattermost/mattermost/server/public/pluginapi" | ||
) | ||
|
||
type Handler struct { | ||
client *pluginapi.Client | ||
} | ||
|
||
type Command interface { | ||
Handle(args *model.CommandArgs) (*model.CommandResponse, error) | ||
executeHelloCommand(args *model.CommandArgs) *model.CommandResponse | ||
} | ||
|
||
const helloCommandTrigger = "hello" | ||
|
||
// Register all your slash commands in the NewCommandHandler function. | ||
func NewCommandHandler(client *pluginapi.Client) Command { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One day, it would be awesome to hoist this into the In that future, I wonder if we would need a discrete package at all and could just do this all in |
||
err := client.SlashCommand.Register(&model.Command{ | ||
Trigger: helloCommandTrigger, | ||
AutoComplete: true, | ||
AutoCompleteDesc: "Say hello to someone", | ||
AutoCompleteHint: "<username>", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should illustrate the advanced autocomplete functionality? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is that advanced functionality? I'm not aware, is there something I can read? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Take a peek at https://github.com/mattermost/mattermost-plugin-playbooks/blob/6c50600fb6151ea1abfed82961e980131b0ca2ab/server/command/command.go#L61 (ironically in an unnecessary |
||
}) | ||
if err != nil { | ||
client.Log.Error("Failed to register command", "error", err) | ||
} | ||
return &Handler{ | ||
client: client, | ||
} | ||
} | ||
|
||
// ExecuteCommand hook calls this method to execute the commands that were registered in the NewCommandHandler function. | ||
func (c *Handler) Handle(args *model.CommandArgs) (*model.CommandResponse, error) { | ||
trigger := strings.TrimPrefix(strings.Fields(args.Command)[0], "/") | ||
switch trigger { | ||
case helloCommandTrigger: | ||
return c.executeHelloCommand(args), nil | ||
default: | ||
return &model.CommandResponse{ | ||
ResponseType: model.CommandResponseTypeEphemeral, | ||
Text: fmt.Sprintf("Unknown command: %s", args.Command), | ||
}, nil | ||
} | ||
} | ||
|
||
func (c *Handler) executeHelloCommand(args *model.CommandArgs) *model.CommandResponse { | ||
if len(strings.Fields(args.Command)) < 2 { | ||
return &model.CommandResponse{ | ||
ResponseType: model.CommandResponseTypeEphemeral, | ||
Text: "Please specify a username", | ||
} | ||
} | ||
username := strings.Fields(args.Command)[1] | ||
return &model.CommandResponse{ | ||
Text: "Hello, " + username, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package command | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/mattermost/mattermost/server/public/model" | ||
"github.com/mattermost/mattermost/server/public/plugin/plugintest" | ||
"github.com/mattermost/mattermost/server/public/pluginapi" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
type env struct { | ||
client *pluginapi.Client | ||
api *plugintest.API | ||
} | ||
|
||
func setupTest() *env { | ||
api := &plugintest.API{} | ||
driver := &plugintest.Driver{} | ||
client := pluginapi.NewClient(api, driver) | ||
|
||
return &env{ | ||
client: client, | ||
api: api, | ||
} | ||
} | ||
|
||
func TestHelloCommand(t *testing.T) { | ||
assert := assert.New(t) | ||
env := setupTest() | ||
|
||
env.api.On("RegisterCommand", &model.Command{ | ||
Trigger: helloCommandTrigger, | ||
AutoComplete: true, | ||
AutoCompleteDesc: "Say hello to someone", | ||
AutoCompleteHint: "<username>", | ||
}).Return(nil) | ||
cmdHandler := NewCommandHandler(env.client) | ||
|
||
args := &model.CommandArgs{ | ||
Command: "/hello world", | ||
} | ||
response, err := cmdHandler.Handle(args) | ||
assert.Nil(err) | ||
assert.Equal("Hello, world", response.Text) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package main | ||
|
||
func (p *Plugin) runJob() { | ||
// Include job logic here | ||
BenCookie95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a package anymore.