- Add model functions for working with prototypes

- Add API calls for working with prototypes
- Get UI for prototypes working (minus add)
This commit is contained in:
Joseph Schorr 2014-01-21 14:18:20 -05:00
parent 330051f7d9
commit e17c3590a7
9 changed files with 329 additions and 1 deletions

View file

@ -135,6 +135,7 @@ class RepositoryPermission(BaseModel):
class PermissionPrototype(BaseModel):
org = ForeignKeyField(User, index=True, related_name='orgpermissionproto')
uuid = CharField()
activating_user = ForeignKeyField(User, index=True, null=True,
related_name='userpermissionproto')
delegate_user = ForeignKeyField(User, related_name='receivingpermission',

View file

@ -4,6 +4,7 @@ import datetime
import dateutil.parser
import operator
import json
import uuid
from datetime import timedelta
@ -671,6 +672,52 @@ def get_all_user_permissions(user):
(UserThroughTeam.id == user))
def delete_prototype_permission(org, uid):
found = get_prototype_permission(org, uid)
if not found:
return None
found.delete_instance()
return found
def get_prototype_permission(org, uid):
found = None
try:
return PermissionPrototype.get(PermissionPrototype.org == org, PermissionPrototype.uuid == uid)
except PermissionPrototype.DoesNotExist:
return None
def get_prototype_permissions(org):
ActivatingUser = User.alias()
DelegateUser = User.alias()
where = PermissionPrototype.select().where(PermissionPrototype.org == org)
join1 = where.join(ActivatingUser, JOIN_LEFT_OUTER, on=(ActivatingUser.id == PermissionPrototype.activating_user))
join2 = join1.join(DelegateUser, JOIN_LEFT_OUTER, on=(DelegateUser.id == PermissionPrototype.delegate_user))
join3 = join2.join(Team, JOIN_LEFT_OUTER, on=(Team.id == PermissionPrototype.delegate_team))
join4 = join3.join(Role, JOIN_LEFT_OUTER, on=(Role.id == PermissionPrototype.role))
return join4
def update_prototype_permission(org, uid, role_name):
found = get_prototype_permission(org, uid)
if not found:
return None
new_role = Role.get(Role.name == role_name)
found.role = new_role
found.save()
return found
def add_prototype_permission(org, role_name, activating_user, delegate_user=None, delegate_team=None):
new_role = Role.get(Role.name == role_name)
uid = uuid.uuid4()
return PermissionPrototype.create(org=org, uuid=uid, role=new_role, activating_user=activating_user,
delegate_user=delegate_user, delegate_team=delegate_team)
def get_org_wide_permissions(user):
Org = User.alias()
team_with_role = Team.select(Team, Org, TeamRole).join(TeamRole)

View file

@ -541,6 +541,113 @@ def change_organization_details(orgname):
abort(403)
def prototype_view(p):
def user_view(u):
return {
'name': u.username,
'is_robot': u.robot,
'kind': 'user'
}
def team_view(t):
return {
'name': t.name,
'kind': 'team'
}
return {
'activating_user': user_view(p.activating_user),
'delegate': user_view(p.delegate_user) if p.delegate_user else team_view(p.delegate_team),
'role': p.role.name,
'id': p.uuid
}
@app.route('/api/organization/<orgname>/prototypes', methods=['GET'])
@api_login_required
def get_organization_prototype_permissions(orgname):
permission = AdministerOrganizationPermission(orgname)
if permission.can():
try:
org = model.get_organization(orgname)
except model.InvalidOrganizationException:
abort(404)
permissions = model.get_prototype_permissions(org)
return jsonify({'prototypes': [prototype_view(p) for p in permissions]})
abort(403)
@app.route('/api/organization/<orgname>/prototypes', methods=['POST'])
@api_login_required
def create_organization_prototype_permission(orgname):
permission = AdministerOrganizationPermission(orgname)
if permission.can():
try:
org = model.get_organization(orgname)
except model.InvalidOrganizationException:
abort(404)
details = request.get_json()
activating_user = details['activating_user']['name']
delegate = details['delegate']
delegate_kind = delegate['kind']
delegate_name = delegate['name']
delegate_user = delegate_name if delegate_kind == 'user' else None
delegate_team = delegate_name if delegate_kind == 'team' else None
role_name = details['role']
if not delegate_user and not delegate_team:
abort(400)
prototype = model.add_prototype_permission(org, role_name, activating_user, delegate_user, delegate_team)
return jsonify(protoype_view(prototype))
abort(403)
@app.route('/api/organization/<orgname>/prototypes/<prototypeid>', methods=['DELETE'])
@api_login_required
def delete_organization_prototype_permission(orgname, prototypeid):
permission = AdministerOrganizationPermission(orgname)
if permission.can():
try:
org = model.get_organization(orgname)
except model.InvalidOrganizationException:
abort(404)
prototype = model.delete_prototype_permission(org, prototypeid)
if not prototype:
abort(404)
return make_response('Deleted', 204)
abort(403)
@app.route('/api/organization/<orgname>/prototypes/<prototypeid>', methods=['PUT'])
@api_login_required
def update_organization_prototype_permission(orgname, prototypeid):
permission = AdministerOrganizationPermission(orgname)
if permission.can():
try:
org = model.get_organization(orgname)
except model.InvalidOrganizationException:
abort(404)
details = request.get_json()
role_name = details['role']
prototype = model.update_prototype_permission(org, prototypeid, role_name)
if not prototype:
abort(404)
return jsonify(prototype_view(prototype))
abort(403)
@app.route('/api/organization/<orgname>/members', methods=['GET'])
@api_login_required
@ -1140,7 +1247,6 @@ def get_filedrop_url():
'file_id': file_id
})
def role_view(repo_perm_obj):
return {
'role': repo_perm_obj.role.name,

View file

@ -153,6 +153,10 @@ def initialize_database():
LogEntryKind.create(name='org_remove_team_member')
LogEntryKind.create(name='org_set_team_description')
LogEntryKind.create(name='org_set_team_role')
LogEntryKind.create(name='org_create_prototype_permission')
LogEntryKind.create(name='org_modify_prototype_permission')
LogEntryKind.create(name='org_delete_prototype_permission')
def wipe_database():
@ -261,6 +265,10 @@ def populate_database():
build.status_url = 'http://localhost:5000/test/build/status'
build.save()
model.add_prototype_permission(org, 'read', activating_user=new_user_1, delegate_user=new_user_2)
model.add_prototype_permission(org, 'read', activating_user=new_user_1, delegate_team=reader_team)
model.add_prototype_permission(org, 'write', activating_user=new_user_2, delegate_user=new_user_1)
today = datetime.today()
week_ago = today - timedelta(6)
six_ago = today - timedelta(5)

View file

@ -2256,6 +2256,16 @@ p.editable:hover i {
color: steelblue;
}
.prototype-manager-element thead th {
padding: 4px;
color: #666;
}
.prototype-manager-element td {
padding: 10px !important;
vertical-align: middle !important;
}
.org-list h2 {
margin-bottom: 20px;
}

View file

@ -0,0 +1,59 @@
<div class="prototype-manager-element">
<div class="quay-spinner" ng-show="loading"></div>
<div class="container" ng-show="!loading">
<div class="alert alert-info">
Default permissions provide a means of specifying <span class="context-tooltip" title="By default, all repositories have the creating user added as an 'Admin'" bs-tooltip="tooltip.title">additional</span> permissions that should be granted automatically to a repository based on the user or robot creating the repository.
</div>
<div class="side-controls">
<button class="btn btn-success">
<i class="fa fa-plus"></i>
New Default Permission
</button>
</div>
<table class="table">
<thead>
<th>
<span class="context-tooltip" title="The user that is creating the repository"
bs-tooltip="tooltip.title" data-container="body">
Creating User/Robot
</span>
</th>
<th>
<span class="context-tooltip" title="The user or team that is being granted the permission"
bs-tooltip="tooltip.title" data-container="body">
Delegated User/Team
</span>
</th>
<th>Permission</th>
<th style="width: 150px"></th>
</thead>
<tr ng-repeat="prototype in prototypes">
<td>
<span class="entity-reference" orgname="organization.name" name="prototype.activating_user.name"
isrobot="prototype.activating_user.is_robot"></span>
</td>
<td>
<span class="entity-reference" orgname="organization.name"
name="prototype.delegate.kind == 'team' ? null :prototype.delegate.name"
team="prototype.delegate.kind == 'team' ? prototype.delegate.name : null"
isrobot="prototype.delegate.is_robot"></span>
</td>
<td>
<span class="role-group" current-role="prototype.role" role-changed="setRole(role, prototype)" roles="roles"></span>
</td>
<td>
<span class="delete-ui" tabindex="0">
<span class="delete-ui-button" ng-click="deletePrototype(prototype)"><button class="btn btn-danger">Delete</button></span>
<i class="fa fa-times" bs-tooltip="tooltip.title" data-placement="right" title="Delete Permission"></i>
</span>
</td>
</tr>
</table>
</div>
</div>

View file

@ -1479,6 +1479,97 @@ quayApp.directive('robotsManager', function () {
});
quayApp.directive('prototypeManager', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/prototype-manager.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'organization': '=organization'
},
controller: function($scope, $element, ApiService) {
$scope.loading = false;
$scope.roles = [
{ 'id': 'read', 'title': 'Read', 'kind': 'success' },
{ 'id': 'write', 'title': 'Write', 'kind': 'success' },
{ 'id': 'admin', 'title': 'Admin', 'kind': 'primary' }
];
$scope.setRole = function(role, prototype) {
var params = {
'orgname': $scope.organization.name,
'prototypeid': prototype.id
};
var data = {
'id': prototype.id,
'role': role
};
ApiService.updateOrganizationPrototypePermission(data, params).then(function(resp) {
prototype.role = role;
}, function(resp) {
bootbox.dialog({
"message": resp.data ? resp.data : 'The permission could not be modified',
"title": "Cannot modify permission",
"buttons": {
"close": {
"label": "Close",
"className": "btn-primary"
}
}
});
});
};
$scope.deletePrototype = function(prototype) {
$scope.loading = true;
var params = {
'orgname': $scope.organization.name,
'prototypeid': prototype.id
};
ApiService.deleteOrganizationPrototypePermission(null, params).then(function(resp) {
$scope.prototypes.splice($scope.prototypes.indexOf(prototype), 1);
$scope.loading = false;
}, function(resp) {
bootbox.dialog({
"message": resp.data ? resp.data : 'The permission could not be deleted',
"title": "Cannot delete permission",
"buttons": {
"close": {
"label": "Close",
"className": "btn-primary"
}
}
});
});
};
var update = function() {
if (!$scope.organization) { return; }
if ($scope.loading) { return; }
var params = {'orgname': $scope.organization.name};
$scope.loading = true;
ApiService.getOrganizationPrototypePermissions(null, params).then(function(resp) {
$scope.prototypes = resp.prototypes;
$scope.loading = false;
});
};
$scope.$watch('organization', update);
}
};
return directiveDefinitionObject;
});
quayApp.directive('popupInputButton', function () {
var directiveDefinitionObject = {
priority: 0,

View file

@ -11,6 +11,7 @@
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#logs" ng-click="loadLogs()">Usage Logs</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#members" ng-click="loadMembers()">Members</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#robots">Robot Accounts</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#prototypes">Default Permissions</a></li>
<li ng-show="hasPaidPlan"><a href="javascript:void(0)" data-toggle="tab" data-target="#billingoptions">Billing</a></li>
<li ng-show="hasPaidPlan"><a href="javascript:void(0)" data-toggle="tab" data-target="#billing" ng-click="loadInvoices()">Billing History</a></li>
</ul>
@ -49,6 +50,11 @@
<div class="robots-manager" organization="organization"></div>
</div>
<!-- Prototypes tab -->
<div id="prototypes" class="tab-pane">
<div class="prototype-manager" organization="organization"></div>
</div>
<!-- Logs tab -->
<div id="logs" class="tab-pane">
<div class="logs-view" organization="organization" visible="logsShown"></div>

Binary file not shown.