2017-12-21 12:50:48 +01:00
package main
import (
"flag"
"fmt"
"image/jpeg"
"net/http"
"net/url"
"os"
2020-06-08 19:07:45 +02:00
"sort"
2017-12-21 12:50:48 +01:00
"strings"
2020-06-11 10:15:49 +02:00
"github.com/pkg/errors"
2017-12-21 12:50:48 +01:00
"github.com/gorilla/mux"
2018-07-10 15:08:33 +02:00
shellquote "github.com/kballard/go-shellquote"
2019-12-20 06:34:44 +01:00
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin"
2017-12-21 12:50:48 +01:00
2019-08-07 15:07:45 +02:00
"github.com/mattermost/mattermost-plugin-memes/server/meme"
"github.com/mattermost/mattermost-plugin-memes/server/memelibrary"
2017-12-21 12:50:48 +01:00
)
2020-06-08 19:07:45 +02:00
const memeCommand = "meme"
2017-12-21 12:50:48 +01:00
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 {
2018-07-10 15:08:33 +02:00
plugin . MattermostPlugin
2017-12-21 12:50:48 +01:00
router * mux . Router
}
2018-07-10 15:08:33 +02:00
func ( p * Plugin ) OnActivate ( ) error {
2020-09-22 11:58:49 +02:00
if p . API . GetConfig ( ) . ServiceSettings . SiteURL == nil {
p . API . LogError ( "SiteURL must be set. Some features will operate incorrectly if the SiteURL is not set. See documentation for details: http://about.mattermost.com/default-site-url" )
}
2017-12-21 12:50:48 +01:00
p . router = mux . NewRouter ( )
p . router . HandleFunc ( "/templates/{name}.jpg" , serveTemplateJPEG ) . Methods ( "GET" )
2020-06-08 19:07:45 +02:00
if err := p . API . RegisterCommand ( createMemesCommand ( ) ) ; err != nil {
return errors . Wrapf ( err , "failed to register %s command" , memeCommand )
}
return nil
}
func createMemesCommand ( ) * model . Command {
var availableMemes = getAvailableMemes ( )
memes := model . NewAutocompleteData ( memeCommand , "[meme-name]" , "Create awesome Memes yourself!" )
for _ , name := range availableMemes {
currentMeme := model . NewAutocompleteData ( name , "" , fmt . Sprintf ( "sends %s meme" , name ) )
currentMeme . AddTextArgument ( "displays text on meme" , "[text]" , "" )
memes . AddCommand ( currentMeme )
}
return & model . Command {
Trigger : memeCommand ,
2017-12-21 12:50:48 +01:00
AutoComplete : true ,
AutoCompleteDesc : "Renders custom memes so you can express yourself with culture." ,
2020-06-08 19:07:45 +02:00
AutocompleteData : memes ,
}
}
func getAvailableMemes ( ) [ ] string {
var availableMemes [ ] string
for name , metadata := range memelibrary . Memes ( ) {
availableMemes = append ( availableMemes , name )
availableMemes = append ( availableMemes , metadata . Aliases ... )
}
2020-06-11 10:15:49 +02:00
sort . Strings ( availableMemes )
2020-06-08 19:07:45 +02:00
return availableMemes
2017-12-21 12:50:48 +01:00
}
2018-07-10 15:08:33 +02:00
func ( p * Plugin ) ServeHTTP ( c * plugin . Context , w http . ResponseWriter , r * http . Request ) {
2017-12-21 12:50:48 +01:00
p . router . ServeHTTP ( w , r )
}
2018-07-10 15:08:33 +02:00
func ( p * Plugin ) ExecuteCommand ( c * plugin . Context , args * model . CommandArgs ) ( * model . CommandResponse , * model . AppError ) {
2020-09-22 11:58:49 +02:00
siteURL := p . GetSiteURL ( )
2020-05-19 18:28:37 +02:00
2017-12-21 12:50:48 +01:00
input := strings . TrimSpace ( strings . TrimPrefix ( args . Command , "/meme" ) )
2020-03-09 14:05:31 +01:00
if input == "" || input == "help" {
2020-06-08 19:07:45 +02:00
var availableMemes = getAvailableMemes ( )
2017-12-21 12:50:48 +01:00
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 ...
2020-05-19 18:28:37 +02:00
! [ brace - yourself ] ( ` + siteURL + ` / plugins / memes / templates / brace - yourselves . jpg ? text = brace + yourself . & text = memes + are + coming . )
2017-12-21 12:50:48 +01:00
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 )
}
2020-05-19 18:28:37 +02:00
resp := & model . CommandResponse {
2017-12-21 12:50:48 +01:00
ResponseType : model . COMMAND_RESPONSE_TYPE_IN_CHANNEL ,
2020-05-19 18:28:37 +02:00
Text : "![" + template . Name + "](" + siteURL + "/plugins/memes/templates/" + template . Name + ".jpg" + queryString + ")" ,
}
return resp , nil
2017-12-21 12:50:48 +01:00
}
2020-09-22 11:58:49 +02:00
func ( p * Plugin ) GetSiteURL ( ) string {
siteURL := ""
ptr := p . API . GetConfig ( ) . ServiceSettings . SiteURL
if ptr != nil {
siteURL = * ptr
}
return siteURL
}
2017-12-21 12:50:48 +01:00
func main ( ) {
if len ( os . Args ) > 1 {
if err := demo ( os . Args [ 1 : ] ) ; err != nil {
fmt . Println ( err . Error ( ) )
os . Exit ( 1 )
}
} else {
2018-07-10 15:08:33 +02:00
plugin . ClientMain ( & Plugin { } )
2017-12-21 12:50:48 +01:00
}
}