Skip to content

Commit

Permalink
Merge branch 'master' into pw-specs
Browse files Browse the repository at this point in the history
* master:
  [MM-50985] Remove usage of model.AppError (#648)
  [GH-548]:Fixed issue #548 on github 'org lock for username not working'  (#658)
  • Loading branch information
trilopin committed Apr 17, 2023
2 parents 07fdaef + c712474 commit ec8ba8a
Show file tree
Hide file tree
Showing 15 changed files with 330 additions and 290 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/google/go-github/v41 v41.0.0
github.com/gorilla/mux v1.8.0
github.com/mattermost/mattermost-plugin-api v0.1.3-0.20230323124751-86c7be7ffbac
github.com/mattermost/mattermost-plugin-api v0.1.3
// mmgoget: github.com/mattermost/mattermost-server/v6@v7.5.0 is replaced by -> github.com/mattermost/mattermost-server/v6@21aec2741b
github.com/mattermost/mattermost-server/v6 v6.0.0-20221109191448-21aec2741bfe
github.com/microcosm-cc/bluemonday v1.0.19
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d h1:/RJ/UV7M5c7L2TQ
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ=
github.com/mattermost/logr/v2 v2.0.15 h1:+WNbGcsc3dBao65eXlceB6dTILNJRIrvubnsTl3zBew=
github.com/mattermost/logr/v2 v2.0.15/go.mod h1:mpPp935r5dIkFDo2y9Q87cQWhFR/4xXpNh0k/y8Hmwg=
github.com/mattermost/mattermost-plugin-api v0.1.3-0.20230323124751-86c7be7ffbac h1:fxdqYaw6wJfMSodMP0SNPm31r9kJ0NI8uQiWVpnj8F0=
github.com/mattermost/mattermost-plugin-api v0.1.3-0.20230323124751-86c7be7ffbac/go.mod h1:EON5x6XoqubANT9zYLuL+m42SijzpK/dDOuu76PGbSc=
github.com/mattermost/mattermost-plugin-api v0.1.3 h1:Z5KBAV/Lpsf1NleSRSeun3jPQOIvN3/G+Xw5DqB2rac=
github.com/mattermost/mattermost-plugin-api v0.1.3/go.mod h1:EON5x6XoqubANT9zYLuL+m42SijzpK/dDOuu76PGbSc=
github.com/mattermost/mattermost-server/v6 v6.0.0-20221109191448-21aec2741bfe h1:9P759/e7xB3IQYo+6Ju9qsj3YUxpnPRXl2x+XFFsRIM=
github.com/mattermost/mattermost-server/v6 v6.0.0-20221109191448-21aec2741bfe/go.mod h1:Eu6nct2XZRPlHHW4MfZtjli5bY7G9QomKcor/lm+0Sw=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
Expand Down
157 changes: 91 additions & 66 deletions server/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/pkg/errors"
"golang.org/x/oauth2"

pluginapi "github.com/mattermost/mattermost-plugin-api"
"github.com/mattermost/mattermost-plugin-api/experimental/bot/logger"
"github.com/mattermost/mattermost-plugin-api/experimental/flow"
"github.com/mattermost/mattermost-server/v6/model"
Expand Down Expand Up @@ -86,13 +87,13 @@ const (
func (p *Plugin) writeJSON(w http.ResponseWriter, v interface{}) {
b, err := json.Marshal(v)
if err != nil {
p.API.LogWarn("Failed to marshal JSON response", "error", err.Error())
p.client.Log.Warn("Failed to marshal JSON response", "error", err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
_, err = w.Write(b)
if err != nil {
p.API.LogWarn("Failed to write JSON response", "error", err.Error())
p.client.Log.Warn("Failed to write JSON response", "error", err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand All @@ -101,7 +102,7 @@ func (p *Plugin) writeJSON(w http.ResponseWriter, v interface{}) {
func (p *Plugin) writeAPIError(w http.ResponseWriter, apiErr *APIErrorResponse) {
b, err := json.Marshal(apiErr)
if err != nil {
p.API.LogWarn("Failed to marshal API error", "error", err.Error())
p.client.Log.Warn("Failed to marshal API error", "error", err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand All @@ -110,7 +111,7 @@ func (p *Plugin) writeAPIError(w http.ResponseWriter, apiErr *APIErrorResponse)

_, err = w.Write(b)
if err != nil {
p.API.LogWarn("Failed to write JSON response", "error", err.Error())
p.client.Log.Warn("Failed to write JSON response", "error", err.Error())
w.WriteHeader(http.StatusInternalServerError)
return
}
Expand Down Expand Up @@ -158,7 +159,7 @@ func (p *Plugin) withRecovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if x := recover(); x != nil {
p.API.LogWarn("Recovered from a panic",
p.client.Log.Warn("Recovered from a panic",
"url", r.URL.String(),
"error", x,
"stack", string(debug.Stack()))
Expand Down Expand Up @@ -192,7 +193,7 @@ func (p *Plugin) checkAuth(handler http.HandlerFunc, responseType ResponseType)
case ResponseTypePlain:
http.Error(w, "Not authorized", http.StatusUnauthorized)
default:
p.API.LogDebug("Unknown ResponseType detected")
p.client.Log.Debug("Unknown ResponseType detected")
}
return
}
Expand Down Expand Up @@ -286,14 +287,8 @@ func (p *Plugin) connectUserToGitHub(c *Context, w http.ResponseWriter, r *http.
PrivateAllowed: privateAllowed,
}

stateBytes, err := json.Marshal(state)
_, err := p.client.KV.Set(githubOauthKey+state.Token, state, pluginapi.SetExpiry(TokenTTL))
if err != nil {
http.Error(w, "json marshal failed", http.StatusInternalServerError)
return
}

appErr := p.API.KVSetWithExpiry(githubOauthKey+state.Token, stateBytes, TokenTTL)
if appErr != nil {
http.Error(w, "error setting stored state", http.StatusBadRequest)
return
}
Expand Down Expand Up @@ -347,27 +342,21 @@ func (p *Plugin) completeConnectUserToGitHub(c *Context, w http.ResponseWriter,

stateToken := r.URL.Query().Get("state")

storedState, appErr := p.API.KVGet(githubOauthKey + stateToken)
if appErr != nil {
c.Log.Warnf("Failed to get state token", "error", appErr.Error())

rErr = errors.Wrap(appErr, "missing stored state")
http.Error(w, rErr.Error(), http.StatusBadRequest)
return
}
var state OAuthState
err := p.client.KV.Get(githubOauthKey+stateToken, &state)
if err != nil {
c.Log.Warnf("Failed to get state token", "error", err.Error())

if err := json.Unmarshal(storedState, &state); err != nil {
rErr = errors.Wrap(err, "json unmarshal failed")
http.Error(w, err.Error(), http.StatusBadRequest)
rErr = errors.Wrap(err, "missing stored state")
http.Error(w, rErr.Error(), http.StatusBadRequest)
return
}

appErr = p.API.KVDelete(githubOauthKey + stateToken)
if appErr != nil {
c.Log.WithError(appErr).Warnf("Failed to delete state token")
err = p.client.KV.Delete(githubOauthKey + stateToken)
if err != nil {
c.Log.WithError(err).Warnf("Failed to delete state token")

rErr = errors.Wrap(appErr, "error deleting stored state")
rErr = errors.Wrap(err, "error deleting stored state")
http.Error(w, rErr.Error(), http.StatusBadRequest)
return
}
Expand Down Expand Up @@ -483,7 +472,7 @@ func (p *Plugin) completeConnectUserToGitHub(c *Context, w http.ResponseWriter,

config := p.getConfiguration()

p.API.PublishWebSocketEvent(
p.client.Frontend.PublishWebSocketEvent(
wsEventConnect,
map[string]interface{}{
"connected": true,
Expand Down Expand Up @@ -621,7 +610,8 @@ func (p *Plugin) getConnected(c *Context, w http.ResponseWriter, r *http.Request

privateRepoStoreKey := info.UserID + githubPrivateRepoKey
if config.EnablePrivateRepo && !info.AllowedPrivateRepos {
val, err := p.API.KVGet(privateRepoStoreKey)
var val []byte
err := p.client.KV.Get(privateRepoStoreKey, &val)
if err != nil {
c.Log.WithError(err).Warnf("Unable to get private repo key value")
return
Expand All @@ -635,7 +625,7 @@ func (p *Plugin) getConnected(c *Context, w http.ResponseWriter, r *http.Request
} else {
p.CreateBotDMPost(info.UserID, fmt.Sprintf(message, "`/github connect private`."), "")
}
err := p.API.KVSet(privateRepoStoreKey, []byte("1"))
_, err := p.client.KV.Set(privateRepoStoreKey, []byte("1"))
if err != nil {
c.Log.WithError(err).Warnf("Unable to set private repo key value")
}
Expand Down Expand Up @@ -852,7 +842,7 @@ func (p *Plugin) searchIssues(c *UserContext, w http.ResponseWriter, r *http.Req
}

func (p *Plugin) getPermaLink(postID string) string {
siteURL := *p.API.GetConfig().ServiceSettings.SiteURL
siteURL := *p.client.Configuration.GetConfig().ServiceSettings.SiteURL

return fmt.Sprintf("%v/_redirect/pl/%v", siteURL, postID)
}
Expand Down Expand Up @@ -919,8 +909,8 @@ func (p *Plugin) createIssueComment(c *UserContext, w http.ResponseWriter, r *ht

githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo)

post, appErr := p.API.GetPost(req.PostID)
if appErr != nil {
post, err := p.client.Post.GetPost(req.PostID)
if err != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "failed to load post " + req.PostID, StatusCode: http.StatusInternalServerError})
return
}
Expand Down Expand Up @@ -968,8 +958,8 @@ func (p *Plugin) createIssueComment(c *UserContext, w http.ResponseWriter, r *ht
UserId: c.UserID,
}

_, appErr = p.API.CreatePost(reply)
if appErr != nil {
err = p.client.Post.CreatePost(reply)
if err != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "failed to create notification post " + req.PostID, StatusCode: http.StatusInternalServerError})
return
}
Expand Down Expand Up @@ -1206,41 +1196,75 @@ func (p *Plugin) getMilestones(c *UserContext, w http.ResponseWriter, r *http.Re
p.writeJSON(w, allMilestones)
}

func getRepositoryList(c context.Context, userName string, githubClient *github.Client, opt github.ListOptions) ([]*github.Repository, error) {
var allRepos []*github.Repository
for {
repos, resp, err := githubClient.Repositories.List(c, userName, &github.RepositoryListOptions{ListOptions: opt})
if err != nil {
return nil, err
}

allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}

opt.Page = resp.NextPage
}

return allRepos, nil
}

func getRepositoryListByOrg(c context.Context, org string, githubClient *github.Client, opt github.ListOptions) ([]*github.Repository, int, error) {
var allRepos []*github.Repository
for {
repos, resp, err := githubClient.Repositories.ListByOrg(c, org, &github.RepositoryListByOrgOptions{Sort: "full_name", ListOptions: opt})
if err != nil {
return nil, resp.StatusCode, err
}

allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}

return allRepos, http.StatusOK, nil
}

func (p *Plugin) getRepositories(c *UserContext, w http.ResponseWriter, r *http.Request) {
githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo)

org := p.getConfiguration().GitHubOrg

var allRepos []*github.Repository
var err error
var statusCode int
opt := github.ListOptions{PerPage: 50}

if org == "" {
for {
repos, resp, err := githubClient.Repositories.List(c.Ctx, "", &github.RepositoryListOptions{ListOptions: opt})
if err != nil {
c.Log.WithError(err).Warnf("Failed to list repositories")
p.writeAPIError(w, &APIErrorResponse{Message: "Failed to fetch repositories", StatusCode: http.StatusInternalServerError})
return
}
allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
allRepos, err = getRepositoryList(c.Ctx, "", githubClient, opt)
if err != nil {
c.Log.WithError(err).Warnf("Failed to list repositories")
p.writeAPIError(w, &APIErrorResponse{Message: "Failed to fetch repositories", StatusCode: http.StatusInternalServerError})
return
}
} else {
for {
repos, resp, err := githubClient.Repositories.ListByOrg(c.Ctx, org, &github.RepositoryListByOrgOptions{Sort: "full_name", ListOptions: opt})
if err != nil {
c.Log.WithError(err).Warnf("Failed to list repositories by org")
allRepos, statusCode, err = getRepositoryListByOrg(c.Ctx, org, githubClient, opt)
if err != nil {
if statusCode == http.StatusNotFound {
allRepos, err = getRepositoryList(c.Ctx, org, githubClient, opt)
if err != nil {
c.Log.WithError(err).Warnf("Failed to list repositories")
p.writeAPIError(w, &APIErrorResponse{Message: "Failed to fetch repositories", StatusCode: http.StatusInternalServerError})
return
}
} else {
c.Log.WithError(err).Warnf("Failed to list repositories")
p.writeAPIError(w, &APIErrorResponse{Message: "Failed to fetch repositories", StatusCode: http.StatusInternalServerError})
return
}
allRepos = append(allRepos, repos...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}
}

Expand Down Expand Up @@ -1275,6 +1299,7 @@ func (p *Plugin) createIssue(c *UserContext, w http.ResponseWriter, r *http.Requ

// get data for the issue from the request body and fill IssueRequest object
issue := &IssueRequest{}

if err := json.NewDecoder(r.Body).Decode(&issue); err != nil {
c.Log.WithError(err).Warnf("Error decoding JSON body")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "Please provide a JSON object.", StatusCode: http.StatusBadRequest})
Expand All @@ -1300,9 +1325,9 @@ func (p *Plugin) createIssue(c *UserContext, w http.ResponseWriter, r *http.Requ
var post *model.Post
permalink := ""
if issue.PostID != "" {
var appErr *model.AppError
post, appErr = p.API.GetPost(issue.PostID)
if appErr != nil {
var err error
post, err = p.client.Post.GetPost(issue.PostID)
if err != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "failed to load post " + issue.PostID, StatusCode: http.StatusInternalServerError})
return
}
Expand Down Expand Up @@ -1340,8 +1365,8 @@ func (p *Plugin) createIssue(c *UserContext, w http.ResponseWriter, r *http.Requ
}
*ghIssue.Body = ghIssue.GetBody() + mmMessage

currentUser, appErr := p.API.GetUser(c.UserID)
if appErr != nil {
currentUser, err := p.client.User.Get(c.UserID)
if err != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "failed to load current user", StatusCode: http.StatusInternalServerError})
return
}
Expand Down Expand Up @@ -1390,12 +1415,12 @@ func (p *Plugin) createIssue(c *UserContext, w http.ResponseWriter, r *http.Requ
}

if post != nil {
_, appErr = p.API.CreatePost(reply)
err = p.client.Post.CreatePost(reply)
} else {
p.API.SendEphemeralPost(c.UserID, reply)
p.client.Post.SendEphemeralPost(c.UserID, reply)
}
if appErr != nil {
c.Log.WithError(appErr).Warnf("failed to create notification post")
if err != nil {
c.Log.WithError(err).Warnf("failed to create notification post")
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: "failed to create notification post, postID: " + issue.PostID + ", channelID: " + channelID, StatusCode: http.StatusInternalServerError})
return
}
Expand Down
2 changes: 2 additions & 0 deletions server/plugin/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http/httptest"
"testing"

pluginapi "github.com/mattermost/mattermost-plugin-api"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/plugin/plugintest"
"github.com/stretchr/testify/mock"
Expand Down Expand Up @@ -36,6 +37,7 @@ func TestWithRecovery(t *testing.T) {
"error", "bad handler",
"stack", mock.Anything)
p.SetAPI(api)
p.client = pluginapi.NewClient(p.API, p.Driver)

ph := panicHandler{}
handler := p.withRecovery(ph)
Expand Down
12 changes: 6 additions & 6 deletions server/plugin/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (p *Plugin) sendOAuthCompleteEvent(event OAuthCompleteEvent) {
func (p *Plugin) sendMessageToCluster(id string, v interface{}) {
b, err := json.Marshal(v)
if err != nil {
p.API.LogWarn("couldn't get JSON bytes from cluster message",
p.client.Log.Warn("couldn't get JSON bytes from cluster message",
"id", id,
"error", err,
)
Expand All @@ -35,8 +35,8 @@ func (p *Plugin) sendMessageToCluster(id string, v interface{}) {
SendType: model.PluginClusterEventSendTypeReliable,
}

if err := p.API.PublishPluginClusterEvent(event, opts); err != nil {
p.API.LogWarn("error publishing cluster event",
if err := p.client.Cluster.PublishPluginEvent(event, opts); err != nil {
p.client.Log.Warn("error publishing cluster event",
"id", id,
"error", err,
)
Expand All @@ -48,20 +48,20 @@ func (p *Plugin) HandleClusterEvent(ev model.PluginClusterEvent) {
case webHookPingEventID:
var event github.PingEvent
if err := json.Unmarshal(ev.Data, &event); err != nil {
p.API.LogWarn("cannot unmarshal cluster event with GitHub ping event", "error", err)
p.client.Log.Warn("cannot unmarshal cluster event with GitHub ping event", "error", err)
return
}

p.webhookBroker.publishPing(&event, true)
case oauthCompleteEventID:
var event OAuthCompleteEvent
if err := json.Unmarshal(ev.Data, &event); err != nil {
p.API.LogWarn("cannot unmarshal cluster event with OAuth complete event", "error", err)
p.client.Log.Warn("cannot unmarshal cluster event with OAuth complete event", "error", err)
return
}

p.oauthBroker.publishOAuthComplete(event.UserID, event.Err, true)
default:
p.API.LogWarn("unknown cluster event", "id", ev.Id)
p.client.Log.Warn("unknown cluster event", "id", ev.Id)
}
}
Loading

0 comments on commit ec8ba8a

Please sign in to comment.