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

[MM-617]: converted the custom post to slack attachment for issue creation event on Github #37

Merged
merged 12 commits into from
Aug 6, 2024
69 changes: 37 additions & 32 deletions server/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,22 @@ const (
ResponseTypeJSON ResponseType = "JSON_RESPONSE"
// ResponseTypePlain indicates that response type is text plain
ResponseTypePlain ResponseType = "TEXT_RESPONSE"
RepoName string = "repo_name"
RepoOwner string = "repo_owner"
IssueNumber string = "issue_number"
IssueID string = "issue_id"
Status string = "status"
ChannelID string = "channel_id"
PostID string = "postId"

CommentModalHeader string = "comment_modal"
StatusModalHeader string = "status_modal"
EditModalHeader string = "edit_modal"

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"

OpenCommentModalPath string = "/open-comment-modal"
OpenEditIssueModalPath string = "/open-edit-modal"
OpenStatusModalPath string = "/open-status-modal"
)

func (p *Plugin) writeJSON(w http.ResponseWriter, v interface{}) {
Expand Down Expand Up @@ -1644,14 +1649,14 @@ func (p *Plugin) handleOpenEditIssueModal(c *UserContext, w http.ResponseWriter,
}

p.client.Frontend.PublishWebSocketEvent(
EditModalHeader,
WebsocketEventOpenEditModal,
map[string]interface{}{
RepoName: postActionIntegrationRequest.Context[RepoName],
RepoOwner: postActionIntegrationRequest.Context[RepoOwner],
IssueNumber: postActionIntegrationRequest.Context[IssueNumber],
PostID: postActionIntegrationRequest.PostId,
Status: postActionIntegrationRequest.Context[Status],
ChannelID: postActionIntegrationRequest.ChannelId,
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},
)
Expand All @@ -1678,14 +1683,14 @@ func (p *Plugin) handleOpenIssueStatusModal(c *UserContext, w http.ResponseWrite
}

p.client.Frontend.PublishWebSocketEvent(
StatusModalHeader,
WebsocketEventOpenStatusModal,
map[string]interface{}{
RepoName: postActionIntegrationRequest.Context[RepoName],
RepoOwner: postActionIntegrationRequest.Context[RepoOwner],
IssueNumber: postActionIntegrationRequest.Context[IssueNumber],
PostID: postActionIntegrationRequest.PostId,
Status: postActionIntegrationRequest.Context[Status],
ChannelID: postActionIntegrationRequest.ChannelId,
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},
)
Expand All @@ -1704,14 +1709,14 @@ func (p *Plugin) handleOpenIssueCommentModal(c *UserContext, w http.ResponseWrit
}

p.client.Frontend.PublishWebSocketEvent(
CommentModalHeader,
WebsocketEventOpenCommentModal,
map[string]interface{}{
RepoName: postActionIntegrationRequest.Context[RepoName],
RepoOwner: postActionIntegrationRequest.Context[RepoOwner],
IssueNumber: postActionIntegrationRequest.Context[IssueNumber],
PostID: postActionIntegrationRequest.PostId,
Status: postActionIntegrationRequest.Context[Status],
ChannelID: postActionIntegrationRequest.ChannelId,
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},
)
Expand Down
6 changes: 5 additions & 1 deletion server/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const (
labelsForProps = "labels"
descriptionForProps = "description"
titleForProps = "title"
attachments = "attachments"
attachmentsForProps = "attachments"
issueNumberForProps = "issue_number"
issueURLForProps = "issue_url"
repoOwnerForProps = "repo_owner"
Expand Down Expand Up @@ -1095,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/github/api/v1", *p.client.Configuration.GetConfig().ServiceSettings.SiteURL)
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
}
89 changes: 27 additions & 62 deletions server/plugin/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,79 +393,23 @@ func (p *Plugin) updatePost(issue *UpdateIssueRequest, w http.ResponseWriter) {
return
}

attachment, err := getAttachmentsFromProps(post.Props)
attachments, err := getAttachmentsFromProps(post.Props)
if err != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: fmt.Sprintf("existing attachments format error: %v", err), StatusCode: http.StatusInternalServerError})
return
}

if len(issue.Assignees) > 0 {
assigneesField := findField(attachment[0].Fields, "Assignees")
if assigneesField != nil {
assigneesField.Value = strings.Join(issue.Assignees, ", ")
} else {
attachment[0].Fields = append(attachment[0].Fields, &model.SlackAttachmentField{
Title: "Assignees",
Value: strings.Join(issue.Assignees, ", "),
Short: true,
})
}
} else {
attachment[0].Fields = removeField(attachment[0].Fields, "Assignees")
}

if len(issue.Labels) > 0 {
labelsField := findField(attachment[0].Fields, "Labels")
if labelsField != nil {
labelsField.Value = strings.Join(issue.Labels, ", ")
} else {
attachment[0].Fields = append(attachment[0].Fields, &model.SlackAttachmentField{
Title: "Labels",
Value: strings.Join(issue.Labels, ", "),
Short: true,
})
}
} else {
attachment[0].Fields = removeField(attachment[0].Fields, "Labels")
}
attachments[0].Fields = p.CreateFieldsForIssuePost(issue.Assignees, issue.Labels)
attachments[0].Title = fmt.Sprintf("%s #%d", issue.Title, issue.IssueNumber)
attachments[0].Text = issue.Body

if attachment[0].Title != issue.Title {
attachment[0].Title = fmt.Sprintf("%s #%d", issue.Title, issue.IssueNumber)
}

if attachment[0].Text != issue.Body {
attachment[0].Text = issue.Body
}

post.Props[attachments] = attachment
post.Props[assigneesForProps] = issue.Assignees
post.Props[labelsForProps] = issue.Labels
post.Props[descriptionForProps] = issue.Body
post.Props[titleForProps] = issue.Title
post.Props[attachmentsForProps] = attachments

if _, appErr = p.API.UpdatePost(post); appErr != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to update the post %s", issue.PostID), StatusCode: http.StatusInternalServerError})
}
}

func findField(fields []*model.SlackAttachmentField, title string) *model.SlackAttachmentField {
for _, field := range fields {
if field.Title == title {
return field
}
}
return nil
}

func removeField(fields []*model.SlackAttachmentField, title string) []*model.SlackAttachmentField {
for i, field := range fields {
if field.Title == title {
return append(fields[:i], fields[i+1:]...)
}
}
return fields
}

func getAttachmentsFromProps(props map[string]interface{}) ([]*model.SlackAttachment, error) {
attachments, ok := props["attachments"]
if !ok {
Expand Down Expand Up @@ -604,7 +548,7 @@ func (p *Plugin) CloseOrReopenIssue(c *UserContext, w http.ResponseWriter, statu
}
}
attachment[0].Actions = actions
post.Props[attachments] = attachment
post.Props[attachmentsForProps] = attachment

if _, appErr := p.API.UpdatePost(post); appErr != nil {
p.writeAPIError(w, &APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to update the post %s", post.Id), StatusCode: http.StatusInternalServerError})
Expand All @@ -631,3 +575,24 @@ func lastN(s string, n int) string {

return string(out)
}

func (p *Plugin) CreateFieldsForIssuePost(assignees []string, labels []string) []*model.SlackAttachmentField {
fields := []*model.SlackAttachmentField{}
if len(assignees) > 0 {
fields = append(fields, &model.SlackAttachmentField{
Title: "Assignees",
Value: strings.Join(assignees, ", "),
Short: true,
})
}

if len(labels) > 0 {
fields = append(fields, &model.SlackAttachmentField{
Title: "Labels",
Value: strings.Join(labels, ", "),
Short: true,
})
}

return fields
}
75 changes: 22 additions & 53 deletions server/plugin/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,6 @@ type EventWithRenderConfig struct {
Config RenderConfig
}

const (
BasePath string = "/api/v1"
OpenCommentModalPath string = "/open-comment-modal"
OpenEditIssueModalPath string = "/open-edit-modal"
OpenStatusModalPath string = "/open-status-modal"

CommentIssueModalTitle string = "Comment"
EditIssueModalTitle string = "Edit"
CloseIssueModalTitle string = "Close"
)

func verifyWebhookSignature(secret []byte, signature string, body []byte) (bool, error) {
const signaturePrefix = "sha1="
const signatureLength = 45
Expand Down Expand Up @@ -606,27 +595,7 @@ func (p *Plugin) postIssueEvent(event *github.IssuesEvent) {
Type: "custom_git_release",
}

pluginURL := p.flowManager.pluginURL

if action == actionOpened {
fields := []*model.SlackAttachmentField{}

if len(assignees) > 0 {
fields = append(fields, &model.SlackAttachmentField{
Title: "Assignees",
Value: strings.Join(assignees, ", "),
Short: true,
})
}

if len(labels) > 0 {
fields = append(fields, &model.SlackAttachmentField{
Title: "Labels",
Value: strings.Join(labels, ", "),
Short: true,
})
}

post.Props = model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Expand All @@ -636,47 +605,47 @@ func (p *Plugin) postIssueEvent(event *github.IssuesEvent) {
Text: description,
Actions: []*model.PostAction{
{
Name: CommentIssueModalTitle,
Name: "Comment",
Integration: &model.PostActionIntegration{
Context: map[string]interface{}{
RepoOwner: repo.GetOwner().GetLogin(),
RepoName: repo.GetName(),
IssueNumber: issue.GetNumber(),
IssueID: issue.GetID(),
Status: *issue.State,
KeyRepoOwner: repo.GetOwner().GetLogin(),
KeyRepoName: repo.GetName(),
KeyIssueNumber: issue.GetNumber(),
KeyIssueID: issue.GetID(),
KeyStatus: *issue.State,
},
URL: fmt.Sprintf("%s%s%s", pluginURL, BasePath, OpenCommentModalPath),
URL: fmt.Sprintf("%s%s", p.GetPluginAPIPath(), OpenCommentModalPath),
},
Style: "primary",
},
{
Name: EditIssueModalTitle,
Name: "Edit",
Integration: &model.PostActionIntegration{
Context: map[string]interface{}{
RepoOwner: repo.GetOwner().GetLogin(),
RepoName: repo.GetName(),
IssueNumber: issue.GetNumber(),
IssueID: issue.GetID(),
Status: *issue.State,
KeyRepoOwner: repo.GetOwner().GetLogin(),
KeyRepoName: repo.GetName(),
KeyIssueNumber: issue.GetNumber(),
KeyIssueID: issue.GetID(),
KeyStatus: *issue.State,
},
URL: fmt.Sprintf("%s%s%s", pluginURL, BasePath, OpenEditIssueModalPath),
URL: fmt.Sprintf("%s%s", p.GetPluginAPIPath(), OpenEditIssueModalPath),
},
},
{
Name: CloseIssueModalTitle,
Name: "Close",
Integration: &model.PostActionIntegration{
Context: map[string]interface{}{
RepoOwner: repo.GetOwner().GetLogin(),
RepoName: repo.GetName(),
IssueNumber: issue.GetNumber(),
IssueID: issue.GetID(),
Status: *issue.State,
KeyRepoOwner: repo.GetOwner().GetLogin(),
KeyRepoName: repo.GetName(),
KeyIssueNumber: issue.GetNumber(),
KeyIssueID: issue.GetID(),
KeyStatus: *issue.State,
},
URL: fmt.Sprintf("%s%s%s", pluginURL, BasePath, OpenStatusModalPath),
URL: fmt.Sprintf("%s%s", p.GetPluginAPIPath(), OpenStatusModalPath),
},
},
},
Fields: fields,
Fields: p.CreateFieldsForIssuePost(assignees, labels),
},
},
}
Expand Down
Loading