diff --git a/admin/handlers/post.go b/admin/handlers/post.go index f89559f9..b8aa8e7d 100644 --- a/admin/handlers/post.go +++ b/admin/handlers/post.go @@ -1440,56 +1440,60 @@ func (h *HandlersAdmin) TagsPOSTHandler(w http.ResponseWriter, r *http.Request) return } switch t.Action { - case "add": - // FIXME password complexity? - if h.Tags.Exists(t.Name) { + case tags.ActionAdd: + if h.Tags.ExistsByEnv(t.Name, env.ID) { adminErrorResponse(w, "error adding tag", http.StatusInternalServerError, fmt.Errorf("tag %s already exists", t.Name)) h.Inc(metricAdminErr) return } - // Prepare user to create if err := h.Tags.NewTag(t.Name, t.Description, t.Color, t.Icon, ctx[sessions.CtxUser], env.ID, false, t.TagType); err != nil { adminErrorResponse(w, "error with new tag", http.StatusInternalServerError, err) h.Inc(metricAdminErr) return } adminOKResponse(w, "tag added successfully") - case "edit": - if t.Description != "" { - if err := h.Tags.ChangeDescription(t.Name, t.Description, env.ID); err != nil { + case tags.ActionEdit: + tag, err := h.Tags.Get(t.Name, env.ID) + if err != nil { + adminErrorResponse(w, "error getting tag", http.StatusInternalServerError, err) + h.Inc(metricAdminErr) + return + } + if t.Description != "" && t.Description != tag.Description { + if err := h.Tags.ChangeDescription(&tag, t.Description); err != nil { adminErrorResponse(w, "error changing description", http.StatusInternalServerError, err) h.Inc(metricAdminErr) return } } - if t.Icon != "" { - if err := h.Tags.ChangeIcon(t.Name, t.Icon, env.ID); err != nil { + if t.Icon != "" && t.Icon != tag.Icon { + if err := h.Tags.ChangeIcon(&tag, t.Icon); err != nil { adminErrorResponse(w, "error changing icon", http.StatusInternalServerError, err) h.Inc(metricAdminErr) return } } - if t.Color != "" { - if err := h.Tags.ChangeColor(t.Name, t.Color, env.ID); err != nil { + if t.Color != "" && t.Color != tag.Color { + if err := h.Tags.ChangeColor(&tag, t.Color); err != nil { adminErrorResponse(w, "error changing color", http.StatusInternalServerError, err) h.Inc(metricAdminErr) return } } - adminOKResponse(w, "tag updated successfully") - case "remove": - if t.Name == ctx[sessions.CtxUser] { - adminErrorResponse(w, "not a good idea", http.StatusInternalServerError, fmt.Errorf("attempt to remove tag %s", t.Name)) - h.Inc(metricAdminErr) - return - } - if h.Tags.Exists(t.Name) { - if err := h.Tags.Delete(t.Name, env.ID); err != nil { - adminErrorResponse(w, "error removing tag", http.StatusInternalServerError, err) + if t.TagType != tag.TagType { + if err := h.Tags.ChangeTagType(&tag, t.TagType); err != nil { + adminErrorResponse(w, "error changing tag type", http.StatusInternalServerError, err) h.Inc(metricAdminErr) return } } + adminOKResponse(w, "tag updated successfully") + case tags.ActionRemove: + if err := h.Tags.DeleteGet(t.Name, env.ID); err != nil { + adminErrorResponse(w, "error removing tag", http.StatusInternalServerError, err) + h.Inc(metricAdminErr) + return + } adminOKResponse(w, "tag removed successfully") } // Serialize and send response diff --git a/api/handlers/tags.go b/api/handlers/tags.go index ab84902f..6a9e0932 100644 --- a/api/handlers/tags.go +++ b/api/handlers/tags.go @@ -1,16 +1,19 @@ package handlers import ( + "encoding/json" "fmt" "net/http" "github.com/jmpsec/osctrl/settings" + "github.com/jmpsec/osctrl/tags" + "github.com/jmpsec/osctrl/types" "github.com/jmpsec/osctrl/users" "github.com/jmpsec/osctrl/utils" "github.com/rs/zerolog/log" ) -// TagsHandler - GET Handler for multiple JSON tags +// AllTagsHandler - GET Handler for all JSON tags func (h *HandlersApi) AllTagsHandler(w http.ResponseWriter, r *http.Request) { h.Inc(metricAPITagsReq) utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAPI, settings.NoEnvironmentID), false) @@ -47,7 +50,7 @@ func (h *HandlersApi) TagsEnvHandler(w http.ResponseWriter, r *http.Request) { h.Inc(metricAPIEnvsErr) return } - // Get environment by name + // Get environment by UUID env, err := h.Envs.GetByUUID(envVar) if err != nil { if err.Error() == "record not found" { @@ -79,3 +82,112 @@ func (h *HandlersApi) TagsEnvHandler(w http.ResponseWriter, r *http.Request) { utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, tags) h.Inc(metricAPITagsOK) } + +// TagsActionHandler - POST Handler to create, update or delete tags +func (h *HandlersApi) TagsActionHandler(w http.ResponseWriter, r *http.Request) { + h.Inc(metricAPITagsReq) + utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAPI, settings.NoEnvironmentID), false) + // Extract environment + envVar := r.PathValue("env") + if envVar == "" { + apiErrorResponse(w, "error getting environment", http.StatusBadRequest, nil) + h.Inc(metricAPIEnvsErr) + return + } + // Get environment by UUID + env, err := h.Envs.GetByUUID(envVar) + if err != nil { + if err.Error() == "record not found" { + apiErrorResponse(w, "environment not found", http.StatusNotFound, err) + } else { + apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, err) + } + h.Inc(metricAPIEnvsErr) + return + } + // Get context data and check access + ctx := r.Context().Value(ContextKey(contextAPI)).(ContextValue) + if !h.Users.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) { + apiErrorResponse(w, "no access", http.StatusForbidden, fmt.Errorf("attempt to use API by user %s", ctx[ctxUser])) + h.Inc(metricAPITagsErr) + return + } + // Extract action + actionVar := r.PathValue("action") + if actionVar == "" { + apiErrorResponse(w, "error getting action", http.StatusBadRequest, nil) + h.Inc(metricAPIEnvsErr) + return + } + var t types.ApiTagsRequest + // Parse request JSON body + if err := json.NewDecoder(r.Body).Decode(&t); err != nil { + apiErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + var returnData string + switch actionVar { + case tags.ActionAdd: + if h.Tags.ExistsByEnv(t.Name, env.ID) { + apiErrorResponse(w, "error adding tag", http.StatusInternalServerError, fmt.Errorf("tag %s already exists", t.Name)) + h.Inc(metricAPITagsErr) + return + } + if err := h.Tags.NewTag(t.Name, t.Description, t.Color, t.Icon, ctx[ctxUser], env.ID, false, t.TagType); err != nil { + apiErrorResponse(w, "error with new tag", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + returnData = "tag added successfully" + case tags.ActionEdit: + tag, err := h.Tags.Get(t.Name, env.ID) + if err != nil { + apiErrorResponse(w, "error getting tag", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + if t.Description != "" && t.Description != tag.Description { + if err := h.Tags.ChangeDescription(&tag, t.Description); err != nil { + apiErrorResponse(w, "error changing description", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + } + if t.Color != "" && t.Color != tag.Color { + if err := h.Tags.ChangeColor(&tag, t.Color); err != nil { + apiErrorResponse(w, "error changing color", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + } + if t.Icon != "" && t.Icon != tag.Icon { + if err := h.Tags.ChangeIcon(&tag, t.Icon); err != nil { + apiErrorResponse(w, "error changing icon", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + } + if t.TagType != tag.TagType { + if err := h.Tags.ChangeTagType(&tag, t.TagType); err != nil { + apiErrorResponse(w, "error changing tag type", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + } + returnData = "tag updated successfully" + case tags.ActionRemove: + if err := h.Tags.DeleteGet(t.Name, env.ID); err != nil { + apiErrorResponse(w, "error removing tag", http.StatusInternalServerError, err) + h.Inc(metricAPITagsErr) + return + } + returnData = "tag removed successfully" + } + // Serialize and serve JSON + if h.Settings.DebugService(settings.ServiceAPI) { + log.Debug().Msgf("DebugService: Returned %s", returnData) + } + utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, types.ApiDataResponse{Data: returnData}) + h.Inc(metricAPITagsOK) +} diff --git a/api/main.go b/api/main.go index 74796b2a..b8ee408f 100644 --- a/api/main.go +++ b/api/main.go @@ -604,6 +604,7 @@ func osctrlAPIService() { // API: tags by environment muxAPI.Handle("GET "+_apiPath(apiTagsPath), handlerAuthCheck(http.HandlerFunc(handlersApi.AllTagsHandler))) muxAPI.Handle("GET "+_apiPath(apiTagsPath)+"/{env}", handlerAuthCheck(http.HandlerFunc(handlersApi.TagsEnvHandler))) + muxAPI.Handle("POST "+_apiPath(apiTagsPath)+"/{env}/{action}", handlerAuthCheck(http.HandlerFunc(handlersApi.TagsActionHandler))) // API: settings by environment muxAPI.Handle("GET "+_apiPath(apiSettingsPath), handlerAuthCheck(http.HandlerFunc(handlersApi.SettingsHandler))) muxAPI.Handle("GET "+_apiPath(apiSettingsPath)+"/{service}", handlerAuthCheck(http.HandlerFunc(handlersApi.SettingsServiceHandler))) diff --git a/osctrl-api.yaml b/osctrl-api.yaml index ad473695..c9d6ca65 100644 --- a/osctrl-api.yaml +++ b/osctrl-api.yaml @@ -1559,6 +1559,67 @@ paths: security: - Authorization: - admin + /tags/{env}/{action}: + post: + tags: + - tags + summary: Get tags + description: Perform tag related actions in tags by environment + operationId: TagsActionHandler + parameters: + - name: env + in: path + description: Name or UUID of the requested osctrl environment to get platforms + required: true + schema: + type: string + - name: action + in: path + description: Action to execute (add, edit, remove) + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ApiTagsRequest" + responses: + 200: + description: successful operation + content: + application/json: + schema: + type: array + items: + type: string + 400: + description: bad request + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorResponse" + 403: + description: no access + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorResponse" + 404: + description: no tags + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorResponse" + 500: + description: error getting tags + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorResponse" + security: + - Authorization: + - admin /settings: get: tags: @@ -1938,11 +1999,6 @@ components: properties: query_name: type: string - ApiErrorResponse: - type: object - properties: - error: - type: string APIQueryData: type: object CarvedFile: @@ -2220,6 +2276,22 @@ components: type: string DebPkgURL: type: string + ApiTagsRequest: + type: object + properties: + Name: + type: string + Description: + type: string + Color: + type: string + Icon: + type: string + EnvUUID: + type: string + TagType: + type: integer + format: uint32 securitySchemes: Authorization: type: http diff --git a/tags/tags.go b/tags/tags.go index 396af6a2..947106d2 100644 --- a/tags/tags.go +++ b/tags/tags.go @@ -26,6 +26,12 @@ const ( TagTypeLocalname uint = 3 // TagTypeCustom as tag type for custom tags TagTypeCustom uint = 4 + // ActionAdd as action to add a tag + ActionAdd string = "add" + // ActionEdit as action to edit a tag + ActionEdit string = "edit" + // ActionRemove as action to remove a tag + ActionRemove string = "remove" ) // AdminTag to hold all tags @@ -142,6 +148,13 @@ func (m *TagManager) Exists(name string) bool { return (results > 0) } +// ExistsByEnv checks if tag exists by environment +func (m *TagManager) ExistsByEnv(name string, envID uint) bool { + var results int64 + m.DB.Model(&AdminTag{}).Where("name = ? AND environment_id = ?", name, envID).Count(&results) + return (results > 0) +} + // ExistsGet checks if tag exists and returns the tag func (m *TagManager) ExistsGet(name string, envID uint) (bool, AdminTag) { tag, err := m.Get(name, envID) @@ -169,8 +182,8 @@ func (m *TagManager) GetByEnv(envID uint) ([]AdminTag, error) { return tags, nil } -// Delete tag by name -func (m *TagManager) Delete(name string, envID uint) error { +// DeleteGet tag by name +func (m *TagManager) DeleteGet(name string, envID uint) error { tag, err := m.Get(name, envID) if err != nil { return fmt.Errorf("error getting tag %v", err) @@ -181,8 +194,16 @@ func (m *TagManager) Delete(name string, envID uint) error { return nil } -// ChangeDescription to update description for a tag -func (m *TagManager) ChangeDescription(name, description string, envID uint) error { +// Delete tag by name +func (m *TagManager) Delete(tag *AdminTag) error { + if err := m.DB.Unscoped().Delete(tag).Error; err != nil { + return fmt.Errorf("Delete %v", err) + } + return nil +} + +// ChangeGetDescription to update description for a tag +func (m *TagManager) ChangeGetDescription(name, description string, envID uint) error { tag, err := m.Get(name, envID) if err != nil { return fmt.Errorf("error getting tag %v", err) @@ -195,8 +216,18 @@ func (m *TagManager) ChangeDescription(name, description string, envID uint) err return nil } -// ChangeColor to update color for a tag -func (m *TagManager) ChangeColor(name, color string, envID uint) error { +// ChangeDescription to update description for a tag +func (m *TagManager) ChangeDescription(tag *AdminTag, desc string) error { + if desc != tag.Description { + if err := m.DB.Model(tag).Update("description", desc).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + +// ChangeGetColor to update color for a tag +func (m *TagManager) ChangeGetColor(name, color string, envID uint) error { tag, err := m.Get(name, envID) if err != nil { return fmt.Errorf("error getting tag %v", err) @@ -209,8 +240,18 @@ func (m *TagManager) ChangeColor(name, color string, envID uint) error { return nil } -// ChangeIcon to update icon for a tag -func (m *TagManager) ChangeIcon(name, icon string, envID uint) error { +// ChangeColor to update color for a tag +func (m *TagManager) ChangeColor(tag *AdminTag, color string) error { + if color != tag.Color { + if err := m.DB.Model(tag).Update("color", color).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + +// ChangeGetIcon to update icon for a tag +func (m *TagManager) ChangeGetIcon(name, icon string, envID uint) error { tag, err := m.Get(name, envID) if err != nil { return fmt.Errorf("error getting tag %v", err) @@ -223,6 +264,64 @@ func (m *TagManager) ChangeIcon(name, icon string, envID uint) error { return nil } +// ChangeIcon to update icon for a tag +func (m *TagManager) ChangeIcon(tag *AdminTag, icon string) error { + if icon != tag.Icon { + if err := m.DB.Model(tag).Update("icon", icon).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + +// ChangeGetTagType to update tag type for a tag +func (m *TagManager) ChangeGetTagType(name string, tagType uint, envID uint) error { + tag, err := m.Get(name, envID) + if err != nil { + return fmt.Errorf("error getting tag %v", err) + } + if tagType != tag.TagType { + if err := m.DB.Model(&tag).Update("tag_type", tagType).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + +// ChangeTagType to update tag type for a tag +func (m *TagManager) ChangeTagType(tag *AdminTag, tagType uint) error { + if tagType != tag.TagType { + if err := m.DB.Model(tag).Update("tag_type", tagType).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + +// ChangeGetEnvironment to update environment for a tag +func (m *TagManager) ChangeGetEnvironment(name string, envID uint) error { + tag, err := m.Get(name, envID) + if err != nil { + return fmt.Errorf("error getting tag %v", err) + } + if envID != tag.EnvironmentID { + if err := m.DB.Model(&tag).Update("environment_id", envID).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + +// ChangeEnvironment to update environment for a tag +func (m *TagManager) ChangeEnvironment(tag *AdminTag, envID uint) error { + if envID != tag.EnvironmentID { + if err := m.DB.Model(tag).Update("environment_id", envID).Error; err != nil { + return fmt.Errorf("Update %v", err) + } + } + return nil +} + // AutoTagNode to automatically tag a node based on multiple fields func (m *TagManager) AutoTagNode(env string, node nodes.OsqueryNode, user string) error { l := []string{env, node.UUID, node.Platform, node.Localname} diff --git a/types/go.mod b/types/go.mod index dce87077..9cfecacb 100644 --- a/types/go.mod +++ b/types/go.mod @@ -20,7 +20,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/rs/zerolog v1.33.0 // indirect github.com/segmentio/ksuid v1.0.4 // indirect - golang.org/x/sys v0.29.0 // indirect + golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.21.0 // indirect gorm.io/gorm v1.25.12 // indirect ) diff --git a/types/go.sum b/types/go.sum index 9d36f9c3..d4274e54 100644 --- a/types/go.sum +++ b/types/go.sum @@ -8,7 +8,6 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -16,6 +15,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -29,29 +30,13 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= -gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= -gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= +gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/types/types.go b/types/types.go index 3aaabdf5..a6358bcf 100644 --- a/types/types.go +++ b/types/types.go @@ -8,7 +8,6 @@ const ( LogLevelInfo string = "info" LogLevelWarn string = "warn" LogLevelError string = "error" - // log formats LogFormatConsole string = "console" LogFormatJSON string = "json" @@ -195,3 +194,13 @@ type ApiActionsRequest struct { RpmPkgURL string `json:"url_rpm_pkg"` DebPkgURL string `json:"url_deb_pkg"` } + +// ApiTagsRequest to receive tag requests +type ApiTagsRequest struct { + Name string `json:"name"` + Description string `json:"description"` + Color string `json:"color"` + Icon string `json:"icon"` + EnvUUID string `json:"env_uuid"` + TagType uint `json:"tagtype"` +}