mitchell852 closed pull request #2229: Add Traffic Ops Golang 
deliveryservicesregexes
URL: https://github.com/apache/incubator-trafficcontrol/pull/2229
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/lib/go-tc/deliveryservice_regexes.go 
b/lib/go-tc/deliveryservice_regexes.go
index df214feb3..117d61f4c 100644
--- a/lib/go-tc/deliveryservice_regexes.go
+++ b/lib/go-tc/deliveryservice_regexes.go
@@ -31,3 +31,37 @@ type DeliveryServiceRegex struct {
        SetNumber int    `json:"setNumber"`
        Pattern   string `json:"pattern"`
 }
+
+type DeliveryServiceRegexV12 struct {
+       DeliveryServiceRegex
+}
+
+type DeliveryServiceRegexV13 struct {
+       DeliveryServiceRegexV12
+}
+
+type DeliveryServiceIDRegexResponse struct {
+       Response []DeliveryServiceIDRegex `json:"response"`
+}
+
+type DeliveryServiceIDRegex struct {
+       ID        int    `json:"id"`
+       Type      int    `json:"type"`
+       TypeName  string `json:"typeName"`
+       SetNumber int    `json:"setNumber"`
+       Pattern   string `json:"pattern"`
+}
+
+type DeliveryServiceIDRegexV12 struct {
+       DeliveryServiceIDRegex
+}
+
+type DeliveryServiceIDRegexV13 struct {
+       DeliveryServiceIDRegexV12
+}
+
+type DeliveryServiceRegexPost struct {
+       Type      int    `json:"type"`
+       SetNumber int    `json:"setNumber"`
+       Pattern   string `json:"pattern"`
+}
diff --git a/traffic_ops/traffic_ops_golang/api/change_log.go 
b/traffic_ops/traffic_ops_golang/api/change_log.go
index f2fb18f5c..1b304292c 100644
--- a/traffic_ops/traffic_ops_golang/api/change_log.go
+++ b/traffic_ops/traffic_ops_golang/api/change_log.go
@@ -51,28 +51,34 @@ const (
 )
 
 func CreateChangeLog(level string, action string, i Identifier, user 
auth.CurrentUser, db *sqlx.DB) error {
-       keys, _ := i.GetKeys()
-       keysString := "{ "
-       for key, value := range keys {
-               keysString += key + ":" + fmt.Sprintf("%v", value) + " "
+       t, ok := i.(ChangeLogger)
+       if !ok {
+               keys, _ := i.GetKeys()
+               return CreateChangeLogBuildMsg(level, action, user, db, 
i.GetType(), i.GetAuditName(), keys)
+       }
+       msg, err := t.ChangeLogMessage(action)
+       if err != nil {
+               log.Errorf("%++v creating log message for %++v", err, t)
+               keys, _ := i.GetKeys()
+               return CreateChangeLogBuildMsg(level, action, user, db, 
i.GetType(), i.GetAuditName(), keys)
        }
-       keysString += "}"
-       message := action + " " + i.GetType() + ": " + i.GetAuditName() + " 
keys: " + keysString
-       // if the object has its own log message generation, use it
-       if t, ok := i.(ChangeLogger); ok {
-               m, err := t.ChangeLogMessage(action)
-               if err != nil {
-                       log.Errorf("error %++v creating log message for %++v", 
err, t)
-                       // use the default message in this case
-               } else {
-                       message = m
-               }
+       return CreateChangeLogMsg(level, user, db, msg)
+}
+
+func CreateChangeLogBuildMsg(level string, action string, user 
auth.CurrentUser, db *sqlx.DB, objType string, auditName string, keys 
map[string]interface{}) error {
+       keyStr := "{ "
+       for key, value := range keys {
+               keyStr += key + ":" + fmt.Sprintf("%v", value) + " "
        }
+       keyStr += "}"
+       msg := action + " " + objType + ": " + auditName + " keys: " + keyStr
+       return CreateChangeLogMsg(level, user, db, msg)
+}
 
+func CreateChangeLogMsg(level string, user auth.CurrentUser, db *sqlx.DB, msg 
string) error {
        query := `INSERT INTO log (level, message, tm_user) VALUES ($1, $2, $3)`
-       log.Debugf("about to exec %s with %s", query, message)
-       _, err := db.Exec(query, level, message, user.ID)
-       if err != nil {
+       log.Debugf("about to exec %s with %s", query, msg)
+       if _, err := db.Exec(query, level, msg, user.ID); err != nil {
                log.Errorf("received error: %++v from audit log insertion", err)
                return err
        }
diff --git 
a/traffic_ops/traffic_ops_golang/deliveryservicesregexes/deliveryservicesregexes.go
 
b/traffic_ops/traffic_ops_golang/deliveryservicesregexes/deliveryservicesregexes.go
new file mode 100644
index 000000000..8284242d3
--- /dev/null
+++ 
b/traffic_ops/traffic_ops_golang/deliveryservicesregexes/deliveryservicesregexes.go
@@ -0,0 +1,591 @@
+package deliveryservicesregexes
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+       "database/sql"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "net/http"
+       "strconv"
+
+       "github.com/apache/incubator-trafficcontrol/lib/go-log"
+       "github.com/apache/incubator-trafficcontrol/lib/go-tc"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
+       // 
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+       // 
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/tovalidate"
+
+       // "github.com/asaskevich/govalidator"
+       // "github.com/go-ozzo/ozzo-validation"
+       "github.com/jmoiron/sqlx"
+       // "github.com/lib/pq"
+)
+
+func Get(dbx *sqlx.DB) http.HandlerFunc {
+       db := dbx.DB
+       return func(w http.ResponseWriter, r *http.Request) {
+               handleErrs := tc.GetHandleErrorsFunc(w, r)
+               user, err := auth.GetCurrentUser(r.Context())
+               if err != nil {
+                       log.Errorf("unable to retrieve current user from 
context: %s", err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               q := `
+SELECT ds.xml_id, ds.tenant_id, dsr.set_number, r.pattern, rt.name as type
+FROM deliveryservice_regex as dsr
+JOIN deliveryservice as ds ON dsr.deliveryservice = ds.id
+JOIN regex as r ON dsr.regex = r.id
+JOIN type as rt ON r.type = rt.id
+`
+               rows, err := db.Query(q)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("querying: "+err.Error()))
+                       return
+               }
+               dsRegexes := 
map[tc.DeliveryServiceName][]tc.DeliveryServiceRegex{}
+               for rows.Next() {
+                       // if 
(!$tenant_utils->is_ds_resource_accessible($tenants_data, $ds->tenant_id)) {
+                       //      next;
+                       // }
+                       dsName := ""
+                       dsTenantID := 0
+                       setNumber := 0
+                       pattern := ""
+                       typeName := ""
+                       if err = rows.Scan(&dsName, &dsTenantID, &setNumber, 
&pattern, &typeName); err != nil {
+                               handleErrs(http.StatusInternalServerError, 
errors.New("querying: "+err.Error()))
+                               return
+                       }
+                       if ok, err := 
tenant.IsResourceAuthorizedToUser(dsTenantID, *user, dbx); !ok {
+                               continue
+                       } else if err != nil {
+                               handleErrs(http.StatusInternalServerError, 
errors.New("checking tenancy: "+err.Error()))
+                               return
+                       }
+                       dsRegexes[tc.DeliveryServiceName(dsName)] = 
append(dsRegexes[tc.DeliveryServiceName(dsName)], tc.DeliveryServiceRegex{
+                               Type:      typeName,
+                               SetNumber: setNumber,
+                               Pattern:   pattern,
+                       })
+               }
+               respRegexes := []tc.DeliveryServiceRegexes{}
+               for dsName, regexes := range dsRegexes {
+                       respRegexes = append(respRegexes, 
tc.DeliveryServiceRegexes{DSName: string(dsName), Regexes: regexes})
+               }
+               respBts, err := 
json.Marshal(&tc.DeliveryServiceRegexResponse{Response: respRegexes})
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("marshalling JSON: "+err.Error()))
+                       return
+               }
+               w.Header().Set("Content-Type", "application/json")
+               w.Write(respBts)
+       }
+}
+
+func DSGet(dbx *sqlx.DB) http.HandlerFunc {
+       db := dbx.DB
+       return func(w http.ResponseWriter, r *http.Request) {
+               handleErrs := tc.GetHandleErrorsFunc(w, r)
+               user, err := auth.GetCurrentUser(r.Context())
+               if err != nil {
+                       log.Errorf("unable to retrieve current user from 
context: %s", err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               params, err := api.GetCombinedParams(r)
+               if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               dsIDStr, ok := params["dsid"]
+               if !ok {
+                       log.Errorln("no delivery service ID")
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               dsID, err := strconv.Atoi(dsIDStr)
+               if err != nil {
+                       log.Errorln("Delivery service ID '" + dsIDStr + "' not 
an integer")
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+
+               q := `
+SELECT ds.tenant_id, dsr.set_number, r.id, r.pattern, rt.id as type, rt.name 
as type_name
+FROM deliveryservice_regex as dsr
+JOIN deliveryservice as ds ON dsr.deliveryservice = ds.id
+JOIN regex as r ON dsr.regex = r.id
+JOIN type as rt ON r.type = rt.id
+WHERE ds.ID = $1
+ORDER BY dsr.set_number ASC
+`
+               rows, err := db.Query(q, dsID)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("querying: "+err.Error()))
+                       return
+               }
+               regexes := []tc.DeliveryServiceIDRegex{}
+               for rows.Next() {
+                       dsTenantID := 0
+                       setNumber := 0
+                       id := 0
+                       pattern := ""
+                       typeID := 0
+                       typeName := ""
+                       if err = rows.Scan(&dsTenantID, &setNumber, &id, 
&pattern, &typeID, &typeName); err != nil {
+                               handleErrs(http.StatusInternalServerError, 
errors.New("querying: "+err.Error()))
+                               return
+                       }
+                       if ok, err := 
tenant.IsResourceAuthorizedToUser(dsTenantID, *user, dbx); !ok {
+                               continue
+                       } else if err != nil {
+                               handleErrs(http.StatusInternalServerError, 
errors.New("checking tenancy: "+err.Error()))
+                               return
+                       }
+                       regexes = append(regexes, tc.DeliveryServiceIDRegex{
+                               ID:        id,
+                               Type:      typeID,
+                               TypeName:  typeName,
+                               SetNumber: setNumber,
+                               Pattern:   pattern,
+                       })
+               }
+               respBts, err := 
json.Marshal(&tc.DeliveryServiceIDRegexResponse{Response: regexes})
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("marshalling JSON: "+err.Error()))
+                       return
+               }
+               w.Header().Set("Content-Type", "application/json")
+               w.Write(respBts)
+       }
+}
+
+func DSGetID(dbx *sqlx.DB) http.HandlerFunc {
+       db := dbx.DB
+       return func(w http.ResponseWriter, r *http.Request) {
+               handleErrs := tc.GetHandleErrorsFunc(w, r)
+               user, err := auth.GetCurrentUser(r.Context())
+               if err != nil {
+                       log.Errorf("unable to retrieve current user from 
context: %s", err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               params, err := api.GetCombinedParams(r)
+               if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               dsIDStr, ok := params["dsid"]
+               if !ok {
+                       log.Errorln("no delivery service ID")
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               dsID, err := strconv.Atoi(dsIDStr)
+               if err != nil {
+                       log.Errorln("Delivery service ID '" + dsIDStr + "' not 
an integer")
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               regexIDStr, ok := params["regexid"]
+               if !ok {
+                       log.Errorln("no regex ID")
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               regexID, err := strconv.Atoi(regexIDStr)
+               if err != nil {
+                       log.Errorln("Regex ID '" + regexIDStr + "' not an 
integer")
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+
+               q := `
+SELECT ds.tenant_id, dsr.set_number, r.id, r.pattern, rt.id as type, rt.name 
as type_name
+FROM deliveryservice_regex as dsr
+JOIN deliveryservice as ds ON dsr.deliveryservice = ds.id
+JOIN regex as r ON dsr.regex = r.id
+JOIN type as rt ON r.type = rt.id
+WHERE ds.ID = $1
+AND r.ID = $2
+ORDER BY dsr.set_number ASC
+`
+               rows, err := db.Query(q, dsID, regexID)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("querying: "+err.Error()))
+                       return
+               }
+               regexes := []tc.DeliveryServiceIDRegex{}
+               for rows.Next() {
+                       dsTenantID := 0
+                       setNumber := 0
+                       id := 0
+                       pattern := ""
+                       typeID := 0
+                       typeName := ""
+                       if err = rows.Scan(&dsTenantID, &setNumber, &id, 
&pattern, &typeID, &typeName); err != nil {
+                               handleErrs(http.StatusInternalServerError, 
errors.New("querying: "+err.Error()))
+                               return
+                       }
+                       if ok, err := 
tenant.IsResourceAuthorizedToUser(dsTenantID, *user, dbx); !ok {
+                               continue
+                       } else if err != nil {
+                               handleErrs(http.StatusInternalServerError, 
errors.New("checking tenancy: "+err.Error()))
+                               return
+                       }
+                       regexes = append(regexes, tc.DeliveryServiceIDRegex{
+                               ID:        id,
+                               Type:      typeID,
+                               TypeName:  typeName,
+                               SetNumber: setNumber,
+                               Pattern:   pattern,
+                       })
+               }
+               respBts, err := 
json.Marshal(&tc.DeliveryServiceIDRegexResponse{Response: regexes})
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("marshalling JSON: "+err.Error()))
+                       return
+               }
+               w.Header().Set("Content-Type", "application/json")
+               w.Write(respBts)
+       }
+}
+
+func Post(dbx *sqlx.DB) http.HandlerFunc {
+       db := dbx.DB
+       return func(w http.ResponseWriter, r *http.Request) {
+               handleErrs := tc.GetHandleErrorsFunc(w, r)
+               user, err := auth.GetCurrentUser(r.Context())
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("unable to retrieve current user from context: "+err.Error()))
+                       return
+               }
+               params, err := api.GetCombinedParams(r)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("unable to get parameters from request: "+err.Error()))
+                       return
+               }
+               dsIDStr, ok := params["dsid"]
+               if !ok {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("no deliveryservice ID"))
+                       return
+               }
+               dsID, err := strconv.Atoi(dsIDStr)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("deliveryservice ID not an integer"))
+                       return
+               }
+               dsTenantID := 0
+               if err := db.QueryRow(`SELECT tenant_id from deliveryservice 
where id = $1`, dsID).Scan(&dsTenantID); err != nil {
+                       if err != sql.ErrNoRows {
+                               log.Errorln("getting deliveryservice name: " + 
err.Error())
+                       }
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               if ok, err := tenant.IsResourceAuthorizedToUser(dsTenantID, 
*user, dbx); !ok {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("unauthorized"))
+                       return
+               } else if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("checking tenancy: "+err.Error()))
+                       return
+               }
+               dsr := tc.DeliveryServiceRegexPost{}
+               if err := json.NewDecoder(r.Body).Decode(&dsr); err != nil {
+                       log.Errorln("failed to parse body: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+
+               regexID := 0
+               if err := db.QueryRow(`INSERT INTO regex (pattern, type) VALUES 
($1, $2) RETURNING id`, dsr.Pattern, dsr.Type).Scan(&regexID); err != nil {
+                       log.Errorln("inserting regex: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+
+               if _, err := db.Exec(`INSERT INTO deliveryservice_regex 
(deliveryservice, regex, set_number) values ($1, $2, $3)`, dsID, regexID, 
dsr.SetNumber); err != nil {
+                       log.Errorln("inserting deliveryservice_regex: " + 
err.Error())
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+
+               typeName := ""
+               if err := db.QueryRow(`SELECT name from type where id = $1`, 
dsr.Type).Scan(&typeName); err != nil {
+                       if err != sql.ErrNoRows {
+                               log.Errorln("getting regex type: " + 
err.Error())
+                       }
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+
+               respObj := tc.DeliveryServiceIDRegex{
+                       ID:        regexID,
+                       Pattern:   dsr.Pattern,
+                       Type:      dsr.Type,
+                       TypeName:  typeName,
+                       SetNumber: dsr.SetNumber,
+               }
+               resp := struct {
+                       Response tc.DeliveryServiceIDRegex `json:"response"`
+                       tc.Alerts
+               }{respObj, tc.CreateAlerts(tc.SuccessLevel, "Delivery service 
regex creation was successful.")}
+
+               respBts, err := json.Marshal(&resp)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("marshalling JSON: "+err.Error()))
+                       return
+               }
+               w.Header().Set("Content-Type", "application/json")
+               w.Write(respBts)
+       }
+}
+
+func Put(dbx *sqlx.DB) http.HandlerFunc {
+       db := dbx.DB
+       return func(w http.ResponseWriter, r *http.Request) {
+               handleErrs := tc.GetHandleErrorsFunc(w, r)
+               user, err := auth.GetCurrentUser(r.Context())
+               if err != nil {
+                       log.Errorf("unable to retrieve current user from 
context: %s", err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               params, err := api.GetCombinedParams(r)
+               if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               dsIDStr, ok := params["dsid"]
+               if !ok {
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               dsID, err := strconv.Atoi(dsIDStr)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               regexIDStr, ok := params["regexid"]
+               if !ok {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("no regex ID"))
+                       return
+               }
+               regexID, err := strconv.Atoi(regexIDStr)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("Regex ID '"+regexIDStr+"' not an integer"))
+                       return
+               }
+               dsTenantID := 0
+               if err := db.QueryRow(`SELECT tenant_id from deliveryservice 
where id = $1`, dsID).Scan(&dsTenantID); err != nil {
+                       if err != sql.ErrNoRows {
+                               log.Errorln("getting deliveryservice name: " + 
err.Error())
+                       }
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               if ok, err := tenant.IsResourceAuthorizedToUser(dsTenantID, 
*user, dbx); !ok {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("unauthorized"))
+                       return
+               } else if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("checking tenancy: "+err.Error()))
+                       return
+               }
+               dsr := tc.DeliveryServiceRegexPost{} // PUT uses same format as 
POST
+               if err := json.NewDecoder(r.Body).Decode(&dsr); err != nil {
+                       log.Errorln("failed to parse body: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               if _, err := db.Exec(`UPDATE regex SET pattern=$1, type=$2 
WHERE id=$3`, dsr.Pattern, dsr.Type, regexID); err != nil {
+                       log.Errorln("deliveryservicesregexes.Put: updating 
regex: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               if _, err := db.Exec(`UPDATE deliveryservice_regex SET 
set_number=$1 WHERE deliveryservice=$2 AND regex=$3`, dsr.SetNumber, dsID, 
regexID); err != nil {
+                       log.Errorln("deliveryservicesregexes.Put: updating 
deliveryservice_regex: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               typeName := ""
+               if err := db.QueryRow(`SELECT name from type where id = $1`, 
dsr.Type).Scan(&typeName); err != nil {
+                       if err != sql.ErrNoRows {
+                               log.Errorln("getting regex type: " + 
err.Error())
+                       }
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               respObj := tc.DeliveryServiceIDRegex{
+                       ID:        regexID,
+                       Pattern:   dsr.Pattern,
+                       Type:      dsr.Type,
+                       TypeName:  typeName,
+                       SetNumber: dsr.SetNumber,
+               }
+               resp := struct {
+                       Response tc.DeliveryServiceIDRegex `json:"response"`
+                       tc.Alerts
+               }{respObj, tc.CreateAlerts(tc.SuccessLevel, "Delivery service 
regex creation was successful.")}
+               respBts, err := json.Marshal(&resp)
+               if err != nil {
+                       handleErrs(http.StatusInternalServerError, 
errors.New("marshalling JSON: "+err.Error()))
+                       return
+               }
+               w.Header().Set("Content-Type", "application/json")
+               w.Write(respBts)
+       }
+}
+
+func Delete(dbx *sqlx.DB) http.HandlerFunc {
+       db := dbx.DB
+       return func(w http.ResponseWriter, r *http.Request) {
+               handleErrs := tc.GetHandleErrorsFunc(w, r)
+               user, err := auth.GetCurrentUser(r.Context())
+               if err != nil {
+                       log.Errorf("unable to retrieve current user from 
context: %s", err)
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               params, err := api.GetCombinedParams(r)
+               if err != nil {
+                       log.Errorf("unable to get parameters from request: %s", 
err)
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               dsIDStr, ok := params["dsid"]
+               if !ok {
+                       log.Errorf("deliveryservicesregexes.Delete: no dsid 
parameter")
+                       handleErrs(http.StatusInternalServerError, 
errors.New("internal server error"))
+                       return
+               }
+               dsID, err := strconv.Atoi(dsIDStr)
+               if err != nil {
+                       handleErrs(http.StatusBadRequest, errors.New("delivery 
service ID is not an integer"))
+                       return
+               }
+               regexIDStr, ok := params["regexid"]
+               if !ok {
+                       handleErrs(http.StatusBadRequest, errors.New("no regex 
ID"))
+                       return
+               }
+               regexID, err := strconv.Atoi(regexIDStr)
+               if err != nil {
+                       handleErrs(http.StatusBadRequest, errors.New("Regex ID 
'"+regexIDStr+"' not an integer"))
+                       return
+               }
+
+               tx, err := db.Begin()
+               if err != nil {
+                       log.Errorln("could not begin transaction: " + 
err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("could not begin transaction: "+err.Error()))
+                       return
+               }
+               commitTx := false
+               defer FinishTx(tx, &commitTx)
+
+               count := 0
+               if err := db.QueryRow(`SELECT count(*) from 
deliveryservice_regex where deliveryservice = $1`, dsID).Scan(&count); err != 
nil {
+                       if err != sql.ErrNoRows {
+                               handleErrs(http.StatusNotFound, errors.New("not 
found"))
+                               return
+                       }
+                       log.Errorln(errors.New("getting deliveryservice regex 
count: " + err.Error()))
+                       handleErrs(http.StatusInternalServerError, 
errors.New("internal server error"))
+                       return
+               }
+               if count < 2 {
+                       handleErrs(http.StatusBadRequest, errors.New("a 
delivery service must have at least one regex"))
+                       return
+               }
+
+               dsTenantID := 0
+               if err := db.QueryRow(`SELECT tenant_id from deliveryservice 
where id = $1`, dsID).Scan(&dsTenantID); err != nil {
+                       if err != sql.ErrNoRows {
+                               log.Errorln("getting deliveryservice name: " + 
err.Error())
+                       }
+                       handleErrs(http.StatusInternalServerError, err)
+                       return
+               }
+               if ok, err := tenant.IsResourceAuthorizedToUser(dsTenantID, 
*user, dbx); !ok {
+                       handleErrs(http.StatusUnauthorized, 
errors.New("unauthorized"))
+                       return
+               } else if err != nil {
+                       log.Errorln("checking tenancy: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+
+               result, err := tx.Exec(`DELETE FROM deliveryservice_regex WHERE 
deliveryservice = $1 and regex = $2`, dsID, regexID)
+               if err != nil {
+                       log.Errorln("deliveryservicesregexes.Delete deleting 
delivery service regexes: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               rowsAffected, err := result.RowsAffected()
+               if err != nil {
+                       log.Errorln("deliveryservicesregexes.Delete delete 
error: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               if rowsAffected != 1 {
+                       if rowsAffected < 1 {
+                               handleErrs(http.StatusNotFound, errors.New("not 
found"))
+                               return
+                       }
+                       log.Errorf("this create affected too many rows: %d", 
rowsAffected)
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+
+               log.Debugf("changelog for delete on object")
+               api.CreateChangeLogMsg(api.ApiChange, *user, dbx, 
fmt.Sprintf(`deleted deliveryservice_regex {"ds": %d, "regex": %d}`, dsID, 
regexID))
+               resp := struct {
+                       tc.Alerts
+               }{tc.CreateAlerts(tc.SuccessLevel, "deliveryservice_regex was 
deleted.")}
+               respBts, err := json.Marshal(resp)
+               if err != nil {
+                       log.Errorln("deliveryservicesregexes.Delete creating 
JSON: " + err.Error())
+                       handleErrs(http.StatusInternalServerError, 
errors.New("server error"))
+                       return
+               }
+               w.Header().Set(tc.ContentType, tc.ApplicationJson)
+               w.Write(respBts)
+               commitTx = true
+       }
+}
+
+// FinishTx commits the transaction if commit is true when it's called, 
otherwise it rolls back the transaction. This is designed to be called in a 
defer.
+func FinishTx(tx *sql.Tx, commit *bool) {
+       if tx == nil {
+               return
+       }
+       if !*commit {
+               tx.Rollback()
+               return
+       }
+       tx.Commit()
+}
diff --git a/traffic_ops/traffic_ops_golang/routes.go 
b/traffic_ops/traffic_ops_golang/routes.go
index 3437de1b8..b36fbcef5 100644
--- a/traffic_ops/traffic_ops_golang/routes.go
+++ b/traffic_ops/traffic_ops_golang/routes.go
@@ -38,8 +38,9 @@ import (
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/coordinate"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/crconfig"
        dsrequest 
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice/request"
-       dsserver 
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice/servers"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice/request/comment"
+       dsserver 
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice/servers"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservicesregexes"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/division"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/hwinfo"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/parameter"
@@ -151,7 +152,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, 
http.Handler, error) {
                {1.1, http.MethodDelete, `regions/{id}$`, 
api.DeleteHandler(region.GetRefType(), d.DB), auth.PrivLevelOperations, 
Authenticated, nil},
 
                // get all edge servers associated with a delivery service 
(from deliveryservice_server table)
-               {1.1, http.MethodGet, `deliveryservices/{id}/servers$`, 
api.ReadHandler(dsserver.GetRefType(), d.DB),auth.PrivLevelReadOnly, 
Authenticated, nil},
+               {1.1, http.MethodGet, `deliveryservices/{id}/servers$`, 
api.ReadHandler(dsserver.GetRefType(), d.DB), auth.PrivLevelReadOnly, 
Authenticated, nil},
 
                //Server
                {1.1, http.MethodGet, `servers/checks$`, 
handlerToFunc(proxyHandler), 0, NoAuth, []Middleware{}},
@@ -221,6 +222,14 @@ func Routes(d ServerData) ([]Route, []RawRoute, 
http.Handler, error) {
                {1.3, http.MethodPost, `roles/?$`, 
api.CreateHandler(role.GetRefType(), d.DB), auth.PrivLevelAdmin, Authenticated, 
nil},
                {1.3, http.MethodDelete, `roles/?$`, 
api.DeleteHandler(role.GetRefType(), d.DB), auth.PrivLevelAdmin, Authenticated, 
nil},
 
+               //Delivery Services Regexes
+               {1.1, http.MethodGet, `deliveryservices_regexes/?(\.json)?$`, 
deliveryservicesregexes.Get(d.DB), auth.PrivLevelReadOnly, Authenticated, nil},
+               {1.1, http.MethodGet, 
`deliveryservices/{dsid}/regexes/?(\.json)?$`, 
deliveryservicesregexes.DSGet(d.DB), auth.PrivLevelReadOnly, Authenticated, 
nil},
+               {1.1, http.MethodGet, 
`deliveryservices/{dsid}/regexes/{regexid}?(\.json)?$`, 
deliveryservicesregexes.DSGetID(d.DB), auth.PrivLevelReadOnly, Authenticated, 
nil},
+               {1.1, http.MethodPost, 
`deliveryservices/{dsid}/regexes/?(\.json)?$`, 
deliveryservicesregexes.Post(d.DB), auth.PrivLevelOperations, Authenticated, 
nil},
+               {1.1, http.MethodPut, 
`deliveryservices/{dsid}/regexes/{regexid}?(\.json)?$`, 
deliveryservicesregexes.Put(d.DB), auth.PrivLevelOperations, Authenticated, 
nil},
+               {1.1, http.MethodDelete, 
`deliveryservices/{dsid}/regexes/{regexid}?(\.json)?$`, 
deliveryservicesregexes.Delete(d.DB), auth.PrivLevelOperations, Authenticated, 
nil},
+
                //Servers
                {1.3, http.MethodPost, `servers/{id}/deliveryservices$`, 
server.AssignDeliveryServicesToServerHandler(d.DB), auth.PrivLevelOperations, 
Authenticated, nil},
                {1.3, http.MethodGet, `servers/{host_name}/update_status$`, 
server.GetServerUpdateStatusHandler(d.DB), auth.PrivLevelReadOnly, 
Authenticated, nil},


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to