Add the team membership to the robots view
This commit is contained in:
parent
e6354571f6
commit
fde9666647
6 changed files with 112 additions and 28 deletions
|
@ -310,15 +310,44 @@ def _list_entity_robots(entity_name):
|
|||
.where(User.robot == True, User.username ** (entity_name + '+%')))
|
||||
|
||||
|
||||
def list_entity_robot_tuples(entity_name):
|
||||
return (_list_entity_robots(entity_name)
|
||||
class _TupleWrapper(object):
|
||||
def __init__(self, data, fields):
|
||||
self._data = data
|
||||
self._fields = fields
|
||||
|
||||
def get(self, field):
|
||||
return self._data[self._fields.index(field.name + ':' + field.model_class.__name__)]
|
||||
|
||||
|
||||
class TupleSelector(object):
|
||||
""" Helper class for selecting tuples from a peewee query and easily accessing
|
||||
them as if they were objects.
|
||||
"""
|
||||
def __init__(self, query, fields):
|
||||
self._query = query.select(*fields).tuples()
|
||||
self._fields = [field.name + ':' + field.model_class.__name__ for field in fields]
|
||||
|
||||
def __iter__(self):
|
||||
return self._build_iterator()
|
||||
|
||||
def _build_iterator(self):
|
||||
for tuple_data in self._query:
|
||||
yield _TupleWrapper(tuple_data, self._fields)
|
||||
|
||||
|
||||
|
||||
def list_entity_robot_permission_teams(entity_name):
|
||||
query = (_list_entity_robots(entity_name)
|
||||
.join(RepositoryPermission, JOIN_LEFT_OUTER,
|
||||
on=(RepositoryPermission.user == FederatedLogin.user))
|
||||
.join(Repository, JOIN_LEFT_OUTER)
|
||||
.switch(User)
|
||||
.group_by(User, FederatedLogin)
|
||||
.select(User.username, FederatedLogin.service_ident, fn.Count(Repository.id))
|
||||
.tuples())
|
||||
.join(TeamMember, JOIN_LEFT_OUTER)
|
||||
.join(Team, JOIN_LEFT_OUTER))
|
||||
|
||||
fields = [User.username, FederatedLogin.service_ident, Repository.name, Team.name]
|
||||
return TupleSelector(query, fields)
|
||||
|
||||
|
||||
def list_robot_permissions(robot_name):
|
||||
return (RepositoryPermission.select(RepositoryPermission, User, Repository)
|
||||
|
|
|
@ -5,15 +5,15 @@ from auth.permissions import AdministerOrganizationPermission, OrganizationMembe
|
|||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from data import model
|
||||
from data.database import User, Team, Repository, FederatedLogin
|
||||
from util.names import format_robot_username
|
||||
from flask import abort
|
||||
from app import avatar
|
||||
|
||||
|
||||
def robot_view(name, token, count=None):
|
||||
def robot_view(name, token):
|
||||
return {
|
||||
'name': name,
|
||||
'token': token,
|
||||
'permission_count': count
|
||||
'token': token
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,6 +27,41 @@ def permission_view(permission):
|
|||
}
|
||||
|
||||
|
||||
def robots_list(prefix):
|
||||
tuples = model.list_entity_robot_permission_teams(prefix)
|
||||
|
||||
robots = {}
|
||||
robot_teams = set()
|
||||
|
||||
for robot_tuple in tuples:
|
||||
robot_name = robot_tuple.get(User.username)
|
||||
if not robot_name in robots:
|
||||
robots[robot_name] = {
|
||||
'name': robot_name,
|
||||
'token': robot_tuple.get(FederatedLogin.service_ident),
|
||||
'teams': [],
|
||||
'repositories': []
|
||||
}
|
||||
|
||||
team_name = robot_tuple.get(Team.name)
|
||||
repository_name = robot_tuple.get(Repository.name)
|
||||
|
||||
if team_name is not None:
|
||||
check_key = robot_name + ':' + team_name
|
||||
if not check_key in robot_teams:
|
||||
robot_teams.add(check_key)
|
||||
|
||||
robots[robot_name]['teams'].append({
|
||||
'name': team_name,
|
||||
'avatar': avatar.get_data(team_name, team_name, 'team')
|
||||
})
|
||||
|
||||
if repository_name is not None:
|
||||
if not repository_name in robots[robot_name]['repositories']:
|
||||
robots[robot_name]['repositories'].append(repository_name)
|
||||
|
||||
return {'robots': robots.values()}
|
||||
|
||||
@resource('/v1/user/robots')
|
||||
@internal_only
|
||||
class UserRobotList(ApiResource):
|
||||
|
@ -36,10 +71,7 @@ class UserRobotList(ApiResource):
|
|||
def get(self):
|
||||
""" List the available robots for the user. """
|
||||
user = get_authenticated_user()
|
||||
robots = model.list_entity_robot_tuples(user.username)
|
||||
return {
|
||||
'robots': [robot_view(name, password, count) for name, password, count in robots]
|
||||
}
|
||||
return robots_list(user.username)
|
||||
|
||||
|
||||
@resource('/v1/user/robots/<robot_shortname>')
|
||||
|
@ -85,10 +117,7 @@ class OrgRobotList(ApiResource):
|
|||
""" List the organization's robots. """
|
||||
permission = OrganizationMemberPermission(orgname)
|
||||
if permission.can():
|
||||
robots = model.list_entity_robot_tuples(orgname)
|
||||
return {
|
||||
'robots': [robot_view(name, password, count) for name, password, count in robots]
|
||||
}
|
||||
return robots_list(orgname)
|
||||
|
||||
raise Unauthorized()
|
||||
|
||||
|
|
|
@ -23,4 +23,8 @@
|
|||
font-style: normal !important;
|
||||
font-weight: normal !important;
|
||||
font-variant: normal !important;
|
||||
}
|
||||
|
||||
a .avatar-element .letter {
|
||||
cursor: pointer !important;
|
||||
}
|
|
@ -83,4 +83,8 @@
|
|||
.robots-manager-element .repo-circle.no-background .fa-lock {
|
||||
bottom: 5px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.robots-manager-element .member-perm-summary {
|
||||
margin-right: 14px;
|
||||
}
|
|
@ -28,16 +28,17 @@
|
|||
|
||||
<table class="co-table" ng-if="robots.length">
|
||||
<thead>
|
||||
<td class="caret-col" ng-if="organization.is_admin"></td>
|
||||
<td class="caret-col" ng-if="organization.is_admin && Config.isNewLayout()"></td>
|
||||
<td>Robot Account Name</td>
|
||||
<td>Repository Permissions</td>
|
||||
<td ng-if="organization && Config.isNewLayout()">Teams</td>
|
||||
<td ng-if="Config.isNewLayout()">Repository Permissions</td>
|
||||
<td class="options-col"></td>
|
||||
</thead>
|
||||
|
||||
<tbody ng-repeat="robotInfo in robots">
|
||||
<tr ng-class="robotInfo.showing_permissions ? 'open' : 'closed'">
|
||||
<td class="caret-col" ng-if="organization.is_admin">
|
||||
<span ng-if="robotInfo.permission_count > 0" ng-click="showPermissions(robotInfo)">
|
||||
<td class="caret-col" ng-if="organization.is_admin && Config.isNewLayout()">
|
||||
<span ng-if="robotInfo.repositories.length > 0" ng-click="showPermissions(robotInfo)">
|
||||
<i class="fa"
|
||||
ng-class="robotInfo.showing_permissions ? 'fa-caret-down' : 'fa-caret-right'"
|
||||
data-title="View Permissions List" bs-tooltip></i>
|
||||
|
@ -49,13 +50,29 @@
|
|||
<span class="prefix">{{ getPrefix(robotInfo.name) }}+</span>{{ getShortenedName(robotInfo.name) }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="empty" ng-if="robotInfo.permission_count == 0">(No permissions on any repositories)</span>
|
||||
<span ng-if="robotInfo.permission_count > 0">
|
||||
<td ng-if="organization && Config.isNewLayout()">
|
||||
<span class="empty" ng-if="robotInfo.teams.length == 0">
|
||||
(Not a member of any team)
|
||||
</span>
|
||||
<span class="empty" ng-if="robotInfo.teams.length > 0">
|
||||
<span ng-repeat="team in robotInfo.teams"
|
||||
data-title="Team {{ team.name }}" bs-tooltip>
|
||||
<span class="anchor" is-text-only="!organization.admin" href="/organization/{{ organization.name }}/teams/{{ team.name }}">
|
||||
<span class="avatar" size="24" data="team.avatar"></span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td ng-if="Config.isNewLayout()">
|
||||
<span class="empty" ng-if="robotInfo.repositories.length == 0">
|
||||
(No permissions on any repositories)
|
||||
</span>
|
||||
|
||||
<span class="member-perm-summary" ng-if="robotInfo.repositories.length > 0">
|
||||
Permissions on
|
||||
<span class="anchor" href="javascript:void(0)" is-text-only="!organization.is_admin" ng-click="showPermissions(robotInfo)">{{ robotInfo.permission_count }}
|
||||
<span ng-if="robotInfo.permission_count == 1">repository</span>
|
||||
<span ng-if="robotInfo.permission_count > 1">repositories</span>
|
||||
<span class="anchor" href="javascript:void(0)" is-text-only="!organization.is_admin" ng-click="showPermissions(robotInfo)">{{ robotInfo.repositories.length }}
|
||||
<span ng-if="robotInfo.repositories.length == 1">repository</span>
|
||||
<span ng-if="robotInfo.repositories.length > 1">repositories</span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
|
|
|
@ -12,7 +12,7 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
'organization': '=organization',
|
||||
'user': '=user'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, $routeParams, CreateService) {
|
||||
controller: function($scope, $element, ApiService, $routeParams, CreateService, Config) {
|
||||
$scope.ROBOT_PATTERN = ROBOT_PATTERN;
|
||||
|
||||
// TODO(jschorr): move this to a service.
|
||||
|
@ -26,6 +26,7 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
$scope.loading = false;
|
||||
$scope.shownRobot = null;
|
||||
$scope.showRobotCounter = 0;
|
||||
$scope.Config = Config;
|
||||
|
||||
var loadRobotPermissions = function(info) {
|
||||
var shortName = $scope.getShortenedName(info.name);
|
||||
|
|
Reference in a new issue