You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by oc...@apache.org on 2020/02/10 14:34:52 UTC

[trafficcontrol] branch master updated: TP: Provides the ability to view all users for a given role (#4196)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 72aa282  TP: Provides the ability to view all users for a given role (#4196)
72aa282 is described below

commit 72aa282b3f518d2d5833328f6936d95151bc65e7
Author: Jeremy Mitchell <mi...@users.noreply.github.com>
AuthorDate: Mon Feb 10 07:34:45 2020 -0700

    TP: Provides the ability to view all users for a given role (#4196)
    
    * adds role query param support to users endpoint to enable the ability to view add the users for a given role.
    
    * adds a test for fetching users by role
    
    * adds changelog entry
    
    * fixes variable name
    
    * another c/p error
    
    * better error message
    
    * adds documentation for role query parameter
    
    * sets button type to button
    
    * simplification of GetUsersByRole
    
    * simplifies GetUsers client method
    
    * adds defensive code to role user tests
    
    * more granular tests
    
    * adds versionadded notice
    
    * adds/updates versionadded notices
---
 CHANGELOG.md                                       |  1 +
 docs/source/api/users.rst                          |  7 ++++--
 traffic_ops/client/user.go                         | 25 ++++++++++---------
 traffic_ops/testing/api/v1/user_test.go            | 28 ++++++++++++++++++++++
 traffic_ops/traffic_ops_golang/user/user.go        |  1 +
 .../common/modules/form/role/FormRoleController.js |  8 +++++--
 .../common/modules/form/role/form.role.tpl.html    |  4 ++--
 .../app/src/modules/private/roles/users/index.js   |  4 ++--
 8 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51951ca..c07113a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - Added a boolean to delivery service in Traffic Portal and Traffic Ops to enable EDNS0 client subnet at the delivery service level and include it in the cr-config.
 - Updated Traffic Router to read new EDSN0 client subnet field and route accordingly only for enabled delivery services. When enabled and a subnet is present in the request, the subnet appears in the `chi` field and the resolver address is in the `rhi` field.
 - Added an optimistic quorum feature to Traffic Monitor to prevent false negative states from propagating to downstream components in the event of network isolation.
+- Added the ability to fetch users by role
 - Traffic Ops Golang Endpoints
   - /api/1.1/cachegroupparameters/{{cachegroupID}}/{{parameterID}} `(DELETE)`
   - /api/1.5/to_extensions/:id `(DELETE)`
diff --git a/docs/source/api/users.rst b/docs/source/api/users.rst
index 948d549..755710a 100644
--- a/docs/source/api/users.rst
+++ b/docs/source/api/users.rst
@@ -38,6 +38,8 @@ Request Structure
 	+-----------+----------+------------------------------------------------------------------------------------------+
 	| tenant    | no       | Return only users belonging to the :term:`Tenant` identified by tenant name              |
 	+-----------+----------+------------------------------------------------------------------------------------------+
+	| role      | no       | Return only users belonging to the :term:`Role` identified by role name                  |
+	+-----------+----------+------------------------------------------------------------------------------------------+
 	| username  | no       | Return only the user with this username                                                  |
 	+-----------+----------+------------------------------------------------------------------------------------------+
 	| orderby   | no       | Choose the ordering of the results - must be the name of one of the fields of the        |
@@ -55,8 +57,9 @@ Request Structure
 	|           |          | parameter has no effect. ``limit`` must be defined to make use of ``page``.              |
 	+-----------+----------+------------------------------------------------------------------------------------------+
 
-.. versionadded:: 1.4
-	The ``id`` and ``username`` query parameters were added in the 1.4 API.
+.. versionadded:: ATCv4.1 The ``role`` query parameter was added in version 4.1 of :abbr:`ATC (Apache Traffic Control)`.
+
+.. versionadded:: ATCv4.0 The ``id`` and ``username`` query parameters were added in version 4.0 of :abbr:`ATC (Apache Traffic Control)`.
 
 .. code-block:: http
 	:caption: Request Example
diff --git a/traffic_ops/client/user.go b/traffic_ops/client/user.go
index bbcfbc1..d7f2c0a 100644
--- a/traffic_ops/client/user.go
+++ b/traffic_ops/client/user.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"net/url"
 	"strconv"
 
 	"github.com/apache/trafficcontrol/lib/go-rfc"
@@ -36,20 +37,18 @@ func (to *Session) Users() ([]tc.User, error) {
 
 // GetUsers returns all users accessible from current user
 func (to *Session) GetUsers() ([]tc.User, ReqInf, error) {
-	route := apiBase + "/users.json"
-	resp, remoteAddr, err := to.request("GET", route, nil)
-	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
-	if err != nil {
-		return nil, reqInf, err
-	}
-	defer resp.Body.Close()
-
-	var data tc.UsersResponse
-	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
-		return nil, reqInf, err
-	}
+	data := tc.UsersResponse{}
+	route := fmt.Sprintf("%s/users", apiBase)
+	inf, err := get(to, route, &data)
+	return data.Response, inf, err
+}
 
-	return data.Response, reqInf, nil
+// GetUsersByRole returns all users accessible from current user for a given role
+func (to *Session) GetUsersByRole(roleName string) ([]tc.User, ReqInf, error) {
+	data := tc.UsersResponse{}
+	route := fmt.Sprintf("%s/users?role=%s", apiBase, url.QueryEscape(roleName))
+	inf, err := get(to, route, &data)
+	return data.Response, inf, err
 }
 
 func (to *Session) GetUserByID(id int) ([]tc.User, ReqInf, error) {
diff --git a/traffic_ops/testing/api/v1/user_test.go b/traffic_ops/testing/api/v1/user_test.go
index 17e38bb..f23353c 100644
--- a/traffic_ops/testing/api/v1/user_test.go
+++ b/traffic_ops/testing/api/v1/user_test.go
@@ -35,6 +35,8 @@ func TestUsers(t *testing.T) {
 		UserSelfUpdateTest(t)
 		UserUpdateOwnRoleTest(t)
 		GetTestUsers(t)
+		GetTestAdminUsers(t)
+		GetTestOperationsUsers(t)
 		GetTestUserCurrent(t)
 		UserTenancyTest(t)
 	})
@@ -291,6 +293,32 @@ func GetTestUsers(t *testing.T) {
 	}
 }
 
+func GetTestAdminUsers(t *testing.T) {
+	adminUsers, _, err := TOSession.GetUsersByRole("admin")
+	if err != nil {
+		t.Errorf("users get: Cannot GET admin users by role: %v", err)
+	} else if len(adminUsers) == 0 {
+		t.Errorf("users get: No admin users found")
+	} else if adminUsers[0].RoleName == nil {
+		t.Errorf("users get: RoleName property doesn't exist")
+	} else if *adminUsers[0].RoleName != "admin" {
+		t.Errorf("users get: RoleName expected %v actual %v", "admin", *adminUsers[0].RoleName)
+	}
+}
+
+func GetTestOperationsUsers(t *testing.T) {
+	opsUsers, _, err := TOSession.GetUsersByRole("operations")
+	if err != nil {
+		t.Errorf("users get: Cannot GET operations users by role: %v", err)
+	} else if len(opsUsers) == 0 {
+		t.Errorf("users get: No operations users found")
+	} else if opsUsers[0].RoleName == nil {
+		t.Errorf("users get: RoleName property doesn't exist")
+	} else if *opsUsers[0].RoleName != "operations" {
+		t.Errorf("users get: RoleName expected %v actual %v", "operations", *opsUsers[0].RoleName)
+	}
+}
+
 func GetTestUserCurrent(t *testing.T) {
 	user, _, err := TOSession.GetUserCurrent()
 	if err != nil {
diff --git a/traffic_ops/traffic_ops_golang/user/user.go b/traffic_ops/traffic_ops_golang/user/user.go
index fc5484d..06f5e2a 100644
--- a/traffic_ops/traffic_ops_golang/user/user.go
+++ b/traffic_ops/traffic_ops_golang/user/user.go
@@ -83,6 +83,7 @@ func (user *TOUser) NewReadObj() interface{} {
 func (user *TOUser) ParamColumns() map[string]dbhelpers.WhereColumnInfo {
 	return map[string]dbhelpers.WhereColumnInfo{
 		"id":       dbhelpers.WhereColumnInfo{"u.id", api.IsInt},
+		"role":     dbhelpers.WhereColumnInfo{"r.name", nil},
 		"tenant":   dbhelpers.WhereColumnInfo{"t.name", nil},
 		"username": dbhelpers.WhereColumnInfo{"u.username", nil},
 	}
diff --git a/traffic_portal/app/src/common/modules/form/role/FormRoleController.js b/traffic_portal/app/src/common/modules/form/role/FormRoleController.js
index 757c5f9..9b711d2 100644
--- a/traffic_portal/app/src/common/modules/form/role/FormRoleController.js
+++ b/traffic_portal/app/src/common/modules/form/role/FormRoleController.js
@@ -17,10 +17,14 @@
  * under the License.
  */
 
-var FormRoleController = function(roles, $scope, formUtils, locationUtils) {
+var FormRoleController = function(roles, $scope, $location, formUtils, locationUtils) {
 
 	$scope.role = roles[0];
 
+	$scope.viewUsers = function() {
+		$location.path($location.path() + '/users');
+	};
+
 	$scope.navigateToPath = locationUtils.navigateToPath;
 
 	$scope.hasError = formUtils.hasError;
@@ -29,5 +33,5 @@ var FormRoleController = function(roles, $scope, formUtils, locationUtils) {
 
 };
 
-FormRoleController.$inject = ['roles', '$scope', 'formUtils', 'locationUtils'];
+FormRoleController.$inject = ['roles', '$scope', '$location', 'formUtils', 'locationUtils'];
 module.exports = FormRoleController;
diff --git a/traffic_portal/app/src/common/modules/form/role/form.role.tpl.html b/traffic_portal/app/src/common/modules/form/role/form.role.tpl.html
index 3ce2e37..2afb57e 100644
--- a/traffic_portal/app/src/common/modules/form/role/form.role.tpl.html
+++ b/traffic_portal/app/src/common/modules/form/role/form.role.tpl.html
@@ -24,8 +24,8 @@ under the License.
             <li class="active">{{roleName}}</li>
         </ol>
         <div class="pull-right" role="group" ng-show="!settings.isNew">
-            <button class="btn btn-primary" title="View Capabilities" ng-show="enforceCapabilities" ng-click="viewCapabilities()">View Capabilities</button>
-            <!--<button class="btn btn-primary" title="View Users" ng-click="viewUsers()">View Users</button>-->
+            <button type="button" class="btn btn-primary" title="View Capabilities" ng-show="enforceCapabilities" ng-click="viewCapabilities()">View Capabilities</button>
+            <button type="button" class="btn btn-primary" title="View Users" ng-click="viewUsers()">View Users</button>
         </div>
         <div class="clearfix"></div>
     </div>
diff --git a/traffic_portal/app/src/modules/private/roles/users/index.js b/traffic_portal/app/src/modules/private/roles/users/index.js
index 38509f7..524fc09 100644
--- a/traffic_portal/app/src/modules/private/roles/users/index.js
+++ b/traffic_portal/app/src/modules/private/roles/users/index.js
@@ -30,8 +30,8 @@ module.exports = angular.module('trafficPortal.private.roles.users', [])
 							roles: function($stateParams, roleService) {
 								return roleService.getRoles({ id: $stateParams.roleId });
 							},
-							roleUsers: function($stateParams, userService) {
-								return userService.getUsers({ roleId: $stateParams.roleId });
+							roleUsers: function(roles, userService) {
+								return userService.getUsers({ role: roles[0].name });
 							}
 						}
 					}