Skip to content
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

Serve the profile image for the plugin from the plugin itself #50

Merged
merged 4 commits into from
Mar 11, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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/github/assets/profile.png")
jwilander marked this conversation as resolved.
Show resolved Hide resolved
}

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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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