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

[GH-618]: Added slack attachment for webhook posts, in order to comment, edit, and close issues. #636

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cbb804e
[MI-2502]:Added custom type for webhook post in order to comment, edi…
Nityanand13 Jan 31, 2023
4378034
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Nityanand13 Jan 31, 2023
20ab25d
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Nityanand13 Feb 8, 2023
70ae885
[MI-2736]: Done the review fixes of a github PR #636 (#20)
Nityanand13 Feb 9, 2023
3cecd5d
[MI-2736]: Done the review fixes of a github PR #636 (#21)
Nityanand13 Feb 16, 2023
779f10f
[MI-2814] Done the review fixes of github PR #636 (#22)
Nityanand13 Mar 13, 2023
67c370b
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Nityanand13 Mar 13, 2023
2de4435
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
ayusht2810 Apr 9, 2024
0f40aba
[MM-618] Update validations, modal title, styling, post messages, con…
ayusht2810 Apr 10, 2024
f4f5057
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
ayusht2810 Apr 24, 2024
9f7af14
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
ayusht2810 May 1, 2024
d0e7abd
[MM-618] Remove constants and serializers package
ayusht2810 May 1, 2024
1a279e8
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
ayusht2810 Jun 21, 2024
39fe3cf
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
raghavaggarwal2308 Jul 2, 2024
c5a8d29
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
raghavaggarwal2308 Jul 5, 2024
136221f
[MM-556] Review fixes
raghavaggarwal2308 Jul 5, 2024
482fcf9
[MM-617]: converted the custom post to slack attachment for issue cre…
Kshitij-Katiyar Aug 6, 2024
79c266e
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Kshitij-Katiyar Aug 6, 2024
28300d5
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Kshitij-Katiyar Aug 30, 2024
b413828
[MM-618]: Fixed the lint
Kshitij-Katiyar Aug 30, 2024
64655a0
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Kshitij-Katiyar Sep 26, 2024
49daa01
Merge branch 'master' of github.com:mattermost/mattermost-plugin-gith…
Kshitij-Katiyar Jan 21, 2025
9ad7d48
fxed testcases
Kshitij-Katiyar Jan 21, 2025
90ec210
merge master to the PR
Kshitij-Katiyar Jan 31, 2025
25c1a3e
fixed lint
Kshitij-Katiyar Jan 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[MM-617]: converted the custom post to slack attachment for issue cre…
…ation event on Github (#37)

* [MM-617]: converted the custom post to slack attachment for issue creation

* [MM-617]: fixed lint and testcases

* [MM-617]: removed unused variables

* [MM-617]: Fixed the title of the issue slackAttachment

* [MM-617]: review fixes

* [MM-617]: fixed lint

* [MM-617]: Review fixes and code clean up

* [MM-617]: removed the custom post file

* [MM-617]: review fixes

* [MM-617]: review fixes

* [MM-617]: Fixed lint

* [MM-617]: improved the error logging
  • Loading branch information
Kshitij-Katiyar authored Aug 6, 2024
commit 482fcf9a39dec85c31c6160b28ac051ece213a08
110 changes: 106 additions & 4 deletions server/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ const (
ResponseTypeJSON ResponseType = "JSON_RESPONSE"
// ResponseTypePlain indicates that response type is text plain
ResponseTypePlain ResponseType = "TEXT_RESPONSE"

KeyRepoName string = "repo_name"
KeyRepoOwner string = "repo_owner"
KeyIssueNumber string = "issue_number"
KeyIssueID string = "issue_id"
KeyStatus string = "status"
KeyChannelID string = "channel_id"
KeyPostID string = "postId"

WebsocketEventOpenCommentModal string = "open_comment_modal"
WebsocketEventOpenStatusModal string = "open_status_modal"
WebsocketEventOpenEditModal string = "open_edit_modal"

PathOpenIssueCommentModal string = "/open-comment-modal"
PathOpenIssueEditModal string = "/open-edit-modal"
PathOpenIssueStatusModal string = "/open-status-modal"
)

func (p *Plugin) writeJSON(w http.ResponseWriter, v interface{}) {
Expand Down Expand Up @@ -124,6 +140,9 @@ func (p *Plugin) initializeAPI() {
apiRouter.HandleFunc("/issue", p.checkAuth(p.attachUserContext(p.getIssueByNumber), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/pr", p.checkAuth(p.attachUserContext(p.getPrByNumber), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc("/lhs-content", p.checkAuth(p.attachUserContext(p.getSidebarContent), ResponseTypePlain)).Methods(http.MethodGet)
apiRouter.HandleFunc(PathOpenIssueCommentModal, p.checkAuth(p.attachUserContext(p.handleOpenIssueCommentModal), ResponseTypePlain)).Methods(http.MethodPost)
apiRouter.HandleFunc(PathOpenIssueEditModal, p.checkAuth(p.attachUserContext(p.handleOpenEditIssueModal), ResponseTypePlain)).Methods(http.MethodPost)
apiRouter.HandleFunc(PathOpenIssueStatusModal, p.checkAuth(p.attachUserContext(p.handleOpenIssueStatusModal), ResponseTypePlain)).Methods(http.MethodPost)

apiRouter.HandleFunc("/config", checkPluginRequest(p.getConfig)).Methods(http.MethodGet)
apiRouter.HandleFunc("/token", checkPluginRequest(p.getToken)).Methods(http.MethodGet)
Expand Down Expand Up @@ -863,7 +882,7 @@ func (p *Plugin) createIssueComment(c *UserContext, w http.ResponseWriter, r *ht
rootID = post.RootId
}

permalinkReplyMessage := fmt.Sprintf("Comment attached to GitHub issue [#%v](%v) from a [Message](%v)", req.Number, result.GetHTMLURL(), permalink)
permalinkReplyMessage := fmt.Sprintf("Comment attached to GitHub issue [#%v](%v)", req.Number, result.GetHTMLURL())
if req.ShowAttachedMessage {
permalinkReplyMessage = fmt.Sprintf("[Message](%v) attached to GitHub issue [#%v](%v)", permalink, req.Number, result.GetHTMLURL())
}
Expand Down Expand Up @@ -1321,7 +1340,6 @@ func (p *Plugin) updateIssue(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)
Expand All @@ -1334,7 +1352,6 @@ func (p *Plugin) updateIssue(c *UserContext, w http.ResponseWriter, r *http.Requ
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", issue.PostID), StatusCode: http.StatusNotFound})
return
}
permalink = p.getPermaLink(issue.PostID)
}

githubIssue := &github.IssueRequest{
Expand Down Expand Up @@ -1392,7 +1409,6 @@ func (p *Plugin) updateIssue(c *UserContext, w http.ResponseWriter, r *http.Requ
rootID = post.RootId
}
channelID = post.ChannelId
message += fmt.Sprintf(" from a [message](%s)", permalink)
}

reply := &model.Post{
Expand Down Expand Up @@ -1622,6 +1638,92 @@ func (p *Plugin) getToken(w http.ResponseWriter, r *http.Request) {
p.writeJSON(w, info.Token)
}

func (p *Plugin) handleOpenEditIssueModal(c *UserContext, w http.ResponseWriter, r *http.Request) {
response := &model.PostActionIntegrationResponse{}
decoder := json.NewDecoder(r.Body)
postActionIntegrationRequest := &model.PostActionIntegrationRequest{}
if err := decoder.Decode(&postActionIntegrationRequest); err != nil {
p.API.LogError("Error decoding PostActionIntegrationRequest params", "Error", err.Error())
p.returnPostActionIntegrationResponse(w, response)
return
}

p.client.Frontend.PublishWebSocketEvent(
WebsocketEventOpenEditModal,
map[string]interface{}{
KeyRepoName: postActionIntegrationRequest.Context[KeyRepoName],
KeyRepoOwner: postActionIntegrationRequest.Context[KeyRepoOwner],
KeyIssueNumber: postActionIntegrationRequest.Context[KeyIssueNumber],
KeyPostID: postActionIntegrationRequest.PostId,
KeyStatus: postActionIntegrationRequest.Context[KeyStatus],
KeyChannelID: postActionIntegrationRequest.ChannelId,
},
&model.WebsocketBroadcast{UserId: postActionIntegrationRequest.UserId},
)

p.returnPostActionIntegrationResponse(w, response)
}

func (p *Plugin) returnPostActionIntegrationResponse(w http.ResponseWriter, res *model.PostActionIntegrationResponse) {
w.Header().Set("Content-Type", "application/json")

if err := json.NewEncoder(w).Encode(res); err != nil {
p.API.LogWarn("Failed to write PostActionIntegrationResponse", "Error", err.Error())
}
}

func (p *Plugin) handleOpenIssueStatusModal(c *UserContext, w http.ResponseWriter, r *http.Request) {
response := &model.PostActionIntegrationResponse{}
decoder := json.NewDecoder(r.Body)
postActionIntegrationRequest := &model.PostActionIntegrationRequest{}
if err := decoder.Decode(&postActionIntegrationRequest); err != nil {
p.API.LogError("Error decoding PostActionIntegrationRequest params", "Error", err.Error())
p.returnPostActionIntegrationResponse(w, response)
return
}

p.client.Frontend.PublishWebSocketEvent(
WebsocketEventOpenStatusModal,
map[string]interface{}{
KeyRepoName: postActionIntegrationRequest.Context[KeyRepoName],
KeyRepoOwner: postActionIntegrationRequest.Context[KeyRepoOwner],
KeyIssueNumber: postActionIntegrationRequest.Context[KeyIssueNumber],
KeyPostID: postActionIntegrationRequest.PostId,
KeyStatus: postActionIntegrationRequest.Context[KeyStatus],
KeyChannelID: postActionIntegrationRequest.ChannelId,
},
&model.WebsocketBroadcast{UserId: postActionIntegrationRequest.UserId},
)

p.returnPostActionIntegrationResponse(w, response)
}

func (p *Plugin) handleOpenIssueCommentModal(c *UserContext, w http.ResponseWriter, r *http.Request) {
response := &model.PostActionIntegrationResponse{}
decoder := json.NewDecoder(r.Body)
postActionIntegrationRequest := &model.PostActionIntegrationRequest{}
if err := decoder.Decode(&postActionIntegrationRequest); err != nil {
p.API.LogError("Error decoding PostActionIntegrationRequest params", "Error", err.Error())
p.returnPostActionIntegrationResponse(w, response)
return
}

p.client.Frontend.PublishWebSocketEvent(
WebsocketEventOpenCommentModal,
map[string]interface{}{
KeyRepoName: postActionIntegrationRequest.Context[KeyRepoName],
KeyRepoOwner: postActionIntegrationRequest.Context[KeyRepoOwner],
KeyIssueNumber: postActionIntegrationRequest.Context[KeyIssueNumber],
KeyPostID: postActionIntegrationRequest.PostId,
KeyStatus: postActionIntegrationRequest.Context[KeyStatus],
KeyChannelID: postActionIntegrationRequest.ChannelId,
},
&model.WebsocketBroadcast{UserId: postActionIntegrationRequest.UserId},
)

p.returnPostActionIntegrationResponse(w, response)
}

// parseRepo parses the owner & repository name from the repo query parameter
func parseRepo(repoParam string) (owner, repo string, err error) {
if repoParam == "" {
Expand Down
5 changes: 5 additions & 0 deletions server/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const (
labelsForProps = "labels"
descriptionForProps = "description"
titleForProps = "title"
attachmentsForProps = "attachments"
issueNumberForProps = "issue_number"
issueURLForProps = "issue_url"
repoOwnerForProps = "repo_owner"
Expand Down Expand Up @@ -1094,3 +1095,7 @@ func (p *Plugin) getUsername(mmUserID string) (string, error) {

return "@" + info.GitHubUsername, nil
}

func (p *Plugin) GetPluginAPIPath() string {
return fmt.Sprintf("%s/plugins/%s/api/v1", *p.client.Configuration.GetConfig().ServiceSettings.SiteURL, Manifest.Id)
}
16 changes: 2 additions & 14 deletions server/plugin/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func init() {

// The repo template links to the corresponding repository.
template.Must(masterTemplate.New("repo").Parse(
`[\[{{.GetFullName}}\]]({{.GetHTMLURL}})`,
`[{{.GetFullName}}]({{.GetHTMLURL}})`,
))

// The eventRepoPullRequest links to the corresponding pull request, anchored at the repo.
Expand Down Expand Up @@ -256,19 +256,7 @@ Assignees: {{range $i, $el := .Assignees -}} {{- if $i}}, {{end}}{{template "use
{{.GetPullRequest.GetBody | trimBody | quote | replaceAllGitHubUsernames}}`))

template.Must(masterTemplate.New("newIssue").Funcs(funcMap).Parse(`
{{ if eq .Config.Style "collapsed" -}}
{{template "repo" .Event.GetRepo}} New issue {{template "issue" .Event.GetIssue}} opened by {{template "user" .Event.GetSender}}.
{{- else -}}
#### {{.Event.GetIssue.GetTitle}}
##### {{template "eventRepoIssue" .Event}}
#new-issue by {{template "user" .Event.GetSender}}
{{- if ne .Config.Style "skip-body" -}}
{{- template "labels" dict "Labels" .Event.GetIssue.Labels "RepositoryURL" .Event.GetRepo.GetHTMLURL }}
{{- template "assignee" .Event.GetIssue }}

{{.Event.GetIssue.GetBody | removeComments | replaceAllGitHubUsernames}}
{{- end -}}
{{- end }}
{{template "user" .Event.GetSender}} created a new issue in {{template "repo" .Event.GetRepo}}
`))

template.Must(masterTemplate.New("closedIssue").Funcs(funcMap).Parse(`
Expand Down
Loading