Skip to content

Commit

Permalink
Merge branch 'master' into release-2.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mattermost-build authored Mar 17, 2023
2 parents 4d0ba56 + 39a2a70 commit e1fd323
Show file tree
Hide file tree
Showing 9 changed files with 897 additions and 275 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ require (
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
github.com/yuin/goldmark v1.4.13 // indirect
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1 // indirect
google.golang.org/grpc v1.48.0 // indirect
Expand Down
11 changes: 6 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down Expand Up @@ -517,17 +517,18 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2 h1:fqTvyMIIj+HRzMmnzr9NtpHP6uVpvB5fkHcgPDC4nu8=
golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
183 changes: 182 additions & 1 deletion server/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ type Plugin struct {

webhookBroker *WebhookBroker
oauthBroker *OAuthBroker

emojiMap map[string]string
}

// NewPlugin returns an instance of a Plugin.
func NewPlugin() *Plugin {
p := &Plugin{
githubPermalinkRegex: regexp.MustCompile(`https?://(?P<haswww>www\.)?github\.com/(?P<user>[\w-]+)/(?P<repo>[\w-]+)/blob/(?P<commit>\w+)/(?P<path>[\w-/.]+)#(?P<line>[\w-]+)?`),
githubPermalinkRegex: regexp.MustCompile(`https?://(?P<haswww>www\.)?github\.com/(?P<user>[\w-]+)/(?P<repo>[\w-.]+)/blob/(?P<commit>\w+)/(?P<path>[\w-/.]+)#(?P<line>[\w-]+)?`),
}

p.CommandHandlers = map[string]CommandHandleFunc{
Expand All @@ -111,9 +113,34 @@ func NewPlugin() *Plugin {
"issue": p.handleIssue,
}

p.createGithubEmojiMap()
return p
}

func (p *Plugin) createGithubEmojiMap() {
baseGithubEmojiMap := map[string]string{
"+1": "+1",
"-1": "-1",
"thumbsup": "+1",
"thumbsdown": "-1",
"laughing": "laugh",
"confused": "confused",
"heart": "heart",
"tada": "hooray",
"rocket": "rocket",
"eyes": "eyes",
}

p.emojiMap = map[string]string{}
for systemEmoji := range model.SystemEmojis {
for mmBase, ghBase := range baseGithubEmojiMap {
if strings.HasPrefix(systemEmoji, mmBase) {
p.emojiMap[systemEmoji] = ghBase
}
}
}
}

func (p *Plugin) GetGitHubClient(ctx context.Context, userID string) (*github.Client, error) {
userInfo, apiErr := p.getGitHubUserInfo(userID)
if apiErr != nil {
Expand Down Expand Up @@ -251,6 +278,160 @@ func (p *Plugin) OnDeactivate() error {
return nil
}

func (p *Plugin) getPostPropsForReaction(reaction *model.Reaction) (org, repo string, id float64, objectType string, ok bool) {
post, err := p.client.Post.GetPost(reaction.PostId)
if err != nil {
p.API.LogDebug("Error fetching post for reaction", "error", err.Error())
return org, repo, id, objectType, false
}

// Getting the Github repository from notification post props
repo, ok = post.GetProp(postPropGithubRepo).(string)
if !ok || repo == "" {
return org, repo, id, objectType, false
}

orgRepo := strings.Split(repo, "/")
if len(orgRepo) != 2 {
p.API.LogDebug("Invalid organization repository")
return org, repo, id, objectType, false
}

org, repo = orgRepo[0], orgRepo[1]

// Getting the Github object id from notification post props
id, ok = post.GetProp(postPropGithubObjectID).(float64)
if !ok || id == 0 {
return org, repo, id, objectType, false
}

// Getting the Github object type from notification post props
objectType, ok = post.GetProp(postPropGithubObjectType).(string)
if !ok || objectType == "" {
return org, repo, id, objectType, false
}

return org, repo, id, objectType, true
}

func (p *Plugin) ReactionHasBeenAdded(c *plugin.Context, reaction *model.Reaction) {
githubEmoji := p.emojiMap[reaction.EmojiName]
if githubEmoji == "" {
p.API.LogWarn("Emoji is not supported by Github", "Emoji", reaction.EmojiName)
return
}

owner, repo, id, objectType, ok := p.getPostPropsForReaction(reaction)
if !ok {
return
}

info, appErr := p.getGitHubUserInfo(reaction.UserId)
if appErr != nil {
if appErr.ID != apiErrorIDNotConnected {
p.API.LogDebug("Error in getting user info", "error", appErr.Error())
}
return
}

ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
ghClient := p.githubConnectUser(ctx, info)
switch objectType {
case githubObjectTypeIssueComment:
if _, _, err := ghClient.Reactions.CreateIssueCommentReaction(context.Background(), owner, repo, int64(id), githubEmoji); err != nil {
p.API.LogDebug("Error occurred while creating issue comment reaction", "error", err.Error())
return
}
case githubObjectTypeIssue:
if _, _, err := ghClient.Reactions.CreateIssueReaction(context.Background(), owner, repo, int(id), githubEmoji); err != nil {
p.API.LogDebug("Error occurred while creating issue reaction", "error", err.Error())
return
}
case githubObjectTypePRReviewComment:
if _, _, err := ghClient.Reactions.CreatePullRequestCommentReaction(context.Background(), owner, repo, int64(id), githubEmoji); err != nil {
p.API.LogDebug("Error occurred while creating PR review comment reaction", "error", err.Error())
return
}
default:
return
}
}

func (p *Plugin) ReactionHasBeenRemoved(c *plugin.Context, reaction *model.Reaction) {
githubEmoji := p.emojiMap[reaction.EmojiName]
if githubEmoji == "" {
p.API.LogWarn("Emoji is not supported by Github", "Emoji", reaction.EmojiName)
return
}

owner, repo, id, objectType, ok := p.getPostPropsForReaction(reaction)
if !ok {
return
}

info, appErr := p.getGitHubUserInfo(reaction.UserId)
if appErr != nil {
if appErr.ID != apiErrorIDNotConnected {
p.API.LogDebug("Error in getting user info", "error", appErr.Error())
}
return
}

ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
ghClient := p.githubConnectUser(ctx, info)
switch objectType {
case githubObjectTypeIssueComment:
reactions, _, err := ghClient.Reactions.ListIssueCommentReactions(context.Background(), owner, repo, int64(id), &github.ListOptions{})
if err != nil {
p.API.LogDebug("Error getting issue comment reaction list", "error", err.Error())
return
}

for _, reactionObj := range reactions {
if info.UserID == reaction.UserId && p.emojiMap[reaction.EmojiName] == reactionObj.GetContent() {
if _, err = ghClient.Reactions.DeleteIssueCommentReaction(context.Background(), owner, repo, int64(id), reactionObj.GetID()); err != nil {
p.API.LogDebug("Error occurred while removing issue comment reaction", "error", err.Error())
}
return
}
}
case githubObjectTypeIssue:
reactions, _, err := ghClient.Reactions.ListIssueReactions(context.Background(), owner, repo, int(id), &github.ListOptions{})
if err != nil {
p.API.LogDebug("Error getting issue reaction list", "error", err.Error())
return
}

for _, reactionObj := range reactions {
if info.UserID == reaction.UserId && p.emojiMap[reaction.EmojiName] == reactionObj.GetContent() {
if _, err = ghClient.Reactions.DeleteIssueReaction(context.Background(), owner, repo, int(id), reactionObj.GetID()); err != nil {
p.API.LogDebug("Error occurred while removing issue reaction", "error", err.Error())
}
return
}
}
case githubObjectTypePRReviewComment:
reactions, _, err := ghClient.Reactions.ListPullRequestCommentReactions(context.Background(), owner, repo, int64(id), &github.ListOptions{})
if err != nil {
p.API.LogDebug("Error getting PR review comment reaction list", "error", err.Error())
return
}

for _, reactionObj := range reactions {
if info.UserID == reaction.UserId && p.emojiMap[reaction.EmojiName] == reactionObj.GetContent() {
if _, err = ghClient.Reactions.DeletePullRequestCommentReaction(context.Background(), owner, repo, int64(id), reactionObj.GetID()); err != nil {
p.API.LogDebug("Error occurred while removing PR review comment reaction", "error", err.Error())
}
return
}
}
default:
return
}
}

func (p *Plugin) OnInstall(c *plugin.Context, event model.OnInstallEvent) error {
// Don't start wizard if OAuth is configured
if p.getConfiguration().IsOAuthConfigured() {
Expand Down
12 changes: 11 additions & 1 deletion server/plugin/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,17 @@ Assignees: {{range $i, $el := .Assignees -}} {{- if $i}}, {{end}}{{template "use
`))

template.Must(masterTemplate.New("commentAssigneeIssueNotification").Funcs(funcMap).Parse(`
{{template "user" .GetSender}} commented on issue you are assigned to {{template "eventRepoIssueFullLinkWithTitle" .}}:
{{template "user" .GetSender}} commented on an issue you are assigned to {{template "eventRepoIssueFullLinkWithTitle" .}}:
{{.GetComment.GetBody | trimBody | quote | replaceAllGitHubUsernames}}
`))

template.Must(masterTemplate.New("commentAssigneeSelfMentionPullRequestNotification").Funcs(funcMap).Parse(`
{{template "user" .GetSender}} mentioned you on a pull request that you are assigned to {{template "eventRepoIssueFullLinkWithTitle" .}}:
{{.GetComment.GetBody | trimBody | quote | replaceAllGitHubUsernames}}
`))

template.Must(masterTemplate.New("commentAssigneeSelfMentionIssueNotification").Funcs(funcMap).Parse(`
{{template "user" .GetSender}} mentioned you on an issue that you are assigned to {{template "eventRepoIssueFullLinkWithTitle" .}}:
{{.GetComment.GetBody | trimBody | quote | replaceAllGitHubUsernames}}
`))

Expand Down
Loading

0 comments on commit e1fd323

Please sign in to comment.