You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by de...@apache.org on 2018/04/02 14:02:22 UTC

[incubator-trafficcontrol] 01/02: intial work to support compound keys, only cdn implemented

This is an automated email from the ASF dual-hosted git repository.

dewrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-trafficcontrol.git

commit 53ec33c6583889c82d2b624dea815f2827cf8aa7
Author: Dylan Volz <Dy...@comcast.com>
AuthorDate: Tue Mar 27 14:40:39 2018 -0600

    intial work to support compound keys, only cdn implemented
---
 .../traffic_ops_golang/api/shared_handlers.go      | 71 +++++++++++++++++-----
 .../traffic_ops_golang/api/shared_interfaces.go    |  7 ++-
 traffic_ops/traffic_ops_golang/cdn/cdns.go         | 19 ++++--
 3 files changed, 72 insertions(+), 25 deletions(-)

diff --git a/traffic_ops/traffic_ops_golang/api/shared_handlers.go b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
index f1edb0d..298f32f 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_handlers.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
@@ -33,10 +33,24 @@ import (
 	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
 
 	"github.com/jmoiron/sqlx"
+	"strings"
 )
 
 const PathParamsKey = "pathParams"
 
+type KeyFieldInfo struct{
+	Field string
+	Func func(string)(interface{},error)
+}
+
+func GetIntKey(s string)(interface{},error){
+	return strconv.Atoi(s)
+}
+
+func GetStringKey(s string)(interface{},error){
+	return s, nil
+}
+
 func GetPathParams(ctx context.Context) (map[string]string, error) {
 	val := ctx.Value(PathParamsKey)
 	if val != nil {
@@ -175,7 +189,7 @@ func UpdateHandler(typeRef Updater, db *sqlx.DB) http.HandlerFunc {
 
 		//collect path parameters and user from context
 		ctx := r.Context()
-		pathParams, err := GetPathParams(ctx)
+		params, err := GetCombinedParams(r)
 		if err != nil {
 			log.Errorf("received error trying to get path parameters: %s", err)
 			handleErrs(http.StatusInternalServerError, err)
@@ -187,17 +201,30 @@ func UpdateHandler(typeRef Updater, db *sqlx.DB) http.HandlerFunc {
 			handleErrs(http.StatusInternalServerError, err)
 			return
 		}
-		id, err := strconv.Atoi(pathParams["id"])
-		if err != nil {
-			log.Errorf("received error trying to convert id path parameter: %s", err)
-			handleErrs(http.StatusBadRequest, errors.New("id from path not parseable as int"))
-			return
+
+		keyFields := u.GetKeyFieldsInfo() //expecting a slice of the key fields info which is a struct with the field name and a function to convert a string into a {}interface of the right type. in most that will be [{Field:"id",Func: func(s string)({}interface,error){return strconv.Atoi(s)}}]
+		keys, ok := u.GetKeys() // a map of keyField to keyValue where keyValue is an {}interface
+		if !ok {
+
 		}
+		for _,keyFieldInfo := range keyFields {
+			paramKey := params[keyFieldInfo.Field]
+			if paramKey == "" {
+				log.Errorf("missing key: %s", keyFieldInfo.Field)
+				handleErrs(http.StatusBadRequest, errors.New("missing key: " + keyFieldInfo.Field))
+				return
+			}
 
-		iid, ok := u.GetID()
-		if !ok || iid != id {
-			handleErrs(http.StatusBadRequest, errors.New("id in body does not match id in path"))
-			return
+			paramValue, err := keyFieldInfo.Func(paramKey)
+			if err != nil {
+				log.Errorf("failed to parse key %s: %s", keyFieldInfo.Field, err)
+				handleErrs(http.StatusBadRequest, errors.New("failed to parse key: " + keyFieldInfo.Field))
+			}
+
+			if paramValue != keys[keyFieldInfo.Field] {
+				handleErrs(http.StatusBadRequest, errors.New("key in body does not match key in params"))
+				return
+			}
 		}
 
 		// if the object has tenancy enabled, check that user is able to access the tenant
@@ -252,7 +279,7 @@ func DeleteHandler(typeRef Deleter, db *sqlx.DB) http.HandlerFunc {
 		d := typeRef
 
 		ctx := r.Context()
-		pathParams, err := GetPathParams(ctx)
+		params, err := GetCombinedParams(r)
 		if err != nil {
 			handleErrs(http.StatusInternalServerError, err)
 			return
@@ -264,12 +291,24 @@ func DeleteHandler(typeRef Deleter, db *sqlx.DB) http.HandlerFunc {
 			return
 		}
 
-		id, err := strconv.Atoi(pathParams["id"])
-		if err != nil {
-			handleErrs(http.StatusBadRequest, errors.New("id from path not parseable as int"))
-			return
+		keyFields := d.GetKeyFieldsInfo() // expecting a slice of the key fields info which is a struct with the field name and a function to convert a string into a interface{} of the right type. in most that will be [{Field:"id",Func: func(s string)(interface{},error){return strconv.Atoi(s)}}]
+		keys := make(map[string]interface{})
+		for _,keyFieldInfo := range keyFields {
+			paramKey := params[keyFieldInfo.Field]
+			if paramKey == "" {
+				log.Errorf("missing key: %s", keyFieldInfo.Field)
+				handleErrs(http.StatusBadRequest, errors.New("missing key: "+keyFieldInfo.Field))
+				return
+			}
+
+			paramValue, err := keyFieldInfo.Func(paramKey)
+			if err != nil {
+				log.Errorf("failed to parse key %s: %s", keyFieldInfo.Field, err)
+				handleErrs(http.StatusBadRequest, errors.New("failed to parse key: "+keyFieldInfo.Field))
+			}
+			keys[keyFieldInfo.Field] = paramValue
 		}
-		d.SetID(id)
+		d.SetKeys(keys)// if the type assertion of a key fails it will be should be set to the zero value of the type and the delete should fail (this means the code is not written properly no changes of user input should cause this.)
 
 		// if the object has tenancy enabled, check that user is able to access the tenant
 		if t, ok := d.(Tenantable); ok {
diff --git a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
index da23de5..5d4c203 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
@@ -32,21 +32,22 @@ type Updater interface {
 }
 
 type Identifier interface {
-	GetID() (int, bool)
+	GetKeys() (map[string]interface{}, bool)
 	GetType() string
 	GetAuditName() string
+	GetKeyFieldsInfo() []KeyFieldInfo
 }
 
 type Creator interface {
 	Create(db *sqlx.DB, user auth.CurrentUser) (error, tc.ApiErrorType)
-	SetID(int)
+	SetKeys(map[string]interface{})
 	Identifier
 	Validator
 }
 
 type Deleter interface {
 	Delete(db *sqlx.DB, user auth.CurrentUser) (error, tc.ApiErrorType)
-	SetID(int)
+	SetKeys(map[string]interface{})
 	Identifier
 }
 
diff --git a/traffic_ops/traffic_ops_golang/cdn/cdns.go b/traffic_ops/traffic_ops_golang/cdn/cdns.go
index c37e6e9..885eb11 100644
--- a/traffic_ops/traffic_ops_golang/cdn/cdns.go
+++ b/traffic_ops/traffic_ops_golang/cdn/cdns.go
@@ -48,27 +48,34 @@ func GetRefType() *TOCDN {
 	return &refType
 }
 
+func (cdn TOCDN) GetKeyFieldsInfo() []api.KeyFieldInfo {
+	return []api.KeyFieldInfo{{"id",api.GetIntKey}}
+}
+
 //Implementation of the Identifier, Validator interface functions
-func (cdn TOCDN) GetID() (int, bool) {
+func (cdn TOCDN) GetKeys() (map[string]interface{}, bool) {
 	if cdn.ID == nil {
-		return 0, false
+		return map[string]interface{}{"id":0}, false
 	}
-	return *cdn.ID, true
+	return map[string]interface{}{"id":*cdn.ID}, true
 }
 
 func (cdn TOCDN) GetAuditName() string {
 	if cdn.Name != nil {
 		return *cdn.Name
 	}
-	id, _ := cdn.GetID()
-	return strconv.Itoa(id)
+	if cdn.ID != nil {
+		return strconv.Itoa(*cdn.ID)
+	}
+	return "0"
 }
 
 func (cdn TOCDN) GetType() string {
 	return "cdn"
 }
 
-func (cdn *TOCDN) SetID(i int) {
+func (cdn *TOCDN) SetKeys(keys map[string]interface{}) {
+	i, _ := keys["id"].(int) //this utilizes the non panicking type assertion, if the thrown away ok variable is false i will be the zero of the type, 0 here.
 	cdn.ID = &i
 }
 

-- 
To stop receiving notification emails like this one, please contact
dewrich@apache.org.