Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 65 additions & 0 deletions backend/plugins/webhook/api/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,43 @@ func CloseIssue(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, erro
return closeIssue(input, err, connection)
}

// CloseIssueByBodyRequest is the body for the body-based close endpoint
type CloseIssueByBodyRequest struct {
IssueKey string `mapstructure:"issueKey" validate:"required,max=255"`
ResolutionDate *time.Time `mapstructure:"resolutionDate"`
OriginalStatus string `mapstructure:"originalStatus"`
}

// CloseIssueByBody
// @Summary close an issue (body-based)
// @Description Close an incident by passing issueKey in the request body.
// @Description Use this when the client (e.g. Kibana) cannot construct a dynamic URL.
// @Tags plugins/webhook
// @Param connectionId path int true "connection ID"
// @Param body body CloseIssueByBodyRequest true "close request"
// @Success 200 {string} noResponse ""
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/webhook/connections/{connectionId}/issue/close [POST]
func CloseIssueByBody(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connection := &models.WebhookConnection{}
err := connectionHelper.First(connection, input.Params)
if err != nil {
return nil, err
}
request := &CloseIssueByBodyRequest{}
if err2 := helper.DecodeMapStruct(input.Body, request, true); err2 != nil {
return &plugin.ApiResourceOutput{Body: err2.Error(), Status: http.StatusBadRequest}, nil
}
vld = validator.New()
if err2 := errors.Convert(vld.Struct(request)); err2 != nil {
return &plugin.ApiResourceOutput{Body: err2.Error(), Status: http.StatusBadRequest}, nil
}
// Inject issueKey into input.Params so closeIssue() can read it
input.Params["issueKey"] = request.IssueKey
return closeIssue(input, err, connection)
}

// CloseIssueByName
// @Summary set issue's status to DONE
// @Description set issue's status to DONE
Expand All @@ -247,6 +284,34 @@ func CloseIssueByName(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput
err := connectionHelper.FirstByName(connection, input.Params)
return closeIssue(input, err, connection)
}

// CloseIssueByBodyByName
// @Summary close an issue by connection name (body-based)
// @Description Close an incident using connection name + issueKey in request body.
// @Tags plugins/webhook
// @Param connectionName path string true "connection name"
// @Param body body CloseIssueByBodyRequest true "close request"
// @Success 200 {string} noResponse ""
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/webhook/connections/by-name/{connectionName}/issue/close [POST]
func CloseIssueByBodyByName(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
connection := &models.WebhookConnection{}
err := connectionHelper.FirstByName(connection, input.Params)
if err != nil {
return nil, err
}
request := &CloseIssueByBodyRequest{}
if err2 := helper.DecodeMapStruct(input.Body, request, true); err2 != nil {
return &plugin.ApiResourceOutput{Body: err2.Error(), Status: http.StatusBadRequest}, nil
}
vld = validator.New()
if err2 := errors.Convert(vld.Struct(request)); err2 != nil {
return &plugin.ApiResourceOutput{Body: err2.Error(), Status: http.StatusBadRequest}, nil
}
input.Params["issueKey"] = request.IssueKey
return closeIssue(input, err, connection)
}

func closeIssue(input *plugin.ApiResourceInput, err errors.Error, connection *models.WebhookConnection) (*plugin.ApiResourceOutput, errors.Error) {
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions backend/plugins/webhook/impl/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ func (p Webhook) ApiResources() map[string]map[string]plugin.ApiResourceHandler
"connections/:connectionId/issue/:issueKey/close": {
"POST": api.CloseIssue,
},
"connections/:connectionId/issue/close": {
"POST": api.CloseIssueByBody,
},
":connectionId/deployments": {
"POST": api.PostDeployments,
},
Expand All @@ -111,6 +114,9 @@ func (p Webhook) ApiResources() map[string]map[string]plugin.ApiResourceHandler
":connectionId/issue/:issueKey/close": {
"POST": api.CloseIssue,
},
":connectionId/issue/close": {
"POST": api.CloseIssueByBody,
},
"connections/by-name/:connectionName": {
"GET": api.GetConnectionByName,
"PATCH": api.PatchConnectionByName,
Expand All @@ -128,6 +134,9 @@ func (p Webhook) ApiResources() map[string]map[string]plugin.ApiResourceHandler
"connections/by-name/:connectionName/issue/:issueKey/close": {
"POST": api.CloseIssueByName,
},
"connections/by-name/:connectionName/issue/close": {
"POST": api.CloseIssueByBodyByName,
},
"projects/:projectName/deployments": {
"POST": api.PostDeploymentsByProjectName,
},
Expand Down