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

[MI-2502]:Added custom type for webhook post in order to comment, edit and close issues #13

Merged
merged 14 commits into from
Jan 31, 2023
Merged
101 changes: 46 additions & 55 deletions server/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -959,102 +959,98 @@ func (p *Plugin) updateSettings(c *serializer.UserContext, w http.ResponseWriter
}

func (p *Plugin) openAttachCommentIssueModal(c *serializer.UserContext, w http.ResponseWriter, r *http.Request) {
owner := r.FormValue(constants.OwnerQueryParam)
repo := r.FormValue(constants.RepoQueryParam)
number := r.FormValue(constants.NumberQueryParam)
postID := r.FormValue(constants.PostIdQueryParam)
issueNumber, err := strconv.Atoi(number)
if err != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{Message: "Invalid param 'number'.", StatusCode: http.StatusBadRequest})
req := &serializer.OpenCreateCommentOrEditIssueModal{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
c.Log.WithError(err).Warnf("Error decoding the JSON body")
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: "Please provide a valid JSON object.", StatusCode: http.StatusBadRequest})
return
}
Nityanand13 marked this conversation as resolved.
Show resolved Hide resolved

userID := r.Header.Get(constants.HeaderMattermostUserID)
post, appErr := p.API.GetPost(postID)
post, appErr := p.API.GetPost(req.PostID)
if appErr != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s", postID), StatusCode: http.StatusInternalServerError})
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s", req.PostID), StatusCode: http.StatusInternalServerError})
return
}
if post == nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", postID), StatusCode: http.StatusNotFound})
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", req.PostID), StatusCode: http.StatusNotFound})
return
}
Nityanand13 marked this conversation as resolved.
Show resolved Hide resolved

p.API.PublishWebSocketEvent(
wsEventAttachCommentToIssue,
map[string]interface{}{
"postId": post.Id,
"owner": owner,
"repo": repo,
"number": issueNumber,
"owner": req.RepoOwner,
"repo": req.RepoName,
"number": req.IssueNumber,
},
&model.WebsocketBroadcast{UserId: userID},
)
}

func (p *Plugin) openCloseOrReopenIssueModal(c *serializer.UserContext, w http.ResponseWriter, r *http.Request) {
owner := r.FormValue(constants.OwnerQueryParam)
repo := r.FormValue(constants.RepoQueryParam)
number := r.FormValue(constants.NumberQueryParam)
postID := r.FormValue(constants.PostIdQueryParam)
req := &serializer.OpenCreateCommentOrEditIssueModal{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
c.Log.WithError(err).Warnf("Error decoding the JSON body")
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: "Please provide a valid JSON object.", StatusCode: http.StatusBadRequest})
return
}

userID := r.Header.Get(constants.HeaderMattermostUserID)
status := r.FormValue(constants.IssueStatus)
post, appErr := p.API.GetPost(postID)

post, appErr := p.API.GetPost(req.PostID)
if appErr != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s", postID), StatusCode: http.StatusInternalServerError})
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s", req.PostID), StatusCode: http.StatusInternalServerError})
return
}
if post == nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", postID), StatusCode: http.StatusNotFound})
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", req.PostID), StatusCode: http.StatusNotFound})
return
}

p.API.PublishWebSocketEvent(
wsEventCloseOrReopenIssue,
map[string]interface{}{
"channel_id": post.ChannelId,
"owner": owner,
"repo": repo,
"number": number,
"status": status,
"postId": postID,
"owner": req.RepoOwner,
"repo": req.RepoName,
"number": req.IssueNumber,
"status": req.Status,
"postId": req.PostID,
},
&model.WebsocketBroadcast{UserId: userID},
)
}

func (p *Plugin) openIssueEditModal(c *serializer.UserContext, w http.ResponseWriter, r *http.Request) {
owner := r.FormValue(constants.OwnerQueryParam)
repo := r.FormValue(constants.RepoQueryParam)
number := r.FormValue(constants.NumberQueryParam)
postID := r.FormValue(constants.PostIdQueryParam)
issueNumber, err := strconv.Atoi(number)
if err != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{Message: "Invalid param 'number'.", StatusCode: http.StatusBadRequest})
req := &serializer.OpenCreateCommentOrEditIssueModal{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
c.Log.WithError(err).Warnf("Error decoding the JSON body")
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: "Please provide a valid JSON object.", StatusCode: http.StatusBadRequest})
return
}

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

issue, _, err := githubClient.Issues.Get(c.Ctx, owner, repo, issueNumber)
issue, _, err := githubClient.Issues.Get(c.Ctx, req.RepoOwner, req.RepoName, req.IssueNumber)
if err != nil {
// If the issue is not found, it probably belongs to a private repo.
// Return an empty response in that case.
var gerr *github.ErrorResponse
if errors.As(err, &gerr) && gerr.Response.StatusCode == http.StatusNotFound {
c.Log.WithError(err).With(logger.LogContext{
"owner": owner,
"repo": repo,
"number": issueNumber,
"owner": req.RepoOwner,
"repo": req.RepoName,
"number": req.IssueNumber,
}).Debugf("Issue not found")
p.writeJSON(w, nil)
return
}

c.Log.WithError(err).With(logger.LogContext{
"owner": owner,
"repo": repo,
"number": issueNumber,
"owner": req.RepoOwner,
"repo": req.RepoName,
"number": req.IssueNumber,
}).Debugf("Could not get the issue")
p.writeAPIError(w, &serializer.APIErrorResponse{Message: "Could not get the issue", StatusCode: http.StatusInternalServerError})
return
Expand Down Expand Up @@ -1084,13 +1080,13 @@ func (p *Plugin) openIssueEditModal(c *serializer.UserContext, w http.ResponseWr
}

userID := r.Header.Get(constants.HeaderMattermostUserID)
post, appErr := p.API.GetPost(postID)
post, appErr := p.API.GetPost(req.PostID)
if appErr != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s", postID), StatusCode: http.StatusInternalServerError})
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s", req.PostID), StatusCode: http.StatusInternalServerError})
return
}
if post == nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", postID), StatusCode: http.StatusNotFound})
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: fmt.Sprintf("failed to load the post %s : not found", req.PostID), StatusCode: http.StatusNotFound})
return
}

Expand All @@ -1099,13 +1095,13 @@ func (p *Plugin) openIssueEditModal(c *serializer.UserContext, w http.ResponseWr
map[string]interface{}{
"title": *issue.Title,
"channel_id": post.ChannelId,
"postId": postID,
"postId": req.PostID,
"milestone_title": milestoneTitle,
"milestone_number": milestoneNumber,
"assignees": assignees,
"labels": labels,
"description": description,
"repo_full_name": fmt.Sprintf("%s/%s", owner, repo),
"repo_full_name": fmt.Sprintf("%s/%s", req.RepoOwner, req.RepoName),
"issue_number": *issue.Number,
},
&model.WebsocketBroadcast{UserId: userID},
Expand Down Expand Up @@ -1445,11 +1441,6 @@ func (p *Plugin) closeOrReopenIssue(c *serializer.UserContext, w http.ResponseWr
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: "Please provide a valid JSON object.", StatusCode: http.StatusBadRequest})
return
}
issueNumber, err := strconv.Atoi(req.Number)
if err != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{Message: "Invalid param 'number'.", StatusCode: http.StatusBadRequest})
return
}

post, appErr := p.API.GetPost(req.PostID)
if appErr != nil {
Expand All @@ -1461,18 +1452,18 @@ func (p *Plugin) closeOrReopenIssue(c *serializer.UserContext, w http.ResponseWr
return
}

if _, err = p.getUsername(post.UserId); err != nil {
if _, err := p.getUsername(post.UserId); err != nil {
p.writeAPIError(w, &serializer.APIErrorResponse{ID: "", Message: "failed to get username", StatusCode: http.StatusInternalServerError})
return
}
if req.IssueComment != "" {
p.CreateCommentToIssue(c, w, req.IssueComment, req.Owner, req.Repository, post, issueNumber)
p.CreateCommentToIssue(c, w, req.IssueComment, req.Owner, req.Repository, post, req.Number)
}

if req.Status == constants.Close {
p.CloseOrReopenIssue(c, w, constants.IssueClose, req.StatusReason, req.Owner, req.Repository, post, issueNumber)
p.CloseOrReopenIssue(c, w, constants.IssueClose, req.StatusReason, req.Owner, req.Repository, post, req.Number)
} else {
p.CloseOrReopenIssue(c, w, constants.IssueOpen, req.StatusReason, req.Owner, req.Repository, post, issueNumber)
p.CloseOrReopenIssue(c, w, constants.IssueOpen, req.StatusReason, req.Owner, req.Repository, post, req.Number)
}
}

Expand Down
10 changes: 9 additions & 1 deletion server/serializer/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,17 @@ type CommentAndCloseRequest struct {
ChannelID string `json:"channel_id"`
IssueComment string `json:"issue_comment"`
StatusReason string `json:"status_reason"`
Number string `json:"number"`
Number int `json:"number"`
Owner string `json:"owner"`
Repository string `json:"repo"`
Status string `json:"status"`
PostID string `json:"postId"`
}

type OpenCreateCommentOrEditIssueModal struct {
Nityanand13 marked this conversation as resolved.
Show resolved Hide resolved
RepoOwner string `json:"repo_owner"`
RepoName string `json:"repo_name"`
IssueNumber int `json:"issue_number"`
PostID string `json:"postId"`
Status string `json:"status"`
}
25 changes: 17 additions & 8 deletions webapp/src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,11 @@ export function getMilestoneOptions(repo) {
};
}

export function attachCommentIssueModal(owner, repo, issueNumber, postId) {
export function attachCommentIssueModal(payload) {
return async (dispatch, getState) => {
let data;
try {
data = await Client.attachCommentIssueModal(owner, repo, issueNumber, postId);
data = await Client.attachCommentIssueModal(payload);
} catch (error) {
return {error};
}
Expand All @@ -229,11 +229,11 @@ export function attachCommentIssueModal(owner, repo, issueNumber, postId) {
};
}

export function editIssueModal(owner, repo, issueNumber, postId) {
export function editIssueModal(payload) {
return async (dispatch, getState) => {
let data;
try {
data = await Client.editIssueModal(owner, repo, issueNumber, postId);
data = await Client.editIssueModal(payload);
} catch (error) {
return {error};
}
Expand All @@ -247,11 +247,11 @@ export function editIssueModal(owner, repo, issueNumber, postId) {
};
}

export function closeOrReopenIssueModal(owner, repo, issueNumber, status, postId) {
export function closeOrReopenIssueModal(payload) {
return async (dispatch, getState) => {
let data;
try {
data = await Client.closeOrReopenIssueModal(owner, repo, issueNumber, status, postId);
data = await Client.closeOrReopenIssueModal(payload);
} catch (error) {
return {error};
}
Expand Down Expand Up @@ -420,6 +420,15 @@ export function openCloseOrReopenIssueModal(messageData) {
};
}

export function openCreateCommentIssueModal(messageData) {
Nityanand13 marked this conversation as resolved.
Show resolved Hide resolved
return {
type: ActionTypes.OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL,
data: {
messageData,
},
};
}

export function closeCreateOrUpdateIssueModal() {
return {
type: ActionTypes.CLOSE_CREATE_OR_UPDATE_ISSUE_MODAL,
Expand Down Expand Up @@ -486,11 +495,11 @@ export function updateIssue(payload) {
};
}

export function openAttachCommentToIssueModal(messageData) {
export function openAttachCommentToIssueModal(postId) {
return {
type: ActionTypes.OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL,
data: {
messageData,
postId,
},
};
}
Expand Down
12 changes: 6 additions & 6 deletions webapp/src/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import {ClientError} from 'mattermost-redux/client/client4';
import {id as pluginId} from '../manifest';

export default class Client {
editIssueModal = async (owner, repo, issueNumber, postId) => {
return this.doPost(`${this.url}/editissuemodal?owner=${owner}&repo=${repo}&number=${issueNumber}&postId=${postId}`);
editIssueModal = async (payload) => {
return this.doPost(`${this.url}/editissuemodal`, payload);
}

closeOrReopenIssueModal = async (owner, repo, issueNumber, status, postId) => {
return this.doPost(`${this.url}/closereopenissuemodal?owner=${owner}&repo=${repo}&number=${issueNumber}&status=${status}&postId=${postId}`);
closeOrReopenIssueModal = async (payload) => {
return this.doPost(`${this.url}/closereopenissuemodal`, payload);
}

attachCommentIssueModal = async (owner, repo, issueNumber, postId) => {
return this.doPost(`${this.url}/attachcommentissuemodal?owner=${owner}&repo=${repo}&number=${issueNumber}&postId=${postId}`);
attachCommentIssueModal = async (payload) => {
return this.doPost(`${this.url}/attachcommentissuemodal`, payload);
}

setServerRoute(url) {
Expand Down
Loading