mattermost-meme/plugin.go

189 lines
4.6 KiB
Go

package main
import (
"flag"
"fmt"
"image/jpeg"
"net/http"
"net/url"
"os"
"strings"
"github.com/gorilla/mux"
shellquote "github.com/kballard/go-shellquote"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-plugin-memes/meme"
"github.com/mattermost/mattermost-plugin-memes/memelibrary"
)
func resolveMeme(input string) (*meme.Template, []string, error) {
if template, text := memelibrary.PatternMatch(input); template != nil {
return template, text, nil
}
parts, err := shellquote.Split(input)
if err != nil {
return nil, nil, err
}
if template := memelibrary.Template(parts[0]); template != nil {
return template, parts[1:], nil
}
return nil, nil, fmt.Errorf("i don't know this meme")
}
func demo(args []string) error {
fs := flag.NewFlagSet("demo", flag.ContinueOnError)
out := fs.String("out", "", "output path to write the meme to")
if err := fs.Parse(args); err != nil {
return err
}
input := fs.Args()
if len(input) != 1 {
return fmt.Errorf("specify an input string")
}
template, text, err := resolveMeme(input[0])
if err != nil {
return err
}
if *out != "" {
f, err := os.Create(*out)
if err != nil {
return err
}
defer f.Close()
img, err := template.Render(text)
if err != nil {
return err
}
if err := jpeg.Encode(f, img, &jpeg.Options{
Quality: 100,
}); err != nil {
return err
}
}
return nil
}
func serveTemplateJPEG(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
templateName := vars["name"]
template := memelibrary.Template(templateName)
if template == nil {
http.NotFound(w, r)
return
}
query := r.URL.Query()
text := query["text"]
img, err := template.Render(text)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "image/jpeg")
w.Header().Set("Cache-Control", "public, max-age=604800")
if err := jpeg.Encode(w, img, &jpeg.Options{
Quality: 90,
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
type Plugin struct {
plugin.MattermostPlugin
router *mux.Router
}
func (p *Plugin) OnActivate() error {
p.router = mux.NewRouter()
p.router.HandleFunc("/templates/{name}.jpg", serveTemplateJPEG).Methods("GET")
return p.API.RegisterCommand(&model.Command{
Trigger: "meme",
AutoComplete: true,
AutoCompleteDesc: "Renders custom memes so you can express yourself with culture.",
})
}
func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Mattermost-User-Id") == "" {
http.Error(w, "please log in", http.StatusForbidden)
return
}
p.router.ServeHTTP(w, r)
}
func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
input := strings.TrimSpace(strings.TrimPrefix(args.Command, "/meme"))
if input == "" {
var availableMemes []string
for name, metadata := range memelibrary.Memes() {
availableMemes = append(availableMemes, name)
for _, alias := range metadata.Aliases {
availableMemes = append(availableMemes, alias)
}
}
return &model.CommandResponse{
ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL,
Text: `You can get started meming in one of two ways:
If your meme has well-defined phrasing, you can just type it:
` + "`" + `/meme brace yourself. memes are coming.` + "`" + `
If your meme doesn't have well-defined phrasing or you want more control, you can name a meme, then follow it with text to fill the slots:
` + "`" + `/meme brace-yourself "brace yourself." "memes are coming."` + "`" + `
In either case...
![brace-yourself](/plugins/memes/templates/brace-yourselves.jpg?text=brace+yourself.&text=memes+are+coming.)
Available memes: ` + strings.Join(availableMemes, ", "),
}, nil
}
template, text, err := resolveMeme(input)
if err != nil {
return nil, model.NewAppError("ExecuteCommand", "error resolving meme", nil, err.Error(), http.StatusInternalServerError)
}
queryString := ""
for _, t := range text {
if queryString == "" {
queryString += "?"
} else {
queryString += "&"
}
queryString += "text=" + url.QueryEscape(t)
}
return &model.CommandResponse{
ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL,
Text: "![" + template.Name + "](/plugins/memes/templates/" + template.Name + ".jpg" + queryString + ")",
}, nil
}
func main() {
if len(os.Args) > 1 {
if err := demo(os.Args[1:]); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
} else {
plugin.ClientMain(&Plugin{})
}
}