From 65715483fbe250059ec83c754ac5b90b9c998279 Mon Sep 17 00:00:00 2001 From: Jenna Hunte Date: Tue, 10 Mar 2020 13:10:06 -0600 Subject: [PATCH 01/44] add service category to TP and TO --- lib/go-tc/deliveryservices.go | 2 + lib/go-tc/service_category.go | 60 ++++++ ...0_add_deliveryservice_service_category.sql | 25 +++ traffic_ops/app/db/seeds.sql | 5 + traffic_ops/client/serviceCategory.go | 132 ++++++++++++++ .../deliveryservice/deliveryservices.go | 22 ++- .../traffic_ops_golang/routing/routes.go | 13 +- .../servicecategory/servicecategories.go | 124 +++++++++++++ traffic_portal/app/src/app.js | 10 + .../src/common/api/ServiceCategoryService.js | 88 +++++++++ traffic_portal/app/src/common/api/index.js | 1 + .../FormDeliveryServiceController.js | 12 +- .../form.deliveryService.DNS.tpl.html | 16 ++ .../form.deliveryService.HTTP.tpl.html | 16 ++ .../form.deliveryService.Steering.tpl.html | 16 ++ .../form.deliveryService.anyMap.tpl.html | 16 ++ .../FormServiceCategoryController.js | 39 ++++ .../edit/FormEditServiceCategoryController.js | 72 ++++++++ .../form/serviceCategory/edit/index.js | 21 +++ .../form.serviceCategory.tpl.html | 48 +++++ .../modules/form/serviceCategory/index.js | 21 +++ .../new/FormNewServiceCategoryController.js | 39 ++++ .../modules/form/serviceCategory/new/index.js | 21 +++ .../modules/navigation/navigation.tpl.html | 1 + .../table.cdnDeliveryServices.tpl.html | 2 + .../TableDeliveryServicesController.js | 1 + .../table.deliveryServices.tpl.html | 2 + .../table.profileDeliveryServices.tpl.html | 2 + .../table.serverDeliveryServices.tpl.html | 2 + .../TableServiceCategoriesController.js | 47 +++++ .../modules/table/serviceCategories/index.js | 21 +++ .../table.serviceCategories.tpl.html | 47 +++++ ...rviceCategoryDeliveryServicesController.js | 55 ++++++ .../serviceCategoryDeliveryServices/index.js | 22 +++ ...e.serviceCategoryDeliveryServices.tpl.html | 171 ++++++++++++++++++ .../table.tenantDeliveryServices.tpl.html | 2 + .../table.typeDeliveryServices.tpl.html | 2 + .../deliveryServices/index.js | 42 +++++ .../private/serviceCategories/edit/index.js | 39 ++++ .../private/serviceCategories/index.js | 34 ++++ .../private/serviceCategories/list/index.js | 39 ++++ .../private/serviceCategories/new/index.js | 39 ++++ .../serviceCategories.tpl.html | 22 +++ 43 files changed, 1402 insertions(+), 9 deletions(-) create mode 100644 lib/go-tc/service_category.go create mode 100644 traffic_ops/app/db/migrations/20200315000000_add_deliveryservice_service_category.sql create mode 100644 traffic_ops/client/serviceCategory.go create mode 100644 traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go create mode 100644 traffic_portal/app/src/common/api/ServiceCategoryService.js create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/FormServiceCategoryController.js create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/edit/FormEditServiceCategoryController.js create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/edit/index.js create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/form.serviceCategory.tpl.html create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/index.js create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/new/FormNewServiceCategoryController.js create mode 100644 traffic_portal/app/src/common/modules/form/serviceCategory/new/index.js create mode 100644 traffic_portal/app/src/common/modules/table/serviceCategories/TableServiceCategoriesController.js create mode 100644 traffic_portal/app/src/common/modules/table/serviceCategories/index.js create mode 100644 traffic_portal/app/src/common/modules/table/serviceCategories/table.serviceCategories.tpl.html create mode 100644 traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/TableServiceCategoryDeliveryServicesController.js create mode 100644 traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/index.js create mode 100644 traffic_portal/app/src/common/modules/table/serviceCategoryDeliveryServices/table.serviceCategoryDeliveryServices.tpl.html create mode 100644 traffic_portal/app/src/modules/private/serviceCategories/deliveryServices/index.js create mode 100644 traffic_portal/app/src/modules/private/serviceCategories/edit/index.js create mode 100644 traffic_portal/app/src/modules/private/serviceCategories/index.js create mode 100644 traffic_portal/app/src/modules/private/serviceCategories/list/index.js create mode 100644 traffic_portal/app/src/modules/private/serviceCategories/new/index.js create mode 100644 traffic_portal/app/src/modules/private/serviceCategories/serviceCategories.tpl.html diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go index 3a75e4b99e..53c7f9c138 100644 --- a/lib/go-tc/deliveryservices.go +++ b/lib/go-tc/deliveryservices.go @@ -167,6 +167,8 @@ type DeliveryServiceNullable struct { FirstHeaderRewrite *string `json:"firstHeaderRewrite" db:"first_header_rewrite"` InnerHeaderRewrite *string `json:"innerHeaderRewrite" db:"inner_header_rewrite"` LastHeaderRewrite *string `json:"lastHeaderRewrite" db:"last_header_rewrite"` + ServiceCategoryId *int `json:"serviceCategory" db:"service_category"` + ServiceCategoryName *string `json:"serviceCategoryName"` } type DeliveryServiceNullableV15 struct { diff --git a/lib/go-tc/service_category.go b/lib/go-tc/service_category.go new file mode 100644 index 0000000000..8ae460675a --- /dev/null +++ b/lib/go-tc/service_category.go @@ -0,0 +1,60 @@ +package tc + +/* + * 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. + */ + +// ServiceCategoriesResponse is a list of Service Categories as a response. +// swagger:response ServiceCategoriesResponse +type ServiceCategoriesResponse struct { + // in: body + Response []ServiceCategory `json:"response"` +} + +// ServiceCategoryResponse is a single Service Category response for Update and Create to +// depict what changed. +// swagger:response ServiceCategoryResponse +// in: body +type ServiceCategoryResponse struct { + // in: body + Response ServiceCategory `json:"response"` +} + +// ServiceCategory ... +type ServiceCategory struct { + + // ServiceCategory ID + // + ID int `json:"id" db:"id"` + + // LastUpdated + // + LastUpdated TimeNoMod `json:"lastUpdated" db:"last_updated"` + + // Division Name + // + // required: true + Name string `json:"name" db:"name"` +} + +// ServiceCategoryNullable is a nullable struct that holds info about a service category +type ServiceCategoryNullable struct { + ID *int `json:"id" db:"id"` + LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` + Name *string `json:"name" db:"name"` +} diff --git a/traffic_ops/app/db/migrations/20200315000000_add_deliveryservice_service_category.sql b/traffic_ops/app/db/migrations/20200315000000_add_deliveryservice_service_category.sql new file mode 100644 index 0000000000..79f670b89d --- /dev/null +++ b/traffic_ops/app/db/migrations/20200315000000_add_deliveryservice_service_category.sql @@ -0,0 +1,25 @@ +/* + Licensed 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. +*/ + +-- +goose Up +-- SQL in section 'Up' is executed when this migration is applied +ALTER TABLE deliveryservice ADD COLUMN service_category int; +CREATE TABLE IF NOT EXISTS service_category ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + last_updated TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL + ); + +-- +goose Down +-- SQL section 'Down' is executed when this migration is rolled back +ALTER TABLE deliveryservice DROP COLUMN service_category; +DROP TABLE service_category; diff --git a/traffic_ops/app/db/seeds.sql b/traffic_ops/app/db/seeds.sql index c301417456..ddd6522291 100644 --- a/traffic_ops/app/db/seeds.sql +++ b/traffic_ops/app/db/seeds.sql @@ -175,6 +175,9 @@ insert into capability (name, description) values ('server-capabilities-write', -- servers insert into capability (name, description) values ('servers-read', 'Ability to view servers') ON CONFLICT (name) DO NOTHING; insert into capability (name, description) values ('servers-write', 'Ability to edit servers') ON CONFLICT (name) DO NOTHING; +-- service categories +insert into capability (name, description) values ('service-categories-read', 'Ability to view service categories') ON CONFLICT (name) DO NOTHING; +insert into capability (name, description) values ('service-categories-write', 'Ability to edit service categories') ON CONFLICT (name) DO NOTHING; -- stats insert into capability (name, description) values ('stats-read', 'Ability to view cache stats') ON CONFLICT (name) DO NOTHING; insert into capability (name, description) values ('stats-write', 'Ability to edit cache stats') ON CONFLICT (name) DO NOTHING; @@ -262,6 +265,8 @@ insert into role_capability (role_id, cap_name) values ((select id from role whe insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'server-capabilities-write') ON CONFLICT (role_id, cap_name) DO NOTHING; insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'servers-read') ON CONFLICT (role_id, cap_name) DO NOTHING; insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'servers-write') ON CONFLICT (role_id, cap_name) DO NOTHING; +insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'service-categories-read') ON CONFLICT (role_id, cap_name) DO NOTHING; +insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'service-categories-write') ON CONFLICT (role_id, cap_name) DO NOTHING; insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'stats-read') ON CONFLICT (role_id, cap_name) DO NOTHING; insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'stats-write') ON CONFLICT (role_id, cap_name) DO NOTHING; insert into role_capability (role_id, cap_name) values ((select id from role where name='admin'), 'statuses-read') ON CONFLICT (role_id, cap_name) DO NOTHING; diff --git a/traffic_ops/client/serviceCategory.go b/traffic_ops/client/serviceCategory.go new file mode 100644 index 0000000000..e522e293c5 --- /dev/null +++ b/traffic_ops/client/serviceCategory.go @@ -0,0 +1,132 @@ +/* + + Licensed 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. +*/ + +package client + +import ( + "encoding/json" + "fmt" + "net" + "net/http" + + "github.com/apache/trafficcontrol/lib/go-tc" +) + +const ( + API_serviceCategories = apiBase + "/servicecategories" +) + +// Create a service category +func (to *Session) CreateServiceCategory(serviceCategory tc.ServiceCategory) (tc.Alerts, ReqInf, error) { + + var remoteAddr net.Addr + reqBody, err := json.Marshal(serviceCategory) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return tc.Alerts{}, reqInf, err + } + resp, remoteAddr, err := to.request(http.MethodPost, API_serviceCategories, reqBody) + if err != nil { + return tc.Alerts{}, reqInf, err + } + defer resp.Body.Close() + var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) + return alerts, reqInf, nil +} + +// Update a service category by ID +func (to *Session) UpdateServiceCategoryByID(id int, serviceCategory tc.ServiceCategory) (tc.Alerts, ReqInf, error) { + + var remoteAddr net.Addr + reqBody, err := json.Marshal(serviceCategory) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return tc.Alerts{}, reqInf, err + } + route := fmt.Sprintf("%s/%d", API_serviceCategories, id) + resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody) + if err != nil { + return tc.Alerts{}, reqInf, err + } + defer resp.Body.Close() + var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) + return alerts, reqInf, nil +} + +// Returns a list of service categories +func (to *Session) GetServiceCategories() ([]tc.ServiceCategory, ReqInf, error) { + resp, remoteAddr, err := to.request(http.MethodGet, API_serviceCategories, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return nil, reqInf, err + } + defer resp.Body.Close() + + var data tc.ServiceCategoriesResponse + err = json.NewDecoder(resp.Body).Decode(&data) + return data.Response, reqInf, nil +} + +// GET a service category by the service category id +func (to *Session) GetServiceCategoryByID(id int) ([]tc.ServiceCategory, ReqInf, error) { + route := fmt.Sprintf("%s?id=%d", API_serviceCategories, id) + resp, remoteAddr, err := to.request(http.MethodGet, route, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return nil, reqInf, err + } + defer resp.Body.Close() + + var data tc.ServiceCategoriesResponse + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return nil, reqInf, err + } + + return data.Response, reqInf, nil +} + +// GET a service category by the service category name +func (to *Session) GetserviceCategoryByName(name string) ([]tc.ServiceCategory, ReqInf, error) { + url := fmt.Sprintf("%s?name=%s", API_serviceCategories, name) + resp, remoteAddr, err := to.request(http.MethodGet, url, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return nil, reqInf, err + } + defer resp.Body.Close() + + var data tc.ServiceCategoriesResponse + if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { + return nil, reqInf, err + } + + return data.Response, reqInf, nil +} + +// DELETE a service category by service category id +func (to *Session) DeleteServiceCategoryByID(id int) (tc.Alerts, ReqInf, error) { + route := fmt.Sprintf("%s/%d", API_serviceCategories, id) + resp, remoteAddr, err := to.request(http.MethodDelete, route, nil) + reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + if err != nil { + return tc.Alerts{}, reqInf, err + } + defer resp.Body.Close() + var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) + return alerts, reqInf, nil +} diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go index 4ecba43fd4..bb1f9e8306 100644 --- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go +++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go @@ -313,6 +313,7 @@ func createV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS t &ds.RegionalGeoBlocking, &ds.RemapText, &ds.RoutingName, + &ds.ServiceCategoryId, &ds.SigningAlgorithm, &ds.SSLKeyVersion, &ds.TenantID, @@ -709,7 +710,8 @@ SELECT ds.topology, ds.first_header_rewrite, ds.inner_header_rewrite, - ds.last_header_rewrite + ds.last_header_rewrite, + ds.service_category FROM deliveryservice ds WHERE @@ -719,6 +721,7 @@ WHERE &dsV30.FirstHeaderRewrite, &dsV30.InnerHeaderRewrite, &dsV30.LastHeaderRewrite, + &dsV30.ServiceCategoryName, ); err != nil { if err == sql.ErrNoRows { return nil, http.StatusNotFound, fmt.Errorf("delivery service ID %d not found", *dsV30.ID), nil @@ -822,6 +825,7 @@ func updateV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, reqDS * &ds.RegionalGeoBlocking, &ds.RemapText, &ds.RoutingName, + &ds.ServiceCategoryId, &ds.SigningAlgorithm, &ds.SSLKeyVersion, &ds.TenantID, @@ -1009,6 +1013,7 @@ func readGetDeliveryServices(h http.Header, params map[string]string, tx *sqlx.T "tenant": {"ds.tenant_id", api.IsInt}, "signingAlgorithm": {"ds.signing_algorithm", nil}, "topology": {"ds.topology", nil}, + "serviceCategory": {"ds.service_category", api.IsInt}, } where, orderBy, pagination, queryValues, errs := dbhelpers.BuildWhereAndOrderByAndPagination(params, queryParamsToSQLCols) @@ -1256,6 +1261,8 @@ func GetDeliveryServices(query string, queryValues map[string]interface{}, tx *s &ds.RegionalGeoBlocking, &ds.RemapText, &ds.RoutingName, + &ds.ServiceCategoryId, + &ds.ServiceCategoryName, &ds.SigningAlgorithm, &ds.RangeSliceBlockSize, &ds.SSLKeyVersion, @@ -1780,6 +1787,8 @@ ds.regex_remap, ds.regional_geo_blocking, ds.remap_text, ds.routing_name, +ds.service_category, +service_category.name as service_category_name, ds.signing_algorithm, ds.range_slice_block_size, ds.ssl_key_version, @@ -1797,6 +1806,7 @@ JOIN type ON ds.type = type.id JOIN cdn ON ds.cdn_id = cdn.id LEFT JOIN profile ON ds.profile = profile.id LEFT JOIN tenant ON ds.tenant_id = tenant.id +LEFT JOIN service_category ON ds.service_category = service_category.id ` } @@ -1861,8 +1871,9 @@ range_slice_block_size=$54, topology=$55, first_header_rewrite=$56, inner_header_rewrite=$57, -last_header_rewrite=$58 -WHERE id=$59 +last_header_rewrite=$58, +service_category=$59 +WHERE id=$60 RETURNING last_updated ` } @@ -1927,9 +1938,10 @@ ecs_enabled, range_slice_block_size, first_header_rewrite, inner_header_rewrite, -last_header_rewrite +last_header_rewrite, +service_category ) -VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58) +VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59) RETURNING id, last_updated ` } diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go b/traffic_ops/traffic_ops_golang/routing/routes.go index a5e1ba03ee..72bc21320e 100644 --- a/traffic_ops/traffic_ops_golang/routing/routes.go +++ b/traffic_ops/traffic_ops_golang/routing/routes.go @@ -80,6 +80,7 @@ import ( "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/servercapability" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/servercheck" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/servercheck/extensions" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/servicecategory" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/staticdnsentry" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/status" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/steering" @@ -695,6 +696,13 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{2, 0}, http.MethodPost, `server_server_capabilities/?$`, api.CreateHandler(&server.TOServerServerCapability{}), auth.PrivLevelOperations, Authenticated, nil, 2293166834, noPerlBypass}, {api.Version{2, 0}, http.MethodDelete, `server_server_capabilities/?$`, api.DeleteHandler(&server.TOServerServerCapability{}), auth.PrivLevelOperations, Authenticated, nil, 2058714058, noPerlBypass}, + //Service Categories: CRUD + {api.Version{2, 0}, http.MethodGet, `servicecategories/?(\.json)?$`, api.ReadHandler(&servicecategory.TOServiceCategory{}), auth.PrivLevelReadOnly, Authenticated, nil, 1085181543, noPerlBypass}, + {api.Version{2, 0}, http.MethodGet, `servicecategories/{id}$`, api.DeprecatedReadHandler(&servicecategory.TOServiceCategory{}, util.StrPtr("GET /servicecategories with the 'id' parameter")), auth.PrivLevelReadOnly, Authenticated, nil, 1241497903, noPerlBypass}, + {api.Version{2, 0}, http.MethodPut, `servicecategories/{id}$`, api.UpdateHandler(&servicecategory.TOServiceCategory{}), auth.PrivLevelOperations, Authenticated, nil, 306369141, noPerlBypass}, + {api.Version{2, 0}, http.MethodPost, `servicecategories/?$`, api.CreateHandler(&servicecategory.TOServiceCategory{}), auth.PrivLevelOperations, Authenticated, nil, 553713801, noPerlBypass}, + {api.Version{2, 0}, http.MethodDelete, `servicecategories/{id}$`, api.DeleteHandler(&servicecategory.TOServiceCategory{}), auth.PrivLevelOperations, Authenticated, nil, 1325382238, noPerlBypass}, + //Status: CRUD {api.Version{2, 0}, http.MethodGet, `statuses/?$`, api.ReadHandler(&status.TOStatus{}), auth.PrivLevelReadOnly, Authenticated, nil, 2244905656, noPerlBypass}, {api.Version{2, 0}, http.MethodPut, `statuses/{id}$`, api.UpdateHandler(&status.TOStatus{}), auth.PrivLevelOperations, Authenticated, nil, 2207966504, noPerlBypass}, @@ -831,8 +839,9 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { ////DeliveryServices {api.Version{2, 0}, http.MethodGet, `deliveryservices/?$`, api.ReadHandler(&deliveryservice.TODeliveryService{}), auth.PrivLevelReadOnly, Authenticated, nil, 2238317294, noPerlBypass}, - {api.Version{2, 0}, http.MethodPost, `deliveryservices/?$`, deliveryservice.CreateV15, auth.PrivLevelOperations, Authenticated, nil, 206431432, noPerlBypass}, - {api.Version{2, 0}, http.MethodPut, `deliveryservices/{id}/?$`, deliveryservice.UpdateV15, auth.PrivLevelOperations, Authenticated, nil, 2766567527, noPerlBypass}, + {api.Version{2, 0}, http.MethodGet, `deliveryservices/{id}/?$`, api.ReadHandler(&deliveryservice.TODeliveryService{}), auth.PrivLevelReadOnly, Authenticated, nil, 244348195, noPerlBypass}, + {api.Version{2, 0}, http.MethodPost, `deliveryservices/?(\.json)?$`, deliveryservice.CreateV16, auth.PrivLevelOperations, Authenticated, nil, 506431433, noPerlBypass}, + {api.Version{2, 0}, http.MethodPut, `deliveryservices/{id}/?(\.json)?$`, deliveryservice.UpdateV16, auth.PrivLevelOperations, Authenticated, nil, 1766567528, noPerlBypass}, {api.Version{2, 0}, http.MethodPut, `deliveryservices/{id}/safe/?$`, deliveryservice.UpdateSafe, auth.PrivLevelOperations, Authenticated, nil, 247210931, perlBypass}, {api.Version{2, 0}, http.MethodDelete, `deliveryservices/{id}/?$`, api.DeleteHandler(&deliveryservice.TODeliveryService{}), auth.PrivLevelOperations, Authenticated, nil, 222642074, noPerlBypass}, {api.Version{2, 0}, http.MethodGet, `deliveryservices/{id}/servers/eligible/?$`, deliveryservice.GetServersEligible, auth.PrivLevelReadOnly, Authenticated, nil, 274761584, noPerlBypass}, diff --git a/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go b/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go new file mode 100644 index 0000000000..e7e1f341e9 --- /dev/null +++ b/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go @@ -0,0 +1,124 @@ +package servicecategory +/* + * 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 ( +"strconv" +"strings" + +"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" + +validation "github.com/go-ozzo/ozzo-validation" +) + +//we need a type alias to define functions on +type TOServiceCategory struct { + api.APIInfoImpl `json:"-"` + tc.ServiceCategoryNullable +} + +func (v *TOServiceCategory) SetLastUpdated(t tc.TimeNoMod) { v.LastUpdated = &t } +func (v *TOServiceCategory) InsertQuery() string { return insertQuery() } +func (v *TOServiceCategory) NewReadObj() interface{} { return &tc.ServiceCategory{} } +func (v *TOServiceCategory) SelectQuery() string { return selectQuery() } +func (v *TOServiceCategory) ParamColumns() map[string]dbhelpers.WhereColumnInfo { + return map[string]dbhelpers.WhereColumnInfo{ + "id": dbhelpers.WhereColumnInfo{"id", api.IsInt}, + "name": dbhelpers.WhereColumnInfo{"name", nil}, + } +} +func (v *TOServiceCategory) UpdateQuery() string { return updateQuery() } +func (v *TOServiceCategory) DeleteQuery() string { return deleteQuery() } + +func (serviceCategory TOServiceCategory) GetAuditName() string { + if serviceCategory.Name != nil { + return *serviceCategory.Name + } + if serviceCategory.ID != nil { + return strconv.Itoa(*serviceCategory.ID) + } + return "unknown" +} + +func (serviceCategory TOServiceCategory) GetKeyFieldsInfo() []api.KeyFieldInfo { + return []api.KeyFieldInfo{{"id", api.GetIntKey}} +} + +//Implementation of the Identifier, Validator interface functions +func (serviceCategory TOServiceCategory) GetKeys() (map[string]interface{}, bool) { + if serviceCategory.ID == nil { + return map[string]interface{}{"id": 0}, false + } + return map[string]interface{}{"id": *serviceCategory.ID}, true +} + +func (serviceCategory *TOServiceCategory) 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. + serviceCategory.ID = &i +} + +func (serviceCategory TOServiceCategory) GetType() string { + return "serviceCategory" +} + +func (serviceCategory TOServiceCategory) Validate() error { + errs := validation.Errors{ + "name": validation.Validate(serviceCategory.Name, validation.NotNil, validation.Required), + } + return util.JoinErrs(tovalidate.ToErrors(errs)) +} + +func (dv *TOServiceCategory) Create() (error, error, int) { return api.GenericCreate(dv) } +func (dv *TOServiceCategory) Read() ([]interface{}, error, error, int) { + params := dv.APIInfo().Params + // TODO move to router, and do for all endpoints + if strings.HasSuffix(params["name"], ".json") { + params["name"] = params["name"][:len(params["name"])-len(".json")] + } + return api.GenericRead(dv) +} +func (dv *TOServiceCategory) Update() (error, error, int) { return api.GenericUpdate(dv) } +func (dv *TOServiceCategory) Delete() (error, error, int) { return api.GenericDelete(dv) } + +func insertQuery() string { + return `INSERT INTO service_category (name) VALUES (:name) RETURNING id,last_updated` +} + +func selectQuery() string { + return `SELECT +id, +last_updated, +name +FROM service_category` +} + +func updateQuery() string { + return `UPDATE +service_category SET +name=:name +WHERE id=:id RETURNING last_updated` +} + +func deleteQuery() string { + return `DELETE FROM service_category WHERE id=:id` +} diff --git a/traffic_portal/app/src/app.js b/traffic_portal/app/src/app.js index 76627fc7aa..5b39530d5e 100644 --- a/traffic_portal/app/src/app.js +++ b/traffic_portal/app/src/app.js @@ -193,6 +193,11 @@ var trafficPortal = angular.module('trafficPortal', [ require('./modules/private/servers/edit').name, require('./modules/private/servers/new').name, require('./modules/private/servers/list').name, + require('./modules/private/serviceCategories').name, + require('./modules/private/serviceCategories/deliveryServices').name, + require('./modules/private/serviceCategories/edit').name, + require('./modules/private/serviceCategories/list').name, + require('./modules/private/serviceCategories/new').name, require('./modules/private/statuses').name, require('./modules/private/statuses/edit').name, require('./modules/private/statuses/list').name, @@ -321,6 +326,9 @@ var trafficPortal = angular.module('trafficPortal', [ require('./common/modules/form/server').name, require('./common/modules/form/server/edit').name, require('./common/modules/form/server/new').name, + require('./common/modules/form/serviceCategory').name, + require('./common/modules/form/serviceCategory/edit').name, + require('./common/modules/form/serviceCategory/new').name, require('./common/modules/form/status').name, require('./common/modules/form/status/edit').name, require('./common/modules/form/status/new').name, @@ -394,6 +402,8 @@ var trafficPortal = angular.module('trafficPortal', [ require('./common/modules/table/serverServerCapabilities').name, require('./common/modules/table/servers').name, require('./common/modules/table/serverDeliveryServices').name, + require('./common/modules/table/serviceCategories').name, + require('./common/modules/table/serviceCategoryDeliveryServices').name, require('./common/modules/table/statuses').name, require('./common/modules/table/statusServers').name, require('./common/modules/table/tenants').name, diff --git a/traffic_portal/app/src/common/api/ServiceCategoryService.js b/traffic_portal/app/src/common/api/ServiceCategoryService.js new file mode 100644 index 0000000000..b6049db860 --- /dev/null +++ b/traffic_portal/app/src/common/api/ServiceCategoryService.js @@ -0,0 +1,88 @@ +/* + * 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. + */ + +var ServiceCategoryService = function($http, ENV, locationUtils, messageModel) { + + this.getServiceCategories = function(queryParams) { + return $http.get(ENV.api['root'] + 'servicecategories', {params: queryParams}).then( + function(result) { + return result.data.response; + }, + function(err) { + throw err; + } + ); + }; + + this.getServiceCategory = function(id) { + return $http.get(ENV.api['root'] + 'servicecategories', {params: {id: id}}).then( + function(result) { + return result.data.response[0]; + }, + function(err) { + throw err; + } + ); + }; + + this.createServiceCategory = function(serviceCategory) { + return $http.post(ENV.api['root'] + 'servicecategories', serviceCategory).then( + function(result) { + messageModel.setMessages(result.data.alerts, true); + locationUtils.navigateToPath('/servicecategories'); + return result; + }, + function(err) { + messageModel.setMessages(err.data.alerts, false); + throw err; + } + ); + }; + + // todo: change to use query param when it is supported + this.updateServiceCategory = function(serviceCategory) { + return $http.put(ENV.api['root'] + 'servicecategories/' + serviceCategory.id, serviceCategory).then( + function(result) { + messageModel.setMessages(result.data.alerts, false); + return result; }, + function(err) { + messageModel.setMessages(err.data.alerts, false); + throw err; + } + ); + }; + + // todo: change to use query param when it is supported + this.deleteServiceCategory = function(id) { + return $http.delete(ENV.api['root'] + 'servicecategories/' + id).then( + function(result) { + messageModel.setMessages(result.data.alerts, true); + return result; + }, + function(err) { + messageModel.setMessages(err.data.alerts, true); + throw err; + } + ); + }; + +}; + +ServiceCategoryService.$inject = ['$http', 'ENV', 'locationUtils', 'messageModel']; +module.exports = ServiceCategoryService; diff --git a/traffic_portal/app/src/common/api/index.js b/traffic_portal/app/src/common/api/index.js index 079b6d9001..2108739a17 100644 --- a/traffic_portal/app/src/common/api/index.js +++ b/traffic_portal/app/src/common/api/index.js @@ -49,6 +49,7 @@ module.exports = angular.module('trafficPortal.api', []) .service('regionService', require('./RegionService')) .service('serverService', require('./ServerService')) .service('serverCapabilityService', require('./ServerCapabilityService')) + .service('serviceCategoryService', require('./ServiceCategoryService')) .service('staticDnsEntryService', require('./StaticDnsEntryService')) .service('statusService', require('./StatusService')) .service('tenantService', require('./TenantService')) diff --git a/traffic_portal/app/src/common/modules/form/deliveryService/FormDeliveryServiceController.js b/traffic_portal/app/src/common/modules/form/deliveryService/FormDeliveryServiceController.js index 4ccff2412a..be362357de 100644 --- a/traffic_portal/app/src/common/modules/form/deliveryService/FormDeliveryServiceController.js +++ b/traffic_portal/app/src/common/modules/form/deliveryService/FormDeliveryServiceController.js @@ -17,7 +17,7 @@ * under the License. */ -var FormDeliveryServiceController = function(deliveryService, dsCurrent, origin, topologies, type, types, $scope, $location, $uibModal, $window, formUtils, locationUtils, tenantUtils, deliveryServiceUtils, cdnService, profileService, tenantService, propertiesModel, userModel) { +var FormDeliveryServiceController = function(deliveryService, dsCurrent, origin, topologies, type, types, $scope, $location, $uibModal, $window, formUtils, locationUtils, tenantUtils, deliveryServiceUtils, cdnService, profileService, tenantService, propertiesModel, userModel, serviceCategoryService) { var getCDNs = function() { cdnService.getCDNs() @@ -46,6 +46,13 @@ var FormDeliveryServiceController = function(deliveryService, dsCurrent, origin, }); }; + var getServiceCategories = function() { + serviceCategoryService.getServiceCategories() + .then(function(result) { + $scope.serviceCategories = result; + }); + }; + $scope.deliveryService = deliveryService; $scope.showGeneralConfig = true; @@ -306,6 +313,7 @@ var FormDeliveryServiceController = function(deliveryService, dsCurrent, origin, getCDNs(); getProfiles(); getTenants(); + getServiceCategories(); if (!deliveryService.consistentHashQueryParams || deliveryService.consistentHashQueryParams.length < 1) { // add an empty one so the dynamic form widget is visible. empty strings get stripped out on save anyhow. $scope.deliveryService.consistentHashQueryParams = [ '' ]; @@ -315,5 +323,5 @@ var FormDeliveryServiceController = function(deliveryService, dsCurrent, origin, }; -FormDeliveryServiceController.$inject = ['deliveryService', 'dsCurrent', 'origin', 'topologies', 'type', 'types', '$scope', '$location', '$uibModal', '$window', 'formUtils', 'locationUtils', 'tenantUtils', 'deliveryServiceUtils', 'cdnService', 'profileService', 'tenantService', 'propertiesModel', 'userModel']; +FormDeliveryServiceController.$inject = ['deliveryService', 'dsCurrent', 'origin', 'topologies', 'type', 'types', '$scope', '$location', '$uibModal', '$window', 'formUtils', 'locationUtils', 'tenantUtils', 'deliveryServiceUtils', 'cdnService', 'profileService', 'tenantService', 'propertiesModel', 'userModel', 'serviceCategoryService']; module.exports = FormDeliveryServiceController; diff --git a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html index 38d17e82cb..93968b7599 100644 --- a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html +++ b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html @@ -244,6 +244,22 @@

Current Value

+
+ +
+ + View Details   + +
+
+
+ +
+ + View Details   + +
+
+
+ +
+ + View Details   + +
+
+
+ +
+ + View Details   + +
+