Skip to content

Commit

Permalink
[gateway] Add new preset attributes and add new endpoint to approve r…
Browse files Browse the repository at this point in the history
…eview (#615)

Add preset attributes session.script and session.webapp_link
Refactor issue_type_name to request_type_id
Add endpoint to update a review by the session id
Update openapi docs
  • Loading branch information
sandromello authored Dec 20, 2024
1 parent 7c5de6d commit 2ae5319
Show file tree
Hide file tree
Showing 18 changed files with 223 additions and 171 deletions.
12 changes: 6 additions & 6 deletions gateway/api/integrations/issuetemplates.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func ListIssueTemplates(c *gin.Context) {
Name: issue.Name,
Description: issue.Description,
ProjectKey: issue.ProjectKey,
IssueTypeName: issue.IssueTypeName,
RequestTypeID: issue.RequestTypeID,
MappingTypes: issue.MappingTypes,
PromptTypes: issue.PromptTypes,
CmdbTypes: issue.CmdbTypes,
Expand Down Expand Up @@ -78,7 +78,7 @@ func GetIssueTemplatesByID(c *gin.Context) {
Name: issue.Name,
Description: issue.Description,
ProjectKey: issue.ProjectKey,
IssueTypeName: issue.IssueTypeName,
RequestTypeID: issue.RequestTypeID,
MappingTypes: issue.MappingTypes,
PromptTypes: issue.PromptTypes,
CmdbTypes: cmdbTypes,
Expand Down Expand Up @@ -115,7 +115,7 @@ func CreateIssueTemplates(c *gin.Context) {
Name: req.Name,
Description: req.Description,
ProjectKey: req.ProjectKey,
IssueTypeName: req.IssueTypeName,
RequestTypeID: req.RequestTypeID,
MappingTypes: req.MappingTypes,
PromptTypes: req.PromptTypes,
CmdbTypes: req.CmdbTypes,
Expand All @@ -134,7 +134,7 @@ func CreateIssueTemplates(c *gin.Context) {
Name: issue.Name,
Description: issue.Description,
ProjectKey: issue.ProjectKey,
IssueTypeName: issue.IssueTypeName,
RequestTypeID: issue.RequestTypeID,
MappingTypes: issue.MappingTypes,
PromptTypes: issue.PromptTypes,
CmdbTypes: req.CmdbTypes,
Expand Down Expand Up @@ -172,7 +172,7 @@ func UpdateIssueTemplates(c *gin.Context) {
Name: req.Name,
Description: req.Description,
ProjectKey: req.ProjectKey,
IssueTypeName: req.IssueTypeName,
RequestTypeID: req.RequestTypeID,
MappingTypes: req.MappingTypes,
PromptTypes: req.PromptTypes,
CmdbTypes: req.CmdbTypes,
Expand All @@ -189,7 +189,7 @@ func UpdateIssueTemplates(c *gin.Context) {
Name: issue.Name,
Description: issue.Description,
ProjectKey: issue.ProjectKey,
IssueTypeName: issue.IssueTypeName,
RequestTypeID: issue.RequestTypeID,
MappingTypes: issue.MappingTypes,
PromptTypes: issue.PromptTypes,
CmdbTypes: issue.CmdbTypes,
Expand Down
74 changes: 66 additions & 8 deletions gateway/api/openapi/autogen/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2753,6 +2753,59 @@ const docTemplate = `{
}
}
},
"/sessions/{session_id}/review": {
"put": {
"description": "Update the status of a review resource by the session id",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Core"
],
"summary": "Update Review Status By Sid",
"parameters": [
{
"type": "string",
"description": "Resource identifier of the session",
"name": "session_id",
"in": "path",
"required": true
},
{
"description": "The request body resource",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/openapi.ReviewRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/openapi.Review"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/openapi.HTTPError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/openapi.HTTPError"
}
}
}
}
},
"/signup": {
"post": {
"description": "Signup anonymous authenticated user. This endpoint is only used for multi tenant setups.",
Expand Down Expand Up @@ -3866,10 +3919,6 @@ const docTemplate = `{
"description": "The unique identifier of the integration",
"type": "string"
},
"issue_type_name": {
"description": "The issue type name (request type) that will be associated to the issue",
"type": "string"
},
"mapping_types": {
"type": "object",
"additionalProperties": {}
Expand All @@ -3886,6 +3935,10 @@ const docTemplate = `{
"type": "object",
"additionalProperties": {}
},
"request_type_id": {
"description": "The request type id that will be associated to the issue",
"type": "string"
},
"updated_at": {
"description": "The time when the template was updated",
"type": "string"
Expand All @@ -3894,6 +3947,11 @@ const docTemplate = `{
},
"openapi.JiraIssueTemplateRequest": {
"type": "object",
"required": [
"name",
"project_key",
"request_type_id"
],
"properties": {
"cmdb_types": {
"description": "Cmdb Types are custom fields integrated with the Jira Assets API\n\n\t\t{\n\t\t \"items\": [\n\t\t {\n\t\t \"description\": \"Service Field\",\n\t\t \"jira_field\": \"customfield_10110\",\n\t\t \"jira_object_type\": \"Service\",\n\t\t \"required\": true,\n\t\t \"value\": \"mydb-prod\"\n\t\t }\n\t\t ]\n\t\t}",
Expand All @@ -3904,10 +3962,6 @@ const docTemplate = `{
"description": "The description of the template",
"type": "string"
},
"issue_type_name": {
"description": "The issue type name (request type) that will be associated to the issue",
"type": "string"
},
"mapping_types": {
"description": "The automated fields that will be sent when creating the issue.\nThere're two types\n- preset: obtain the value from a list of available fields that could be propagated\nThe list of available preset values are:\n\n\t\t- session.id\n\t\t- session.user_email\n\t\t- session.user_id\n\t\t- session.user_name\n\t\t- session.type\n\t\t- session.connection\n\t\t- session.status\n\t\t- session.verb\n\t\t- session.start_date\n\n- custom: use a custom static value\n\n\t\t{\n\t\t \"items\": [\n\t\t {\n\t\t \"description\": \"Hoop Connection Name\",\n\t\t \"jira_field\": \"customfield_10050\",\n\t\t \"type\": \"preset\",\n\t\t \"value\": \"session.connection\"\n\t\t }\n\t\t ]\n\t\t}",
"type": "object",
Expand All @@ -3925,6 +3979,10 @@ const docTemplate = `{
"description": "The prompt fields that will be show to user before executing a session\n\n\t\t{\n\t\t \"items\": [\n\t\t {\n\t\t \"description\": \"Squad Name\",\n\t\t \"jira_field\": \"customfield_10052\",\n\t\t \"label\": \"Squad Name\",\n\t\t \"required\": true\n\t\t }\n\t\t ]\n\t\t}",
"type": "object",
"additionalProperties": {}
},
"request_type_id": {
"description": "The request type that will be associated to the issue",
"type": "string"
}
}
},
Expand Down
12 changes: 6 additions & 6 deletions gateway/api/openapi/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -837,8 +837,8 @@ type JiraIssueTemplate struct {
Description string `json:"description"`
// The project key which is the shortand version of the project's name
ProjectKey string `json:"project_key"`
// The issue type name (request type) that will be associated to the issue
IssueTypeName string `json:"issue_type_name"`
// The request type id that will be associated to the issue
RequestTypeID string `json:"request_type_id"`
MappingTypes map[string]any `json:"mapping_types"`
PromptTypes map[string]any `json:"prompt_types"`
CmdbTypes map[string]any `json:"cmdb_types"`
Expand All @@ -850,13 +850,13 @@ type JiraIssueTemplate struct {

type JiraIssueTemplateRequest struct {
// The name of the template
Name string `json:"name"`
Name string `json:"name" binding:"required"`
// The description of the template
Description string `json:"description"`
// The project key which is the shortand version of the project's name
ProjectKey string `json:"project_key"`
// The issue type name (request type) that will be associated to the issue
IssueTypeName string `json:"issue_type_name"`
ProjectKey string `json:"project_key" binding:"required"`
// The request type that will be associated to the issue
RequestTypeID string `json:"request_type_id" binding:"required"`
// The automated fields that will be sent when creating the issue.
// There're two types
// - preset: obtain the value from a list of available fields that could be propagated
Expand Down
14 changes: 14 additions & 0 deletions gateway/api/review/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,17 @@ func (h *handler) List(c *gin.Context) { h.legacy.FindAll(c) }
// @Failure 404,500 {object} openapi.HTTPError
// @Router /reviews/{id} [put]
func (h *handler) Put(c *gin.Context) { h.legacy.Put(c) }

// UpdateReviewBySid
//
// @Summary Update Review Status By Sid
// @Description Update the status of a review resource by the session id
// @Tags Core
// @Param session_id path string true "Resource identifier of the session"
// @Accept json
// @Produce json
// @Param request body openapi.ReviewRequest true "The request body resource"
// @Success 200 {object} openapi.Review
// @Failure 404,500 {object} openapi.HTTPError
// @Router /sessions/{session_id}/review [put]
func (h *handler) ReviewBySession(c *gin.Context) { h.legacy.Put(c) }
3 changes: 3 additions & 0 deletions gateway/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ func (api *Api) buildRoutes(r *apiroutes.Router) {
r.AuthMiddleware,
sessionapi.Get)
r.GET("/sessions/:session_id/download", sessionapi.DownloadSession)
r.PUT("/sessions/:session_id/review",
r.AuthMiddleware,
reviewHandler.ReviewBySession)
r.GET("/sessions",
apiroutes.ReadOnlyAccessRole,
r.AuthMiddleware,
Expand Down
1 change: 0 additions & 1 deletion gateway/api/session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ func Post(c *gin.Context) {
return
}
resp, err := jira.CreateCustomerRequest(issueTemplate, jiraConfig, jiraFields)
// resp, err := jira.CreateIssue(issueTemplate, jiraConfig, jiraFields)
if err != nil {
log.Error(err)
c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()})
Expand Down
32 changes: 0 additions & 32 deletions gateway/jira/assetstypes.go

This file was deleted.

64 changes: 22 additions & 42 deletions gateway/jira/issuesapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"io"
"net/http"
"strings"
"time"

"github.com/hoophq/hoop/common/log"
"github.com/hoophq/hoop/gateway/appconfig"
"github.com/hoophq/hoop/gateway/models"
"github.com/hoophq/hoop/gateway/storagev2/types"
)
Expand All @@ -23,7 +25,6 @@ func (e *ErrInvalidIssueFields) Error() string {
return fmt.Sprintf("unable to parse fields, missing required fields: %v", e.resources)
}
return fmt.Sprintf("unable to parse fields, invalid preset mapping types values: %v", e.resources)

}

func TransitionIssue(config *models.JiraIntegration, issueKey, name string) error {
Expand Down Expand Up @@ -101,47 +102,6 @@ func listIssueTransitions(config *models.JiraIntegration, issueKey string) (*Iss
return &obj, nil
}

func CreateIssue(issueTemplate *models.JiraIssueTemplate, config *models.JiraIntegration, customFields CustomFields) (*IssueResponse, error) {
if customFields == nil {
return nil, fmt.Errorf("custom fields map is empty")
}

issueFields := IssueFields[CustomFields]{
Project: Project{Key: issueTemplate.ProjectKey},
Summary: "Hoop Session",
Issuetype: Issuetype{Name: issueTemplate.IssueTypeName},
CustomFields: customFields,
}
issuePayload, err := json.Marshal(map[string]any{"fields": issueFields})
if err != nil {
return nil, fmt.Errorf("failed encoding issue payload, reason=%v", err)
}
log.Infof("creating jira issue with issue fields payload: %v", string(issuePayload))
apiURL := fmt.Sprintf("%s/rest/api/3/issue", config.URL)
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(issuePayload))
if err != nil {
return nil, fmt.Errorf("failed creating request, reason=%v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.SetBasicAuth(config.User, config.APIToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed creating jira issue, reason=%v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 201 {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("unable to create jira issue, status=%v, body=%v",
resp.StatusCode, string(body))
}
var response IssueResponse
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed decoding jira issue response, reason=%v", err)
}
return &response, nil
}

func ParseIssueFields(tmpl *models.JiraIssueTemplate, input map[string]string, session types.Session) (CustomFields, error) {
if input == nil {
input = map[string]string{}
Expand Down Expand Up @@ -206,3 +166,23 @@ func ParseIssueFields(tmpl *models.JiraIssueTemplate, input map[string]string, s

return output, nil
}

func loadDefaultPresetFields(s types.Session) map[string]string {
script := s.Script["data"]
if len(s.Script) > 5000 {
script = script[0:5000] + fmt.Sprintf(" ...[TRUNCATED %v]", len(script[5000:]))
}
return map[string]string{
"session.id": s.ID,
"session.user_email": s.UserEmail,
"session.user_id": s.UserID,
"session.user_name": s.UserName,
"session.type": s.Type,
// "session.subtype": "",
"session.connection": s.Connection,
"session.status": s.Status,
"session.script": "{code:shell}" + script + "{code}",
"session.start_date": s.StartSession.Format(time.RFC3339),
"session.webapp_link": appconfig.Get().ApiURL() + "/sessions/" + s.ID,
}
}
9 changes: 2 additions & 7 deletions gateway/jira/requestsapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"io"
"net/http"
"os"

"github.com/hoophq/hoop/common/log"
"github.com/hoophq/hoop/gateway/models"
Expand All @@ -21,9 +20,9 @@ func CreateCustomerRequest(tmpl *models.JiraIssueTemplate, config *models.JiraIn
if _, hasSummary := fields["summary"]; !hasSummary {
fields["summary"] = "Hoop Session"
}
issue := IssueFieldsV2[CustomFields]{
issue := IssueFields[CustomFields]{
ServiceDeskID: serviceDeskID,
RequestTypeID: tmpl.IssueTypeName,
RequestTypeID: tmpl.RequestTypeID,
IsAdfRequest: false,
IssueFieldValues: IssueFieldValues[CustomFields]{fields},
}
Expand Down Expand Up @@ -58,10 +57,6 @@ func CreateCustomerRequest(tmpl *models.JiraIssueTemplate, config *models.JiraIn
}

func fetchServiceDeskID(config *models.JiraIntegration, projectKey string) (string, error) {
// temporary to avoid having to paginate
if val := os.Getenv("JIRA_SERVICE_DESK_ID"); val != "" {
return val, nil
}
apiURL := fmt.Sprintf("%s/rest/servicedeskapi/servicedesk?limit=100", config.URL)
req, err := http.NewRequest("GET", apiURL, nil)
if err != nil {
Expand Down
Loading

0 comments on commit 2ae5319

Please sign in to comment.