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

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

commit 77464b59890693698208829f81afdd5b28f5d487
Author: Dewayne Richardson <dewr...@apache.org>
AuthorDate: Mon Feb 19 14:40:38 2018 -0700

    updated to use the CRUD interface
---
 traffic_ops/traffic_ops_golang/region/regions.go   | 325 +++++++++++++++++++++
 .../{ => region}/regions_test.go                   |   2 +-
 traffic_ops/traffic_ops_golang/regions.go          | 122 --------
 traffic_ops/traffic_ops_golang/routes.go           |  12 +-
 4 files changed, 334 insertions(+), 127 deletions(-)

diff --git a/traffic_ops/traffic_ops_golang/region/regions.go 
b/traffic_ops/traffic_ops_golang/region/regions.go
new file mode 100644
index 0000000..cc9ed61
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/region/regions.go
@@ -0,0 +1,325 @@
+package region
+
+/*
+ * 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 (
+       "errors"
+       "fmt"
+
+       "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/dbhelpers"
+       "github.com/jmoiron/sqlx"
+       "github.com/lib/pq"
+)
+
+//we need a type alias to define functions on
+type TORegion tc.Region
+
+//the refType is passed into the handlers where a copy of its type is used to 
decode the json.
+var refType = TORegion(tc.Region{})
+
+func GetRefType() *TORegion {
+       return &refType
+}
+
+//Implementation of the Identifier, Validator interface functions
+func (region *TORegion) GetID() int {
+       return region.ID
+}
+
+func (region *TORegion) GetAuditName() string {
+       return region.Name
+}
+
+func (region *TORegion) GetType() string {
+       return "region"
+}
+
+func (region *TORegion) SetID(i int) {
+       region.ID = i
+}
+
+func (region *TORegion) Validate(db *sqlx.DB) []error {
+       errs := []error{}
+       if len(region.Name) < 1 {
+               errs = append(errs, errors.New(`Region 'name' is required.`))
+       }
+       return errs
+}
+
+func (region *TORegion) Read(db *sqlx.DB, parameters map[string]string, user 
auth.CurrentUser) ([]interface{}, []error, tc.ApiErrorType) {
+       var rows *sqlx.Rows
+
+       // Query Parameters to Database Query column mappings
+       // see the fields mapped in the SQL query
+       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
+               "domainName":    dbhelpers.WhereColumnInfo{"domain_name", nil},
+               "dnssecEnabled": dbhelpers.WhereColumnInfo{"dnssec_enabled", 
nil},
+               "id":            dbhelpers.WhereColumnInfo{"id", api.IsInt},
+               "name":          dbhelpers.WhereColumnInfo{"name", nil},
+       }
+       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(parameters, queryParamsToQueryCols)
+       if len(errs) > 0 {
+               return nil, errs, tc.DataConflictError
+       }
+
+       query := selectRegionsQuery() + where + orderBy
+       log.Debugln("Query is ", query)
+
+       rows, err := db.NamedQuery(query, queryValues)
+       if err != nil {
+               log.Errorf("Error querying Regions: %v", err)
+               return nil, []error{tc.DBError}, tc.SystemError
+       }
+       defer rows.Close()
+
+       Regions := []interface{}{}
+       for rows.Next() {
+               var s tc.Region
+               if err = rows.StructScan(&s); err != nil {
+                       log.Errorf("error parsing Region rows: %v", err)
+                       return nil, []error{tc.DBError}, tc.SystemError
+               }
+               Regions = append(Regions, s)
+       }
+
+       return Regions, []error{}, tc.NoError
+}
+
+func selectRegionsQuery() string {
+       query := `SELECT
+description,
+division,
+id,
+last_updated,
+name
+
+FROM region r`
+       return query
+}
+
+//The TORegion implementation of the Updater interface
+//all implementations of Updater should use transactions and return the proper 
errorType
+//ParsePQUniqueConstraintError is used to determine if a region with 
conflicting values exists
+//if so, it will return an errorType of DataConflict and the type should be 
appended to the
+//generic error message returned
+func (region *TORegion) Update(db *sqlx.DB, user auth.CurrentUser) (error, 
tc.ApiErrorType) {
+       rollbackTransaction := true
+       tx, err := db.Beginx()
+       defer func() {
+               if tx == nil || !rollbackTransaction {
+                       return
+               }
+               err := tx.Rollback()
+               if err != nil {
+                       log.Errorln(errors.New("rolling back transaction: " + 
err.Error()))
+               }
+       }()
+
+       if err != nil {
+               log.Error.Printf("could not begin transaction: %v", err)
+               return tc.DBError, tc.SystemError
+       }
+       log.Debugf("about to run exec query: %s with region: %++v", 
updateQuery(), region)
+       resultRows, err := tx.NamedQuery(updateQuery(), region)
+       if err != nil {
+               if pqErr, ok := err.(*pq.Error); ok {
+                       err, eType := 
dbhelpers.ParsePQUniqueConstraintError(pqErr)
+                       if eType == tc.DataConflictError {
+                               return errors.New("a region with " + 
err.Error()), eType
+                       }
+                       return err, eType
+               } else {
+                       log.Errorf("received error: %++v from update 
execution", err)
+                       return tc.DBError, tc.SystemError
+               }
+       }
+       defer resultRows.Close()
+
+       var lastUpdated tc.Time
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := resultRows.Scan(&lastUpdated); err != nil {
+                       log.Error.Printf("could not scan lastUpdated from 
insert: %s\n", err)
+                       return tc.DBError, tc.SystemError
+               }
+       }
+       log.Debugf("lastUpdated: %++v", lastUpdated)
+       region.LastUpdated = lastUpdated
+       if rowsAffected != 1 {
+               if rowsAffected < 1 {
+                       return errors.New("no region found with this id"), 
tc.DataMissingError
+               } else {
+                       return fmt.Errorf("this update affected too many rows: 
%d", rowsAffected), tc.SystemError
+               }
+       }
+       err = tx.Commit()
+       if err != nil {
+               log.Errorln("Could not commit transaction: ", err)
+               return tc.DBError, tc.SystemError
+       }
+       rollbackTransaction = false
+       return nil, tc.NoError
+}
+
+//The TORegion implementation of the Inserter interface
+//all implementations of Inserter should use transactions and return the 
proper errorType
+//ParsePQUniqueConstraintError is used to determine if a region with 
conflicting values exists
+//if so, it will return an errorType of DataConflict and the type should be 
appended to the
+//generic error message returned
+//The insert sql returns the id and lastUpdated values of the newly inserted 
region and have
+//to be added to the struct
+func (region *TORegion) Insert(db *sqlx.DB, user auth.CurrentUser) (error, 
tc.ApiErrorType) {
+       rollbackTransaction := true
+       tx, err := db.Beginx()
+       defer func() {
+               if tx == nil || !rollbackTransaction {
+                       return
+               }
+               err := tx.Rollback()
+               if err != nil {
+                       log.Errorln(errors.New("rolling back transaction: " + 
err.Error()))
+               }
+       }()
+
+       if err != nil {
+               log.Error.Printf("could not begin transaction: %v", err)
+               return tc.DBError, tc.SystemError
+       }
+       resultRows, err := tx.NamedQuery(insertQuery(), region)
+       if err != nil {
+               if pqErr, ok := err.(*pq.Error); ok {
+                       err, eType := 
dbhelpers.ParsePQUniqueConstraintError(pqErr)
+                       if eType == tc.DataConflictError {
+                               return errors.New("a region with " + 
err.Error()), eType
+                       }
+                       return err, eType
+               } else {
+                       log.Errorf("received non pq error: %++v from create 
execution", err)
+                       return tc.DBError, tc.SystemError
+               }
+       }
+       defer resultRows.Close()
+
+       var id int
+       var lastUpdated tc.Time
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := resultRows.Scan(&id, &lastUpdated); err != nil {
+                       log.Error.Printf("could not scan id from insert: %s\n", 
err)
+                       return tc.DBError, tc.SystemError
+               }
+       }
+       if rowsAffected == 0 {
+               err = errors.New("no region was inserted, no id was returned")
+               log.Errorln(err)
+               return tc.DBError, tc.SystemError
+       } else if rowsAffected > 1 {
+               err = errors.New("too many ids returned from region insert")
+               log.Errorln(err)
+               return tc.DBError, tc.SystemError
+       }
+       region.SetID(id)
+       region.LastUpdated = lastUpdated
+       err = tx.Commit()
+       if err != nil {
+               log.Errorln("Could not commit transaction: ", err)
+               return tc.DBError, tc.SystemError
+       }
+       rollbackTransaction = false
+       return nil, tc.NoError
+}
+
+//The Region implementation of the Deleter interface
+//all implementations of Deleter should use transactions and return the proper 
errorType
+func (region *TORegion) Delete(db *sqlx.DB, user auth.CurrentUser) (error, 
tc.ApiErrorType) {
+       rollbackTransaction := true
+       tx, err := db.Beginx()
+       defer func() {
+               if tx == nil || !rollbackTransaction {
+                       return
+               }
+               err := tx.Rollback()
+               if err != nil {
+                       log.Errorln(errors.New("rolling back transaction: " + 
err.Error()))
+               }
+       }()
+
+       if err != nil {
+               log.Error.Printf("could not begin transaction: %v", err)
+               return tc.DBError, tc.SystemError
+       }
+       log.Debugf("about to run exec query: %s with region: %++v", 
deleteQuery(), region)
+       result, err := tx.NamedExec(deleteQuery(), region)
+       if err != nil {
+               log.Errorf("received error: %++v from delete execution", err)
+               return tc.DBError, tc.SystemError
+       }
+       rowsAffected, err := result.RowsAffected()
+       if err != nil {
+               return tc.DBError, tc.SystemError
+       }
+       if rowsAffected != 1 {
+               if rowsAffected < 1 {
+                       return errors.New("no region with that id found"), 
tc.DataMissingError
+               } else {
+                       return fmt.Errorf("this create affected too many rows: 
%d", rowsAffected), tc.SystemError
+               }
+       }
+       err = tx.Commit()
+       if err != nil {
+               log.Errorln("Could not commit transaction: ", err)
+               return tc.DBError, tc.SystemError
+       }
+       rollbackTransaction = false
+       return nil, tc.NoError
+}
+
+func updateQuery() string {
+       query := `UPDATE
+region SET
+description=:description,
+division=:division,
+name=:name
+WHERE id=:id RETURNING last_updated`
+       return query
+}
+
+func insertQuery() string {
+       query := `INSERT INTO region (
+description,
+division,
+name) VALUES (
+:description,
+:division,
+:name) RETURNING id,last_updated`
+       return query
+}
+
+func deleteQuery() string {
+       query := `DELETE FROM region
+WHERE id=:id`
+       return query
+}
diff --git a/traffic_ops/traffic_ops_golang/regions_test.go 
b/traffic_ops/traffic_ops_golang/region/regions_test.go
similarity index 99%
rename from traffic_ops/traffic_ops_golang/regions_test.go
rename to traffic_ops/traffic_ops_golang/region/regions_test.go
index 1b18d75..b4fac20 100644
--- a/traffic_ops/traffic_ops_golang/regions_test.go
+++ b/traffic_ops/traffic_ops_golang/region/regions_test.go
@@ -1,4 +1,4 @@
-package main
+package region
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
diff --git a/traffic_ops/traffic_ops_golang/regions.go 
b/traffic_ops/traffic_ops_golang/regions.go
deleted file mode 100644
index 66e06ef..0000000
--- a/traffic_ops/traffic_ops_golang/regions.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package main
-
-/*
- * 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 (
-       "encoding/json"
-       "fmt"
-       "net/http"
-
-       "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/dbhelpers"
-       "github.com/jmoiron/sqlx"
-)
-
-func regionsHandler(db *sqlx.DB) http.HandlerFunc {
-       return func(w http.ResponseWriter, r *http.Request) {
-               handleErrs := tc.GetHandleErrorsFunc(w, r)
-
-               params, err := api.GetCombinedParams(r)
-               if err != nil {
-                       log.Errorf("unable to get parameters from request: %s", 
err)
-                       handleErrs(http.StatusInternalServerError, err)
-               }
-
-               resp, errs, errType := getRegionsResponse(params, db)
-               if len(errs) > 0 {
-                       tc.HandleErrorsWithType(errs, errType, handleErrs)
-                       return
-               }
-
-               respBts, err := json.Marshal(resp)
-               if err != nil {
-                       handleErrs(http.StatusInternalServerError, err)
-                       return
-               }
-
-               w.Header().Set("Content-Type", "application/json")
-               fmt.Fprintf(w, "%s", respBts)
-       }
-}
-
-func getRegionsResponse(params map[string]string, db *sqlx.DB) 
(*tc.RegionsResponse, []error, tc.ApiErrorType) {
-       regions, errs, errType := getRegions(params, db)
-       if len(errs) > 0 {
-               return nil, errs, errType
-       }
-
-       resp := tc.RegionsResponse{
-               Response: regions,
-       }
-       return &resp, nil, tc.NoError
-}
-
-func getRegions(params map[string]string, db *sqlx.DB) ([]tc.Region, []error, 
tc.ApiErrorType) {
-       var rows *sqlx.Rows
-       var err error
-
-       // Query Parameters to Database Query column mappings
-       // see the fields mapped in the SQL query
-       queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{
-               "division": dbhelpers.WhereColumnInfo{"d.id", api.IsInt},
-               "id":       dbhelpers.WhereColumnInfo{"r.id", api.IsInt},
-               "name":     dbhelpers.WhereColumnInfo{"r.name", nil},
-       }
-
-       where, orderBy, queryValues, errs := 
dbhelpers.BuildWhereAndOrderBy(params, queryParamsToQueryCols)
-       if len(errs) > 0 {
-               return nil, errs, tc.DataConflictError
-       }
-
-       query := selectRegionsQuery() + where + orderBy
-       log.Debugln("Query is ", query)
-
-       rows, err = db.NamedQuery(query, queryValues)
-       if err != nil {
-               return nil, []error{err}, tc.SystemError
-       }
-       defer rows.Close()
-
-       regions := []tc.Region{}
-       for rows.Next() {
-               var s tc.Region
-               if err = rows.StructScan(&s); err != nil {
-                       return nil, []error{fmt.Errorf("getting regions: %v", 
err)}, tc.SystemError
-               }
-               regions = append(regions, s)
-       }
-       return regions, nil, tc.NoError
-}
-
-func selectRegionsQuery() string {
-
-       query := `SELECT
-r.division,
-d.name as divisionname,
-r.id,
-r.last_updated,
-r.name
-
-FROM region r
-JOIN division d ON r.division = d.id`
-       return query
-}
diff --git a/traffic_ops/traffic_ops_golang/routes.go 
b/traffic_ops/traffic_ops_golang/routes.go
index b59d92b..a61c015 100644
--- a/traffic_ops/traffic_ops_golang/routes.go
+++ b/traffic_ops/traffic_ops_golang/routes.go
@@ -35,6 +35,7 @@ import (
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/cdn"
        dsrequest 
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice/request"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/division"
+       
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/region"
        
"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/status"
        "github.com/basho/riak-go-client"
 )
@@ -110,13 +111,16 @@ func Routes(d ServerData) ([]Route, http.Handler, error) {
                //HwInfo
                {1.2, http.MethodGet, `hwinfo-wip/?(\.json)?$`, 
hwInfoHandler(d.DB), auth.PrivLevelReadOnly, Authenticated, nil},
 
+               //Regions
+               {1.3, http.MethodGet, `regions/?(\.json)?$`, 
api.ReadHandler(region.GetRefType(), d.DB), auth.PrivLevelReadOnly, 
Authenticated, nil},
+               {1.3, http.MethodGet, `regions/{id}$`, 
api.ReadHandler(region.GetRefType(), d.DB), auth.PrivLevelReadOnly, 
Authenticated, nil},
+               {1.3, http.MethodPut, `regions/{id}$`, 
api.UpdateHandler(region.GetRefType(), d.DB), auth.PrivLevelOperations, 
Authenticated, nil},
+               {1.3, http.MethodPost, `regions/?$`, 
api.CreateHandler(region.GetRefType(), d.DB), auth.PrivLevelOperations, 
Authenticated, nil},
+               {1.3, http.MethodDelete, `regions/{id}$`, 
api.DeleteHandler(region.GetRefType(), d.DB), auth.PrivLevelOperations, 
Authenticated, nil},
+
                //Parameters
                {1.3, http.MethodGet, `parameters/?(\.json)?$`, 
parametersHandler(d.DB), auth.PrivLevelReadOnly, Authenticated, nil},
 
-               //Regions
-               {1.2, http.MethodGet, `regions/?(\.json)?$`, 
regionsHandler(d.DB), auth.PrivLevelReadOnly, Authenticated, nil},
-               {1.2, http.MethodGet, `regions/{id}$`, regionsHandler(d.DB), 
auth.PrivLevelReadOnly, Authenticated, nil},
-
                //Servers
                // explicitly passed to legacy system until fully implemented.  
Auth handled by legacy system.
                {1.2, http.MethodGet, `servers/checks$`, 
handlerToFunc(proxyHandler), 0, NoAuth, []Middleware{}},

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

Reply via email to