Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Serve the profile image for the plugin from the plugin itself (#50)
* Serve the profile image from the plugin itself

* Use SiteURL instead of relative profile image URL

* Improve URL path creation
  • Loading branch information
jwilander committed Mar 11, 2019
1 parent ad6c275 commit f22f01c
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 39 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -92,6 +92,7 @@ bundle:
rm -rf dist/
mkdir -p dist/$(PLUGIN_ID)
cp $(MANIFEST_FILE) dist/$(PLUGIN_ID)/
cp -r assets dist/$(PLUGIN_ID)/assets
ifneq ($(HAS_SERVER),)
mkdir -p dist/$(PLUGIN_ID)/server/dist;
cp -r server/dist/* dist/$(PLUGIN_ID)/server/dist/;
Expand Down
Binary file added assets/profile.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 20 additions & 1 deletion server/api.go
Expand Up @@ -4,7 +4,10 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
Expand All @@ -19,7 +22,6 @@ import (

const (
API_ERROR_ID_NOT_CONNECTED = "not_connected"
GITHUB_ICON_URL = "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
GITHUB_USERNAME = "GitHub Plugin"
)

Expand Down Expand Up @@ -48,6 +50,8 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req
switch path := r.URL.Path; path {
case "/webhook":
p.handleWebhook(w, r)
case "/assets/profile.png":
p.handleProfileImage(w, r)
case "/oauth/connect":
p.connectUserToGitHub(w, r)
case "/oauth/complete":
Expand Down Expand Up @@ -207,6 +211,21 @@ func (p *Plugin) completeConnectUserToGitHub(w http.ResponseWriter, r *http.Requ
w.Write([]byte(html))
}

func (p *Plugin) handleProfileImage(w http.ResponseWriter, r *http.Request) {
config := p.getConfiguration()

img, err := os.Open(filepath.Join(config.PluginsDirectory, manifest.Id, "assets", "profile.png"))
if err != nil {
http.NotFound(w, r)
mlog.Error("Unable to read github profile image, err=" + err.Error())
return
}
defer img.Close()

w.Header().Set("Content-Type", "image/png")
io.Copy(w, img)
}

type ConnectedResponse struct {
Connected bool `json:"connected"`
GitHubUsername string `json:"github_username"`
Expand Down
52 changes: 26 additions & 26 deletions server/command.go
Expand Up @@ -45,12 +45,12 @@ func getCommand() *model.Command {
}
}

func getCommandResponse(responseType, text string) *model.CommandResponse {
func (p *Plugin) getCommandResponse(responseType, text string) *model.CommandResponse {
return &model.CommandResponse{
ResponseType: responseType,
Text: text,
Username: GITHUB_USERNAME,
IconURL: GITHUB_ICON_URL,
IconURL: p.getConfiguration().ProfileImageURL,
Type: model.POST_DEFAULT,
}
}
Expand All @@ -74,10 +74,10 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo
if action == "connect" {
config := p.API.GetConfig()
if config.ServiceSettings.SiteURL == nil {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error connecting to GitHub."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error connecting to GitHub."), nil
}

resp := getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("[Click here to link your GitHub account.](%s/plugins/github/oauth/connect)", *config.ServiceSettings.SiteURL))
resp := p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("[Click here to link your GitHub account.](%s/plugins/github/oauth/connect)", *config.ServiceSettings.SiteURL))
return resp, nil
}

Expand All @@ -90,7 +90,7 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo
if apiErr.ID == API_ERROR_ID_NOT_CONNECTED {
text = "You must connect your account to GitHub first. Either click on the GitHub logo in the bottom left of the screen or enter `/github connect`."
}
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
}

githubClient = p.githubConnect(*info.Token)
Expand All @@ -102,11 +102,11 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo

txt := ""
if len(parameters) == 0 {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Please specify a repository or 'list' command."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Please specify a repository or 'list' command."), nil
} else if len(parameters) == 1 && parameters[0] == "list" {
subs, err := p.GetSubscriptionsByChannel(args.ChannelId)
if err != nil {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, err.Error()), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, err.Error()), nil
}

if len(subs) == 0 {
Expand All @@ -117,78 +117,78 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo
for _, sub := range subs {
txt += fmt.Sprintf("* `%s` - %s\n", sub.Repository, sub.Features)
}
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, txt), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, txt), nil
} else if len(parameters) > 1 {
features = strings.Join(parameters[1:], " ")
}

_, owner, repo := parseOwnerAndRepo(parameters[0], config.EnterpriseBaseURL)
if repo == "" {
if err := p.SubscribeOrg(context.Background(), githubClient, args.UserId, owner, args.ChannelId, features); err != nil {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, err.Error()), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, err.Error()), nil
}

return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("Successfully subscribed to organization %s.", owner)), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("Successfully subscribed to organization %s.", owner)), nil
}

if err := p.Subscribe(context.Background(), githubClient, args.UserId, owner, repo, args.ChannelId, features); err != nil {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, err.Error()), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, err.Error()), nil
}

return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("Successfully subscribed to %s.", repo)), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("Successfully subscribed to %s.", repo)), nil
case "unsubscribe":
if len(parameters) == 0 {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Please specify a repository."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Please specify a repository."), nil
}

repo := parameters[0]

if err := p.Unsubscribe(args.ChannelId, repo); err != nil {
mlog.Error(err.Error())
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error trying to unsubscribe. Please try again."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error trying to unsubscribe. Please try again."), nil
}

return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("Succesfully unsubscribed from %s.", repo)), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, fmt.Sprintf("Succesfully unsubscribed from %s.", repo)), nil
case "disconnect":
p.disconnectGitHubAccount(args.UserId)
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Disconnected your GitHub account."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Disconnected your GitHub account."), nil
case "todo":
text, err := p.GetToDo(ctx, info.GitHubUsername, githubClient)
if err != nil {
mlog.Error(err.Error())
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error getting your to do items."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error getting your to do items."), nil
}
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
case "me":
gitUser, _, err := githubClient.Users.Get(ctx, "")
if err != nil {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error getting your GitHub profile."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Encountered an error getting your GitHub profile."), nil
}

text := fmt.Sprintf("You are connected to GitHub as:\n# [![image](%s =40x40)](%s) [%s](%s)", gitUser.GetAvatarURL(), gitUser.GetHTMLURL(), gitUser.GetLogin(), gitUser.GetHTMLURL())
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
case "help":
text := "###### Mattermost GitHub Plugin - Slash Command Help\n" + strings.Replace(COMMAND_HELP, "|", "`", -1)
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
case "":
text := "###### Mattermost GitHub Plugin - Slash Command Help\n" + strings.Replace(COMMAND_HELP, "|", "`", -1)
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, text), nil
case "settings":
if len(parameters) < 2 {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Please specify both a setting and value. Use `/github help` for more usage information."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Please specify both a setting and value. Use `/github help` for more usage information."), nil
}

setting := parameters[0]
if setting != SETTING_NOTIFICATIONS && setting != SETTING_REMINDERS {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Unknown setting."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Unknown setting."), nil
}

strValue := parameters[1]
value := false
if strValue == SETTING_ON {
value = true
} else if strValue != SETTING_OFF {
return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Invalid value. Accepted values are: \"on\" or \"off\"."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Invalid value. Accepted values are: \"on\" or \"off\"."), nil
}

if setting == SETTING_NOTIFICATIONS {
Expand All @@ -205,7 +205,7 @@ func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*mo

p.storeGitHubUserInfo(info)

return getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Settings updated."), nil
return p.getCommandResponse(model.COMMAND_RESPONSE_TYPE_EPHEMERAL, "Settings updated."), nil
}

return &model.CommandResponse{}, nil
Expand Down
18 changes: 16 additions & 2 deletions server/configuration.go
Expand Up @@ -2,8 +2,10 @@ package main

import (
"fmt"
"path"
"reflect"

"github.com/mattermost/mattermost-server/model"
"github.com/pkg/errors"
)

Expand All @@ -28,6 +30,8 @@ type configuration struct {
EncryptionKey string
EnterpriseBaseURL string
EnterpriseUploadURL string
PluginsDirectory string
ProfileImageURL string
}

// Clone shallow copies the configuration. Your implementation may require a deep copy if
Expand Down Expand Up @@ -81,7 +85,7 @@ func (p *Plugin) getConfiguration() *configuration {
// This method panics if setConfiguration is called with the existing configuration. This almost
// certainly means that the configuration was modified without being cloned and may result in
// an unsafe access.
func (p *Plugin) setConfiguration(configuration *configuration) {
func (p *Plugin) setConfiguration(configuration *configuration, serverConfiguration *model.Config) {
p.configurationLock.Lock()
defer p.configurationLock.Unlock()

Expand All @@ -96,6 +100,14 @@ func (p *Plugin) setConfiguration(configuration *configuration) {
panic("setConfiguration called with the existing configuration")
}

// PluginDirectory & ProfileImageURL should be set based on server configuration and not the plugin configuration
if serverConfiguration.PluginSettings.Directory != nil {
configuration.PluginsDirectory = *serverConfiguration.PluginSettings.Directory
}
if serverConfiguration.ServiceSettings.SiteURL != nil {
configuration.ProfileImageURL = path.Join(*serverConfiguration.ServiceSettings.SiteURL, "plugins", manifest.Id, "assets", "profile.png")
}

p.configuration = configuration
}

Expand All @@ -108,7 +120,9 @@ func (p *Plugin) OnConfigurationChange() error {
return errors.Wrap(err, "failed to load plugin configuration")
}

p.setConfiguration(configuration)
serverConfiguration := p.API.GetConfig()

p.setConfiguration(configuration, serverConfiguration)

return nil
}
5 changes: 4 additions & 1 deletion server/plugin.go
Expand Up @@ -88,6 +88,7 @@ func (p *Plugin) OnActivate() error {
}

p.BotUserID = user.Id

return nil
}

Expand Down Expand Up @@ -220,6 +221,8 @@ func (p *Plugin) CreateBotDMPost(userID, message, postType string) *model.AppErr
return err
}

config := p.getConfiguration()

post := &model.Post{
UserId: p.BotUserID,
ChannelId: channel.Id,
Expand All @@ -228,7 +231,7 @@ func (p *Plugin) CreateBotDMPost(userID, message, postType string) *model.AppErr
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down
19 changes: 10 additions & 9 deletions server/webhook.go
Expand Up @@ -217,7 +217,7 @@ func (p *Plugin) postPullRequestEvent(event *github.PullRequestEvent) {
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down Expand Up @@ -309,7 +309,7 @@ func (p *Plugin) postIssueEvent(event *github.IssuesEvent) {
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down Expand Up @@ -400,7 +400,7 @@ func (p *Plugin) postPushEvent(event *github.PushEvent) {
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
Message: newPushMessage,
}
Expand Down Expand Up @@ -452,7 +452,7 @@ func (p *Plugin) postCreateEvent(event *github.CreateEvent) {
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
Message: newCreateMessage,
}
Expand Down Expand Up @@ -504,7 +504,7 @@ func (p *Plugin) postDeleteEvent(event *github.DeleteEvent) {
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
Message: newDeleteMessage,
}
Expand Down Expand Up @@ -559,7 +559,7 @@ func (p *Plugin) postIssueCommentEvent(event *github.IssueCommentEvent) {
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down Expand Up @@ -641,7 +641,7 @@ func (p *Plugin) postPullRequestReviewEvent(event *github.PullRequestReviewEvent
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down Expand Up @@ -702,7 +702,7 @@ func (p *Plugin) postPullRequestReviewCommentEvent(event *github.PullRequestRevi
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down Expand Up @@ -738,6 +738,7 @@ func (p *Plugin) postPullRequestReviewCommentEvent(event *github.PullRequestRevi

func (p *Plugin) handleCommentMentionNotification(event *github.IssueCommentEvent) {
body := event.GetComment().GetBody()
config := p.getConfiguration()

// Try to parse out email footer junk
if strings.Contains(body, "notifications@github.com") {
Expand All @@ -755,7 +756,7 @@ func (p *Plugin) handleCommentMentionNotification(event *github.IssueCommentEven
Props: map[string]interface{}{
"from_webhook": "true",
"override_username": GITHUB_USERNAME,
"override_icon_url": GITHUB_ICON_URL,
"override_icon_url": config.ProfileImageURL,
},
}

Expand Down

0 comments on commit f22f01c

Please sign in to comment.