diff --git a/data/model.py b/data/model.py index a18dc0af4..822605b92 100644 --- a/data/model.py +++ b/data/model.py @@ -379,11 +379,19 @@ def get_matching_teams(team_prefix, organization): return query.limit(10) -def get_matching_users(username_prefix, organization=None): +def get_matching_users(username_prefix, robot_namespace=None, + organization=None): Org = User.alias() - users_no_orgs = (User.username ** (username_prefix + '%') & - (User.organization == False)) - query = User.select(User.username, Org.username).where(users_no_orgs) + direct_user_query = (User.username ** (username_prefix + '%') & + (User.organization == False) & (User.robot == False)) + + if robot_namespace: + robot_prefix = format_robot_username(robot_namespace, username_prefix) + direct_user_query = (direct_user_query | + (User.username ** (robot_prefix + '%') & + (User.robot == True))) + + query = User.select(User.username, Org.username, User.robot).where(direct_user_query) if organization: with_team = query.join(TeamMember, JOIN_LEFT_OUTER).join(Team, @@ -396,6 +404,7 @@ def get_matching_users(username_prefix, organization=None): class MatchingUserResult(object): def __init__(self, *args): self.username = args[0] + self.is_robot = args[2] if organization: self.is_org_member = (args[1] == organization.username) else: diff --git a/endpoints/api.py b/endpoints/api.py index 185459094..202e723dd 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -260,20 +260,26 @@ def get_matching_users(prefix): def get_matching_entities(prefix): teams = [] - organization_name = request.args.get('organization', None) + namespace_name = request.args.get('namespace', None) + robot_namespace = None organization = None - if organization_name: - permission = OrganizationMemberPermission(organization_name) + try: + organization = model.get_organization(namespace_name) + + # namespace name was an org + permission = OrganizationMemberPermission(namespace_name) if permission.can(): - try: - organization = model.get_organization(organization_name) - except model.InvalidOrganizationException: - pass + robot_namespace = namespace_name - if organization: - teams = model.get_matching_teams(prefix, organization) + if request.args.get('includeTeams', False): + teams = model.get_matching_teams(prefix, organization) - users = model.get_matching_users(prefix, organization) + except model.InvalidOrganizationException: + # namespace name was a user + if current_user.db_user().username == namespace_name: + robot_namespace = namespace_name + + users = model.get_matching_users(prefix, robot_namespace, organization) def entity_team_view(team): result = { @@ -286,7 +292,7 @@ def get_matching_entities(prefix): def user_view(user): user_json = { 'name': user.username, - 'kind': 'user', + 'kind': 'robot' if user.is_robot else 'user', } if user.is_org_member is not None: diff --git a/initdb.py b/initdb.py index 5a2fbeb40..e810d8ab7 100644 --- a/initdb.py +++ b/initdb.py @@ -132,6 +132,8 @@ def populate_database(): new_user_1.verified = True new_user_1.save() + model.create_robot('dtrobot', new_user_1) + new_user_2 = model.create_user('public', 'password', 'jacob.moshenko@gmail.com') new_user_2.verified = True @@ -188,6 +190,8 @@ def populate_database(): org.stripe_id = TEST_STRIPE_ID org.save() + model.create_robot('neworgrobot', org) + owners = model.get_organization_team('buynlarge', 'owners') owners.description = 'Owners have unfetterd access across the entire org.' owners.save() diff --git a/static/js/app.js b/static/js/app.js index 26d7aa5da..04a887b8c 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -604,9 +604,10 @@ quayApp.directive('entitySearch', function () { transclude: false, restrict: 'C', scope: { - 'organization': '=organization', + 'namespace': '=namespace', 'inputTitle': '=inputTitle', - 'entitySelected': '=entitySelected' + 'entitySelected': '=entitySelected', + 'includeTeams': '=includeTeams' }, controller: function($scope, $element) { if (!$scope.entitySelected) { return; } @@ -614,15 +615,16 @@ quayApp.directive('entitySearch', function () { number++; var input = $element[0].firstChild; - $scope.organization = $scope.organization || ''; + $scope.namespace = $scope.namespace || ''; $(input).typeahead({ name: 'entities' + number, remote: { url: '/api/entities/%QUERY', replace: function (url, uriEncodedQuery) { url = url.replace('%QUERY', uriEncodedQuery); - if ($scope.organization) { - url += '?organization=' + encodeURIComponent($scope.organization); + url += '?namespace=' + encodeURIComponent($scope.namespace); + if ($scope.includeTeams) { + url += '&includeTeams=true' } return url; }, @@ -648,7 +650,7 @@ quayApp.directive('entitySearch', function () { } template += '' + datum.value + ''; - if (datum.entity.is_org_member !== undefined && !datum.entity.is_org_member) { + if (datum.entity.is_org_member !== undefined && !datum.entity.is_org_member && datum.kind == 'user') { template += '
This user is outside your organization
'; } diff --git a/static/js/controllers.js b/static/js/controllers.js index 8bba4f712..a83f375a2 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -1296,7 +1296,7 @@ function TeamViewCtrl($rootScope, $scope, Restangular, $routeParams) { 'html': true }); - var orgname = $routeParams.orgname; + $scope.orgname = $routeParams.orgname; var teamname = $routeParams.teamname; $rootScope.title = 'Loading...'; @@ -1307,7 +1307,7 @@ function TeamViewCtrl($rootScope, $scope, Restangular, $routeParams) { if ($scope.members[member.name]) { return; } $scope.$apply(function() { - var addMember = Restangular.one(getRestUrl('organization', orgname, 'team', teamname, 'members', member.name)); + var addMember = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname, 'members', member.name)); addMember.customPOST().then(function(resp) { $scope.members[member.name] = resp; }, function() { @@ -1317,7 +1317,7 @@ function TeamViewCtrl($rootScope, $scope, Restangular, $routeParams) { }; $scope.removeMember = function(username) { - var removeMember = Restangular.one(getRestUrl('organization', orgname, 'team', teamname, 'members', username)); + var removeMember = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname, 'members', username)); removeMember.customDELETE().then(function(resp) { delete $scope.members[username]; }, function() { @@ -1328,7 +1328,7 @@ function TeamViewCtrl($rootScope, $scope, Restangular, $routeParams) { $scope.updateForDescription = function(content) { $scope.organization.teams[teamname].description = content; - var updateTeam = Restangular.one(getRestUrl('organization', orgname, 'team', teamname)); + var updateTeam = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname)); var data = $scope.organization.teams[teamname]; updateTeam.customPUT(data).then(function(resp) { }, function() { @@ -1337,7 +1337,7 @@ function TeamViewCtrl($rootScope, $scope, Restangular, $routeParams) { }; var loadOrganization = function() { - var getOrganization = Restangular.one(getRestUrl('organization', orgname)) + var getOrganization = Restangular.one(getRestUrl('organization', $scope.orgname)) getOrganization.get().then(function(resp) { $scope.organization = resp; $scope.team = $scope.organization.teams[teamname]; @@ -1350,12 +1350,12 @@ function TeamViewCtrl($rootScope, $scope, Restangular, $routeParams) { }; var loadMembers = function() { - var getMembers = Restangular.one(getRestUrl('organization', orgname, 'team', teamname, 'members')); + var getMembers = Restangular.one(getRestUrl('organization', $scope.orgname, 'team', teamname, 'members')); getMembers.get().then(function(resp) { $scope.members = resp.members; $scope.canEditMembers = resp.can_edit; $scope.loading = !$scope.organization || !$scope.members; - $rootScope.title = teamname + ' (' + orgname + ')'; + $rootScope.title = teamname + ' (' + $scope.orgname + ')'; }, function() { $scope.organization = null; $scope.members = null; diff --git a/static/partials/repo-admin.html b/static/partials/repo-admin.html index d9016b83a..89442c88f 100644 --- a/static/partials/repo-admin.html +++ b/static/partials/repo-admin.html @@ -91,7 +91,7 @@ - + diff --git a/static/partials/team-view.html b/static/partials/team-view.html index 6d7084b3e..1d8d66d5c 100644 --- a/static/partials/team-view.html +++ b/static/partials/team-view.html @@ -33,7 +33,7 @@ - + diff --git a/test/data/test.db b/test/data/test.db index 6a2cb0c86..fdb9329a0 100644 Binary files a/test/data/test.db and b/test/data/test.db differ