- Add support for orgs in the entity search and the notification system
- Fix the titles/names of the different notification types - Fix the styling of the options buttons on the notifications
This commit is contained in:
parent
1ffbc77106
commit
54ee94754e
6 changed files with 55 additions and 13 deletions
|
@ -2,9 +2,11 @@ from endpoints.api import (ApiResource, parse_args, query_param, truthy_bool, ni
|
||||||
require_scope)
|
require_scope)
|
||||||
from data import model
|
from data import model
|
||||||
from auth.permissions import (OrganizationMemberPermission, ViewTeamPermission,
|
from auth.permissions import (OrganizationMemberPermission, ViewTeamPermission,
|
||||||
ReadRepositoryPermission, UserAdminPermission)
|
ReadRepositoryPermission, UserAdminPermission,
|
||||||
|
AdministerOrganizationPermission)
|
||||||
from auth.auth_context import get_authenticated_user
|
from auth.auth_context import get_authenticated_user
|
||||||
from auth import scopes
|
from auth import scopes
|
||||||
|
from util.gravatar import compute_hash
|
||||||
|
|
||||||
|
|
||||||
@resource('/v1/entities/<prefix>')
|
@resource('/v1/entities/<prefix>')
|
||||||
|
@ -14,10 +16,12 @@ class EntitySearch(ApiResource):
|
||||||
@query_param('namespace', 'Namespace to use when querying for org entities.', type=str,
|
@query_param('namespace', 'Namespace to use when querying for org entities.', type=str,
|
||||||
default='')
|
default='')
|
||||||
@query_param('includeTeams', 'Whether to include team names.', type=truthy_bool, default=False)
|
@query_param('includeTeams', 'Whether to include team names.', type=truthy_bool, default=False)
|
||||||
|
@query_param('includeOrgs', 'Whether to include orgs names.', type=truthy_bool, default=False)
|
||||||
@nickname('getMatchingEntities')
|
@nickname('getMatchingEntities')
|
||||||
def get(self, args, prefix):
|
def get(self, args, prefix):
|
||||||
""" Get a list of entities that match the specified prefix. """
|
""" Get a list of entities that match the specified prefix. """
|
||||||
teams = []
|
teams = []
|
||||||
|
org_data = []
|
||||||
|
|
||||||
namespace_name = args['namespace']
|
namespace_name = args['namespace']
|
||||||
robot_namespace = None
|
robot_namespace = None
|
||||||
|
@ -34,6 +38,15 @@ class EntitySearch(ApiResource):
|
||||||
if args['includeTeams']:
|
if args['includeTeams']:
|
||||||
teams = model.get_matching_teams(prefix, organization)
|
teams = model.get_matching_teams(prefix, organization)
|
||||||
|
|
||||||
|
if args['includeOrgs'] and AdministerOrganizationPermission(namespace_name) \
|
||||||
|
and namespace_name.startswith(prefix):
|
||||||
|
org_data = [{
|
||||||
|
'name': namespace_name,
|
||||||
|
'kind': 'org',
|
||||||
|
'is_org_member': True,
|
||||||
|
'gravatar': compute_hash(organization.email),
|
||||||
|
}]
|
||||||
|
|
||||||
except model.InvalidOrganizationException:
|
except model.InvalidOrganizationException:
|
||||||
# namespace name was a user
|
# namespace name was a user
|
||||||
user = get_authenticated_user()
|
user = get_authenticated_user()
|
||||||
|
@ -69,7 +82,7 @@ class EntitySearch(ApiResource):
|
||||||
user_data = [user_view(user) for user in users]
|
user_data = [user_view(user) for user in users]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'results': team_data + user_data
|
'results': team_data + user_data + org_data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,17 @@ class QuayNotificationMethod(NotificationMethod):
|
||||||
# Just to be safe.
|
# Just to be safe.
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
target_users.append(target)
|
||||||
|
elif target_info['kind'] == 'org':
|
||||||
|
target = model.get_organization(target_info['name'])
|
||||||
|
if not target:
|
||||||
|
# Just to be safe.
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Only repositories under the organization can cause notifications to that org.
|
||||||
|
if target_info['name'] != repository.namespace:
|
||||||
|
return False
|
||||||
|
|
||||||
target_users.append(target)
|
target_users.append(target)
|
||||||
elif target_info['kind'] == 'team':
|
elif target_info['kind'] == 'team':
|
||||||
# Lookup the team.
|
# Lookup the team.
|
||||||
|
|
|
@ -4469,11 +4469,11 @@ i.quay-icon {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.external-notification-view-element .side-controls {
|
.external-notification-view-element .side-controls button {
|
||||||
opacity: 0;
|
border: 1px solid transparent;
|
||||||
transition: opacity 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.external-notification-view-element:hover .side-controls {
|
.external-notification-view-element:hover .side-controls button {
|
||||||
opacity: 1;
|
border: 1px solid #eee;
|
||||||
}
|
}
|
|
@ -66,7 +66,7 @@
|
||||||
placeholder="''"
|
placeholder="''"
|
||||||
current-entity="currentConfig[field.name]"
|
current-entity="currentConfig[field.name]"
|
||||||
ng-model="currentConfig[field.name]"
|
ng-model="currentConfig[field.name]"
|
||||||
allowed-entities="['user', 'team']"
|
allowed-entities="['user', 'team', 'org']"
|
||||||
ng-switch-when="entity">
|
ng-switch-when="entity">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" class="btn btn-primary"
|
<button type="submit" class="btn btn-primary"
|
||||||
ng-disabled="createForm.$invalid || !currentMethod || !currentEvent || creating">
|
ng-disabled="createForm.$invalid || !currentMethod.id || !currentEvent.id || creating">
|
||||||
Create Notification
|
Create Notification
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="creating">Cancel</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal" ng-disabled="creating">Cancel</button>
|
||||||
|
|
|
@ -6,7 +6,14 @@
|
||||||
<span ng-if="getIsAdmin(namespace)"><a href="/organization/{{ namespace }}/teams/{{ entity.name }}">{{entity.name}}</a></span>
|
<span ng-if="getIsAdmin(namespace)"><a href="/organization/{{ namespace }}/teams/{{ entity.name }}">{{entity.name}}</a></span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span ng-if="entity.kind != 'team'">
|
<span ng-if="entity.kind == 'org'">
|
||||||
|
<img src="//www.gravatar.com/avatar/{{ entity.gravatar }}?s=16&d=identicon">
|
||||||
|
<span class="entity-name">
|
||||||
|
<span ng-if="!getIsAdmin(entity.name)">{{entity.name}}</span>
|
||||||
|
<span ng-if="getIsAdmin(entity.name)"><a href="/organization/{{ entity.name }}">{{entity.name}}</a></span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span ng-if="entity.kind != 'team' && entity.kind != 'org'">
|
||||||
<i class="fa fa-user" ng-show="!entity.is_robot" data-title="User" bs-tooltip="tooltip.title" data-container="body"></i>
|
<i class="fa fa-user" ng-show="!entity.is_robot" data-title="User" bs-tooltip="tooltip.title" data-container="body"></i>
|
||||||
<i class="fa fa-wrench" ng-show="entity.is_robot" data-title="Robot Account" bs-tooltip="tooltip.title" data-container="body"></i>
|
<i class="fa fa-wrench" ng-show="entity.is_robot" data-title="Robot Account" bs-tooltip="tooltip.title" data-container="body"></i>
|
||||||
<span class="entity-name" ng-if="entity.is_robot">
|
<span class="entity-name" ng-if="entity.is_robot">
|
||||||
|
|
|
@ -1015,7 +1015,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'email',
|
'id': 'email',
|
||||||
'title': 'E-mail notification',
|
'title': 'E-mail',
|
||||||
'icon': 'fa-envelope',
|
'icon': 'fa-envelope',
|
||||||
'fields': [
|
'fields': [
|
||||||
{
|
{
|
||||||
|
@ -1027,7 +1027,7 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'webhook',
|
'id': 'webhook',
|
||||||
'title': 'Webhook invoke',
|
'title': 'Webhook POST',
|
||||||
'icon': 'fa-link',
|
'icon': 'fa-link',
|
||||||
'fields': [
|
'fields': [
|
||||||
{
|
{
|
||||||
|
@ -3304,6 +3304,7 @@ quayApp.directive('entitySearch', function () {
|
||||||
|
|
||||||
$scope.includeTeams = true;
|
$scope.includeTeams = true;
|
||||||
$scope.includeRobots = true;
|
$scope.includeRobots = true;
|
||||||
|
$scope.includeOrgs = false;
|
||||||
|
|
||||||
$scope.currentEntityInternal = $scope.currentEntity;
|
$scope.currentEntityInternal = $scope.currentEntity;
|
||||||
|
|
||||||
|
@ -3436,6 +3437,9 @@ quayApp.directive('entitySearch', function () {
|
||||||
if ($scope.isOrganization && isSupported('team')) {
|
if ($scope.isOrganization && isSupported('team')) {
|
||||||
url += '&includeTeams=true'
|
url += '&includeTeams=true'
|
||||||
}
|
}
|
||||||
|
if (isSupported('org')) {
|
||||||
|
url += '&includeOrgs=true'
|
||||||
|
}
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
filter: function(data) {
|
filter: function(data) {
|
||||||
|
@ -3448,6 +3452,8 @@ quayApp.directive('entitySearch', function () {
|
||||||
found = entity.is_robot ? 'robot' : 'user';
|
found = entity.is_robot ? 'robot' : 'user';
|
||||||
} else if (entity.kind == 'team') {
|
} else if (entity.kind == 'team') {
|
||||||
found = 'team';
|
found = 'team';
|
||||||
|
} else if (entity.kind == 'org') {
|
||||||
|
found = 'org';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSupported(found)) {
|
if (!isSupported(found)) {
|
||||||
|
@ -3491,6 +3497,7 @@ quayApp.directive('entitySearch', function () {
|
||||||
var classes = [];
|
var classes = [];
|
||||||
|
|
||||||
if (isSupported('user')) { classes.push('users'); }
|
if (isSupported('user')) { classes.push('users'); }
|
||||||
|
if (isSupported('org')) { classes.push('organizations'); }
|
||||||
if ($scope.isAdmin && isSupported('robot')) { classes.push('robot accounts'); }
|
if ($scope.isAdmin && isSupported('robot')) { classes.push('robot accounts'); }
|
||||||
if ($scope.isOrganization && isSupported('team')) { classes.push('teams'); }
|
if ($scope.isOrganization && isSupported('team')) { classes.push('teams'); }
|
||||||
|
|
||||||
|
@ -3524,7 +3531,11 @@ quayApp.directive('entitySearch', function () {
|
||||||
template += '<i class="fa fa-wrench fa-lg"></i>';
|
template += '<i class="fa fa-wrench fa-lg"></i>';
|
||||||
} else if (datum.entity.kind == 'team') {
|
} else if (datum.entity.kind == 'team') {
|
||||||
template += '<i class="fa fa-group fa-lg"></i>';
|
template += '<i class="fa fa-group fa-lg"></i>';
|
||||||
|
} else if (datum.entity.kind == 'org') {
|
||||||
|
template += '<i class="fa"><img src="//www.gravatar.com/avatar/' +
|
||||||
|
datum.entity.gravatar + '?s=16&d=identicon"></i>';
|
||||||
}
|
}
|
||||||
|
|
||||||
template += '<span class="name">' + datum.value + '</span>';
|
template += '<span class="name">' + datum.value + '</span>';
|
||||||
|
|
||||||
if (datum.entity.is_org_member === false && datum.entity.kind == 'user') {
|
if (datum.entity.is_org_member === false && datum.entity.kind == 'user') {
|
||||||
|
|
Reference in a new issue