This is an automated email from the ASF dual-hosted git repository.
rshah pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new 8a08e3b187 To types rfc format (#7575)
8a08e3b187 is described below
commit 8a08e3b187de43bd78188feda005dc75a445fd6d
Author: Kannan.G.B <[email protected]>
AuthorDate: Thu Jul 6 23:20:32 2023 +0530
To types rfc format (#7575)
* types rfc time changes
* types rfc time changes fixes
* type get api scan order fix
* types golang rfc changes
types golang rfc changes
* DOC UPDATED FOR TYPE
* removed unwanted code
* test case fix
error in test case fixed
* revert code
* revert old change
* align correction
* Delete admin
* comments addresed
* typo changes
* comment addressing
* comment changes
* comments addressed
* removed unused TypeNullableV5
* comments corrected as per fnc name
* test case fail fix
* correct method used
* type reference correction
* changelog fixed
---
CHANGELOG.md | 1 +
docs/source/api/v5/types.rst | 8 +-
docs/source/api/v5/types_id.rst | 2 +-
lib/go-tc/types.go | 23 ++
traffic_ops/testing/api/v5/traffic_control_test.go | 2 +-
traffic_ops/testing/api/v5/types_test.go | 16 +-
traffic_ops/traffic_ops_golang/routing/routes.go | 8 +-
traffic_ops/traffic_ops_golang/types/types.go | 238 +++++++++++++++++++++
traffic_ops/v5-client/type.go | 8 +-
9 files changed, 284 insertions(+), 22 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 98871c886a..7c44cfab32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -126,6 +126,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- [#7471](https://github.com/apache/trafficcontrol/pull/7471) *Traffic Control
Cache Config (t3c)* Fixed issue with MSO non topo origins from multiple cache
groups.
- [#4393](https://github.com/apache/trafficcontrol/issues/4393) *Traffic Ops*
Fixed the error code and alert structure when TO is queried for a delivery
service with no ssl keys.
- [#7590](https://github.com/apache/trafficcontrol/issues/7590) *Traffic
Control Cache Config (t3c)* Fixed issue with git detected dubious ownership in
repository.
+- [#7575](https://github.com/apache/trafficcontrol/pull/7575) *Traffic Ops*
Fixes `types` v5 apis to respond with `RFC3339` date/time Format.
### Removed
- [#7271](https://github.com/apache/trafficcontrol/pull/7271) Remove
components in `infrastructre/docker/`, not in use as cdn-in-a-box performs the
same functionality.
diff --git a/docs/source/api/v5/types.rst b/docs/source/api/v5/types.rst
index d45201d789..d00066ce4a 100644
--- a/docs/source/api/v5/types.rst
+++ b/docs/source/api/v5/types.rst
@@ -55,7 +55,7 @@ Response Structure
------------------
:description: A short description of this type
:id: An integral, unique identifier for this type
-:lastUpdated: The date and time at which this type was last updated, in
:ref:`non-rfc-datetime`
+:lastUpdated: The date and time at which this type was last updated, in
:rfc:`3339`
:name: The name of this type
:useInTable: The name of the Traffic Ops database table that contains objects
which are grouped, identified, or described by this type
@@ -77,7 +77,7 @@ Response Structure
{ "response": [
{
"id": 48,
- "lastUpdated": "2018-12-12 16:26:41+00",
+ "lastUpdated": "2018-12-12T10:59:07.962423+05:30",
"name": "TC_LOC",
"description": "Location for Traffic Control Component
Servers",
"useInTable": "cachegroup"
@@ -124,7 +124,7 @@ Response Structure
:description: A short description of this type
:id: An integral, unique identifier for this type
-:lastUpdated: The date and time at which this type was last updated, in
:ref:`non-rfc-datetime`
+:lastUpdated: The date and time at which this type was last updated, in
:rfc:`3339`
:name: The name of this type
:useInTable: The name of the Traffic Ops database table that contains objects
which are grouped, identified, or described by this type
@@ -152,7 +152,7 @@ Response Structure
"response": [
{
"id": 3004,
- "lastUpdated": "2020-02-26 18:58:41+00",
+ "lastUpdated": "2020-02-26T10:59:07.962423+05:30",
"name": "Example01",
"description": "Example"
"useInTable": "server"
diff --git a/docs/source/api/v5/types_id.rst b/docs/source/api/v5/types_id.rst
index 598476d81c..1581080533 100644
--- a/docs/source/api/v5/types_id.rst
+++ b/docs/source/api/v5/types_id.rst
@@ -93,7 +93,7 @@ Response Structure
"response": [
{
"id": 3004,
- "lastUpdated": "2020-02-26 18:58:41+00",
+ "lastUpdated": "2020-02-26T10:59:07.962423+05:30",
"name": "Example02",
"description": "Example"
"useInTable": "server"
diff --git a/lib/go-tc/types.go b/lib/go-tc/types.go
index f6e286c0c9..3d189aa6fe 100644
--- a/lib/go-tc/types.go
+++ b/lib/go-tc/types.go
@@ -22,6 +22,7 @@ package tc
import (
"database/sql"
"errors"
+ "time"
)
// TypesResponse is the type of a response from Traffic Ops to a GET request
@@ -49,6 +50,28 @@ type TypeNullable struct {
UseInTable *string `json:"useInTable" db:"use_in_table"`
}
+// TypesResponseV5 is type struct response used for the latest minor version
associated with api major version 5.
+type TypesResponseV5 = TypesResponseV50
+
+// TypesResponseV50 is the type of response (for RFC3339) from Traffic Ops to
a GET Request
+// made to its /types API endpoint.
+type TypesResponseV50 struct {
+ Response []TypeV50 `json:"response"`
+ Alerts
+}
+
+// TypeV5 contains information about a given Type in Traffic Ops used for the
latest minor version associated with api major version 5.
+type TypeV5 = TypeV50
+
+// TypeV50 contains information about a given Type in Traffic Ops.
+type TypeV50 struct {
+ ID int `json:"id"`
+ LastUpdated time.Time `json:"lastUpdated"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ UseInTable string `json:"useInTable"`
+}
+
// GetTypeData returns the type's name and use_in_table, true/false if the
// query returned data, and any error.
//
diff --git a/traffic_ops/testing/api/v5/traffic_control_test.go
b/traffic_ops/testing/api/v5/traffic_control_test.go
index 409da97887..4279332f36 100644
--- a/traffic_ops/testing/api/v5/traffic_control_test.go
+++ b/traffic_ops/testing/api/v5/traffic_control_test.go
@@ -55,7 +55,7 @@ type TrafficControl struct {
Tenants []tc.Tenant
`json:"tenants"`
ServerCheckExtensions
[]tc.ServerCheckExtensionNullable `json:"servercheck_extensions"`
Topologies []tc.Topology
`json:"topologies"`
- Types []tc.Type
`json:"types"`
+ Types []tc.TypeV5
`json:"types"`
SteeringTargets
[]tc.SteeringTargetNullable `json:"steeringTargets"`
Serverchecks
[]tc.ServercheckRequestNullable `json:"serverchecks"`
Users []tc.UserV4
`json:"users"`
diff --git a/traffic_ops/testing/api/v5/types_test.go
b/traffic_ops/testing/api/v5/types_test.go
index e23166b56d..307744eee0 100644
--- a/traffic_ops/testing/api/v5/types_test.go
+++ b/traffic_ops/testing/api/v5/types_test.go
@@ -38,7 +38,7 @@ func TestTypes(t *testing.T) {
currentTimeRFC := currentTime.Format(time.RFC1123)
tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)
- methodTests := utils.TestCase[client.Session,
client.RequestOptions, tc.Type]{
+ methodTests := utils.TestCase[client.Session,
client.RequestOptions, tc.TypeV5]{
"GET": {
"NOT MODIFIED when NO CHANGES made": {
ClientSession: TOSession,
@@ -65,7 +65,7 @@ func TestTypes(t *testing.T) {
"POST": {
"BAD REQUEST when INVALID useInTable NOT
server": {
ClientSession: TOSession,
- RequestBody: tc.Type{
+ RequestBody: tc.TypeV5{
Description: "Host header
regular expression-Test",
Name: "TEST_1",
UseInTable: "regex",
@@ -74,12 +74,12 @@ func TestTypes(t *testing.T) {
},
"OK when VALID request when useInTable=server":
{
ClientSession: TOSession,
- RequestBody: tc.Type{
+ RequestBody: tc.TypeV5{
Description: "Host header
regular expression-Test",
Name: "TEST_4",
UseInTable: "server",
},
- Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
+ Expectations:
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusCreated),
validateTypeUpdateCreateFields("TEST_4", map[string]interface{}{"Name":
"TEST_4"})),
},
},
@@ -87,7 +87,7 @@ func TestTypes(t *testing.T) {
"BAD REQUEST when useInTable NOT server": {
EndpointID: GetTypeID(t,
"ACTIVE_DIRECTORY"),
ClientSession: TOSession,
- RequestBody: tc.Type{
+ RequestBody: tc.TypeV5{
Description: "Active Directory
User",
Name: "TEST_3",
UseInTable: "cachegroup",
@@ -97,7 +97,7 @@ func TestTypes(t *testing.T) {
"OK when VALID request when useInTable=server":
{
EndpointID: GetTypeID(t, "RIAK"),
ClientSession: TOSession,
- RequestBody: tc.Type{
+ RequestBody: tc.TypeV5{
Description: "riak type",
Name: "TEST_5",
UseInTable: "server",
@@ -158,7 +158,7 @@ func validateTypeSort() utils.CkReqFunc {
return func(t *testing.T, _ toclientlib.ReqInf, resp interface{},
alerts tc.Alerts, _ error) {
assert.RequireNotNil(t, resp, "Expected Type response to not be
nil.")
var typeNames []string
- typeResp := resp.([]tc.Type)
+ typeResp := resp.([]tc.TypeV5)
for _, typ := range typeResp {
typeNames = append(typeNames, typ.Name)
}
@@ -169,7 +169,7 @@ func validateTypeSort() utils.CkReqFunc {
func validateTypeFields(expectedResp map[string]interface{}) utils.CkReqFunc {
return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _
tc.Alerts, _ error) {
assert.RequireNotNil(t, resp, "Expected Type response to not be
nil.")
- typeResp := resp.([]tc.Type)
+ typeResp := resp.([]tc.TypeV5)
for field, expected := range expectedResp {
for _, typ := range typeResp {
switch field {
diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go
b/traffic_ops/traffic_ops_golang/routing/routes.go
index fd92566d82..396db1766c 100644
--- a/traffic_ops/traffic_ops_golang/routing/routes.go
+++ b/traffic_ops/traffic_ops_golang/routing/routes.go
@@ -345,10 +345,10 @@ func Routes(d ServerData) ([]Route, http.Handler, error) {
{Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodGet, Path: `system/info/?$`, Handler: systeminfo.Get,
RequiredPrivLevel: auth.PrivLevelReadOnly, RequiredPermissions: nil,
Authenticated: Authenticated, Middlewares: nil, ID: 42104747531},
//Type: CRUD
- {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodGet, Path: `types/?$`, Handler: api.ReadHandler(&types.TOType{}),
RequiredPrivLevel: auth.PrivLevelReadOnly, RequiredPermissions:
[]string{"TYPE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID:
422670182331},
- {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodPut, Path: `types/{id}$`, Handler:
api.UpdateHandler(&types.TOType{}), RequiredPrivLevel:
auth.PrivLevelOperations, RequiredPermissions: []string{"TYPE:UPDATE",
"TYPE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 4886011531},
- {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodPost, Path: `types/?$`, Handler: api.CreateHandler(&types.TOType{}),
RequiredPrivLevel: auth.PrivLevelOperations, RequiredPermissions:
[]string{"TYPE:CREATE", "TYPE:READ"}, Authenticated: Authenticated,
Middlewares: nil, ID: 451330819531},
- {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodDelete, Path: `types/{id}$`, Handler:
api.DeleteHandler(&types.TOType{}), RequiredPrivLevel:
auth.PrivLevelOperations, RequiredPermissions: []string{"TYPE:DELETE",
"TYPE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 4317577331},
+ {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodGet, Path: `types/?$`, Handler: types.Read, RequiredPrivLevel:
auth.PrivLevelReadOnly, RequiredPermissions: []string{"TYPE:READ"},
Authenticated: Authenticated, Middlewares: nil, ID: 422670182331},
+ {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodPut, Path: `types/{id}$`, Handler: types.Update, RequiredPrivLevel:
auth.PrivLevelOperations, RequiredPermissions: []string{"TYPE:UPDATE",
"TYPE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 4886011531},
+ {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodPost, Path: `types/?$`, Handler: types.Create, RequiredPrivLevel:
auth.PrivLevelOperations, RequiredPermissions: []string{"TYPE:CREATE",
"TYPE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 451330819531},
+ {Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodDelete, Path: `types/{id}$`, Handler: types.Delete,
RequiredPrivLevel: auth.PrivLevelOperations, RequiredPermissions:
[]string{"TYPE:DELETE", "TYPE:READ"}, Authenticated: Authenticated,
Middlewares: nil, ID: 4317577331},
//About
{Version: api.Version{Major: 5, Minor: 0}, Method:
http.MethodGet, Path: `about/?$`, Handler: about.Handler(), RequiredPrivLevel:
auth.PrivLevelReadOnly, RequiredPermissions: nil, Authenticated: Authenticated,
Middlewares: nil, ID: 431750116631},
diff --git a/traffic_ops/traffic_ops_golang/types/types.go
b/traffic_ops/traffic_ops_golang/types/types.go
index 858715ebc8..ed77f4b941 100644
--- a/traffic_ops/traffic_ops_golang/types/types.go
+++ b/traffic_ops/traffic_ops_golang/types/types.go
@@ -21,17 +21,20 @@ package types
import (
"database/sql"
+ "encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"time"
+ "github.com/apache/trafficcontrol/lib/go-log"
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/lib/go-tc/tovalidate"
"github.com/apache/trafficcontrol/lib/go-util"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/util/ims"
validation "github.com/go-ozzo/ozzo-validation"
)
@@ -211,3 +214,238 @@ func deleteQuery() string {
WHERE id=:id`
return query
}
+
+// Read [V5] - gets a list of types for APIv5
+func Read(w http.ResponseWriter, r *http.Request) {
+ var runSecond bool
+ var maxTime time.Time
+ inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+ tx := inf.Tx
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ // Query Parameters to Database Query column mappings
+ queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+ "name": {Column: "typ.name"},
+ "id": {Column: "typ.id", Checker: api.IsInt},
+ "useInTable": {Column: "typ.use_in_table"},
+ }
+ if _, ok := inf.Params["orderby"]; !ok {
+ inf.Params["orderby"] = "name"
+ }
+ where, orderBy, pagination, queryValues, errs :=
dbhelpers.BuildWhereAndOrderByAndPagination(inf.Params, queryParamsToQueryCols)
+ if len(errs) > 0 {
+ api.HandleErr(w, r, tx.Tx, http.StatusBadRequest,
util.JoinErrs(errs), nil)
+ }
+
+ if inf.Config.UseIMS {
+ runSecond, maxTime = ims.TryIfModifiedSinceQuery(tx, r.Header,
queryValues, SelectMaxLastUpdatedQuery(where))
+ if !runSecond {
+ log.Debugln("IMS HIT")
+ api.AddLastModifiedHdr(w, maxTime)
+ w.WriteHeader(http.StatusNotModified)
+ return
+ }
+ log.Debugln("IMS MISS")
+ } else {
+ log.Debugln("Non IMS request")
+ }
+
+ query := selectQuery() + where + orderBy + pagination
+ rows, err := tx.NamedQuery(query, queryValues)
+ if err != nil {
+ api.HandleErr(w, r, tx.Tx, http.StatusInternalServerError, nil,
fmt.Errorf("type get: error getting type(s): %w", err))
+ }
+ defer log.Close(rows, "unable to close DB connection")
+
+ typ := tc.TypeV5{}
+ typeList := []tc.TypeV5{}
+ for rows.Next() {
+ if err = rows.Scan(&typ.ID, &typ.Name, &typ.Description,
&typ.UseInTable, &typ.LastUpdated); err != nil {
+ api.HandleErr(w, r, tx.Tx,
http.StatusInternalServerError, nil, fmt.Errorf("error getting type(s): %w",
err))
+ }
+ typeList = append(typeList, typ)
+ }
+
+ api.WriteResp(w, r, typeList)
+ return
+}
+
+// Create [V5] - creates the type with the passed data fpr APIv5.
+func Create(w http.ResponseWriter, r *http.Request) {
+ typ := tc.TypeV5{}
+
+ inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+ tx := inf.Tx.Tx
+
+ typ, readValErr := readAndValidateJsonStructV5(r)
+ if readValErr != nil {
+ api.HandleErr(w, r, tx, http.StatusBadRequest, readValErr, nil)
+ return
+ }
+
+ if typ.UseInTable != "server" {
+ api.HandleErr(w, r, tx, http.StatusBadRequest, fmt.Errorf("can
not create type."), nil)
+ return
+ }
+
+ // check if type already exists
+ var exists bool
+ err := tx.QueryRow(`SELECT EXISTS(SELECT * from type where name = $1)`,
typ.Name).Scan(&exists)
+
+ if err != nil {
+ api.HandleErr(w, r, tx, http.StatusInternalServerError, nil,
fmt.Errorf("error: %w, when checking if type with name %s exists", err,
typ.Name))
+ return
+ }
+ if exists {
+ api.HandleErr(w, r, tx, http.StatusBadRequest, fmt.Errorf("type
name '%s' already exists.", typ.Name), nil)
+ return
+ }
+
+ // create type
+ query := `INSERT INTO type (name, description, use_in_table) VALUES
($1, $2, $3) RETURNING id,last_updated`
+ err = tx.QueryRow(query, typ.Name, typ.Description,
typ.UseInTable).Scan(&typ.ID, &typ.LastUpdated)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ api.HandleErr(w, r, tx, http.StatusInternalServerError,
fmt.Errorf("error: %w in creating type with name: %s", err, typ.Name), nil)
+ return
+ }
+ usrErr, sysErr, code := api.ParseDBError(err)
+ api.HandleErr(w, r, tx, code, usrErr, sysErr)
+ return
+ }
+ alerts := tc.CreateAlerts(tc.SuccessLevel, "type was created.")
+ w.Header().Set("Location", fmt.Sprintf("/api/%d.%d/type?name=%s",
inf.Version.Major, inf.Version.Minor, typ.Name))
+ api.WriteAlertsObj(w, r, http.StatusCreated, alerts, typ)
+ return
+}
+
+// Update [V5] - updates name & description of the type passed for APIv5.
+func Update(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"},
[]string{"id"})
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+ tx := inf.Tx.Tx
+
+ typ, readValErr := readAndValidateJsonStructV5(r)
+ if readValErr != nil {
+ api.HandleErr(w, r, tx, http.StatusBadRequest, readValErr, nil)
+ return
+ }
+
+ requestedId := inf.IntParams["id"]
+ // check if the entity was already updated
+ userErr, sysErr, errCode = api.CheckIfUnModified(r.Header, inf.Tx,
requestedId, "type")
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+ return
+ }
+
+ if typ.UseInTable != "server" {
+ api.HandleErr(w, r, tx, http.StatusBadRequest, fmt.Errorf("can
not update type."), nil)
+ return
+ }
+
+ //update type query
+ query := `UPDATE type typ SET name= $1, description= $2, use_in_table=
$3 WHERE typ.id=$4 RETURNING typ.id, typ.last_updated`
+
+ err := tx.QueryRow(query, typ.Name, typ.Description, typ.UseInTable,
requestedId).Scan(&typ.ID, &typ.LastUpdated)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ api.HandleErr(w, r, tx, http.StatusNotFound,
fmt.Errorf("type with id: %d not found", requestedId), nil)
+ return
+ }
+ usrErr, sysErr, code := api.ParseDBError(err)
+ api.HandleErr(w, r, tx, code, usrErr, sysErr)
+ return
+ }
+ alerts := tc.CreateAlerts(tc.SuccessLevel, "type was updated")
+ api.WriteAlertsObj(w, r, http.StatusOK, alerts, typ)
+ return
+}
+
+// Delete [V5] - deletes the type passed for APIv5.
+func Delete(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+ tx := inf.Tx.Tx
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ id := inf.Params["id"]
+ // check if type already exists
+ var exists bool
+ err := tx.QueryRow(`SELECT EXISTS(SELECT * from type where id = $1)`,
id).Scan(&exists)
+
+ if err != nil {
+ api.HandleErr(w, r, tx, http.StatusInternalServerError, nil,
err)
+ return
+ }
+ if !exists {
+ api.HandleErr(w, r, tx, http.StatusNotFound, fmt.Errorf("can
not delete type"), nil)
+ return
+ }
+
+ res, err := tx.Exec("DELETE FROM type AS typ WHERE typ.id=$1", id)
+ if err != nil {
+ api.HandleErr(w, r, tx, http.StatusInternalServerError, nil,
err)
+ return
+ }
+ rowsAffected, err := res.RowsAffected()
+ if err != nil {
+ api.HandleErr(w, r, tx, http.StatusInternalServerError, nil,
fmt.Errorf("determining rows affected for delete type: %w", err))
+ return
+ }
+ if rowsAffected == 0 {
+ api.HandleErr(w, r, tx, http.StatusInternalServerError, nil,
fmt.Errorf("no rows deleted for type"))
+ return
+ }
+
+ alertMessage := fmt.Sprintf("type was deleted.")
+ alerts := tc.CreateAlerts(tc.SuccessLevel, alertMessage)
+ api.WriteAlerts(w, r, http.StatusOK, alerts)
+ return
+}
+
+// readAndValidateJsonStructV5 [V5] - validates the JSON object passed.
+func readAndValidateJsonStructV5(r *http.Request) (tc.TypeV5, error) {
+ var typ tc.TypeV5
+ if err := json.NewDecoder(r.Body).Decode(&typ); err != nil {
+ userErr := fmt.Errorf("error decoding POST request body into
TypeV5 struct %w", err)
+ return typ, userErr
+ }
+
+ // validate JSON body
+ rule :=
validation.NewStringRule(tovalidate.IsAlphanumericUnderscoreDash, "must consist
of only alphanumeric, dash, or underscore characters")
+ errs := tovalidate.ToErrors(validation.Errors{
+ "name": validation.Validate(typ.Name,
validation.Required, rule),
+ "description": validation.Validate(typ.Description,
validation.Required),
+ "use_in_table": validation.Validate(typ.UseInTable,
validation.Required),
+ })
+ if len(errs) > 0 {
+ userErr := util.JoinErrs(errs)
+ return typ, userErr
+ }
+ return typ, nil
+}
+
+// SelectMaxLastUpdatedQuery used for TryIfModifiedSinceQuery()
+func SelectMaxLastUpdatedQuery(where string) string {
+ return `SELECT max(t) from (
+ SELECT max(last_updated) as t from type typ ` + where +
+ ` UNION ALL
+ select max(last_updated) as t from last_deleted l where
l.table_name='type') as res`
+}
diff --git a/traffic_ops/v5-client/type.go b/traffic_ops/v5-client/type.go
index 521f1d8a94..6572c51a5a 100644
--- a/traffic_ops/v5-client/type.go
+++ b/traffic_ops/v5-client/type.go
@@ -26,14 +26,14 @@ import (
const apiTypes = "/types"
// CreateType creates the given Type. There should be a very good reason for
doing this.
-func (to *Session) CreateType(typ tc.Type, opts RequestOptions) (tc.Alerts,
toclientlib.ReqInf, error) {
+func (to *Session) CreateType(typ tc.TypeV5, opts RequestOptions) (tc.Alerts,
toclientlib.ReqInf, error) {
var alerts tc.Alerts
reqInf, err := to.post(apiTypes, opts, typ, &alerts)
return alerts, reqInf, err
}
// UpdateType replaces the Type identified by 'id' with the one provided.
-func (to *Session) UpdateType(id int, typ tc.Type, opts RequestOptions)
(tc.Alerts, toclientlib.ReqInf, error) {
+func (to *Session) UpdateType(id int, typ tc.TypeV5, opts RequestOptions)
(tc.Alerts, toclientlib.ReqInf, error) {
route := fmt.Sprintf("%s/%d", apiTypes, id)
var alerts tc.Alerts
reqInf, err := to.put(route, opts, typ, &alerts)
@@ -44,8 +44,8 @@ func (to *Session) UpdateType(id int, typ tc.Type, opts
RequestOptions) (tc.Aler
// If a 'useInTable' parameter is passed, the returned Types are restricted to
those with
// that exact 'useInTable' property. Only exactly 1 or exactly 0 'useInTable'
parameters may
// be passed; passing more will result in an error being returned.
-func (to *Session) GetTypes(opts RequestOptions) (tc.TypesResponse,
toclientlib.ReqInf, error) {
- var data tc.TypesResponse
+func (to *Session) GetTypes(opts RequestOptions) (tc.TypesResponseV5,
toclientlib.ReqInf, error) {
+ var data tc.TypesResponseV5
reqInf, err := to.get(apiTypes, opts, &data)
return data, reqInf, err
}