Add ability to change the visibility of a repo, and show whether the repo is private in the repo-view screen
This commit is contained in:
parent
ce7620673b
commit
4382ebfd20
6 changed files with 214 additions and 11 deletions
|
@ -165,6 +165,15 @@ def repository_is_public(namespace_name, repository_name):
|
||||||
return len(list(query)) > 0
|
return len(list(query)) > 0
|
||||||
|
|
||||||
|
|
||||||
|
def set_repository_visibility(repo, visibility):
|
||||||
|
visibility_obj = Visibility.get(name=visibility)
|
||||||
|
if not visibility_obj:
|
||||||
|
return
|
||||||
|
|
||||||
|
repo.visibility = visibility_obj
|
||||||
|
repo.save()
|
||||||
|
|
||||||
|
|
||||||
def create_repository(namespace, name, owner):
|
def create_repository(namespace, name, owner):
|
||||||
private = Visibility.get(name='private')
|
private = Visibility.get(name='private')
|
||||||
repo = Repository.create(namespace=namespace, name=name,
|
repo = Repository.create(namespace=namespace, name=name,
|
||||||
|
|
|
@ -61,7 +61,7 @@ def match_repos_api(prefix):
|
||||||
return {
|
return {
|
||||||
'namespace': repo.namespace,
|
'namespace': repo.namespace,
|
||||||
'name': repo.name,
|
'name': repo.name,
|
||||||
'description': repo.description,
|
'description': repo.description
|
||||||
}
|
}
|
||||||
|
|
||||||
username = current_user.db_user.username
|
username = current_user.db_user.username
|
||||||
|
@ -111,6 +111,23 @@ def update_repo_api(namespace, repository):
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/repository/<path:repository>/changevisibility', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@parse_repository_name
|
||||||
|
def change_repo_visibility_api(namespace, repository):
|
||||||
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
|
if permission.can():
|
||||||
|
repo = model.get_repository(namespace, repository)
|
||||||
|
if repo:
|
||||||
|
values = request.get_json()
|
||||||
|
model.set_repository_visibility(repo, values['visibility'])
|
||||||
|
return jsonify({
|
||||||
|
'success': True
|
||||||
|
})
|
||||||
|
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
def image_view(image):
|
def image_view(image):
|
||||||
return {
|
return {
|
||||||
'id': image.image_id,
|
'id': image.image_id,
|
||||||
|
@ -136,7 +153,8 @@ def get_repo_api(namespace, repository):
|
||||||
}
|
}
|
||||||
|
|
||||||
permission = ReadRepositoryPermission(namespace, repository)
|
permission = ReadRepositoryPermission(namespace, repository)
|
||||||
if permission.can() or model.repository_is_public(namespace, repository):
|
is_public = model.repository_is_public(namespace, repository)
|
||||||
|
if permission.can() or is_public:
|
||||||
repo = model.get_repository(namespace, repository)
|
repo = model.get_repository(namespace, repository)
|
||||||
if repo:
|
if repo:
|
||||||
tags = model.list_repository_tags(namespace, repository)
|
tags = model.list_repository_tags(namespace, repository)
|
||||||
|
@ -150,6 +168,7 @@ def get_repo_api(namespace, repository):
|
||||||
'tags': tag_dict,
|
'tags': tag_dict,
|
||||||
'can_write': can_write,
|
'can_write': can_write,
|
||||||
'can_admin': can_admin,
|
'can_admin': can_admin,
|
||||||
|
'is_public': is_public
|
||||||
})
|
})
|
||||||
|
|
||||||
abort(404) # Not fount
|
abort(404) # Not fount
|
||||||
|
|
|
@ -86,6 +86,33 @@ p.editable:hover i {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.repo .header .icon-container {
|
||||||
|
position: relative;
|
||||||
|
background: #eee;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 38px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo .header .icon-container .icon-lock {
|
||||||
|
font-size: 50%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -6px;
|
||||||
|
right: 0px;
|
||||||
|
background: rgb(253, 191, 191);
|
||||||
|
width: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
.repo .description {
|
.repo .description {
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
@ -272,6 +299,56 @@ p.editable:hover i {
|
||||||
width: 54px;
|
width: 54px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.repo-admin .repo-access-state .state-icon {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .repo-access-state .state-icon i {
|
||||||
|
font-size: 46px;
|
||||||
|
width: 54px;
|
||||||
|
height: 54px;
|
||||||
|
line-height: 54px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .repo-access-state {
|
||||||
|
text-align: center;
|
||||||
|
width: 520px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .repo-access-state .state-icon i.icon-lock {
|
||||||
|
background: rgb(253, 191, 191);
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .repo-access-state .state-icon i.icon-unlock-alt {
|
||||||
|
background: rgb(170, 236, 170);
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .change-access {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .change-access .alert {
|
||||||
|
color: black;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .change-access .alert .alert-content {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repo-admin .change-access:hover .alert {
|
||||||
|
background: inherit;
|
||||||
|
border: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Overrides for typeahead to work with bootstrap 3. */
|
/* Overrides for typeahead to work with bootstrap 3. */
|
||||||
|
|
||||||
.twitter-typeahead .tt-query,
|
.twitter-typeahead .tt-query,
|
||||||
|
|
|
@ -212,17 +212,36 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.askChangeAccess = function(newAccess) {
|
||||||
|
$('#make' + newAccess + 'Modal').modal({});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.changeAccess = function(newAccess) {
|
||||||
|
$('#make' + newAccess + 'Modal').modal('hide');
|
||||||
|
|
||||||
|
var visibility = {
|
||||||
|
'visibility': newAccess
|
||||||
|
};
|
||||||
|
var visibilityPost = Restangular.one('repository/' + namespace + '/' + name + '/changevisibility');
|
||||||
|
visibilityPost.customPOST(visibility).then(function() {
|
||||||
|
$scope.repo.is_public = newAccess == 'public';
|
||||||
|
}, function() {
|
||||||
|
$('#cannotchangeModal').modal({});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the repository information.
|
||||||
|
var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name);
|
||||||
|
repositoryFetch.get().then(function(repo) {
|
||||||
|
$scope.repo = repo;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch the permissions.
|
||||||
var permissionsFetch = Restangular.one('repository/' + namespace + '/' + name + '/permissions');
|
var permissionsFetch = Restangular.one('repository/' + namespace + '/' + name + '/permissions');
|
||||||
permissionsFetch.get().then(function(resp) {
|
permissionsFetch.get().then(function(resp) {
|
||||||
$rootScope.title = 'Settings - ' + namespace + '/' + name;
|
$rootScope.title = 'Settings - ' + namespace + '/' + name;
|
||||||
$scope.repo = {
|
|
||||||
'namespace': namespace,
|
|
||||||
'name': name
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.permissions = resp.permissions;
|
$scope.permissions = resp.permissions;
|
||||||
}, function() {
|
}, function() {
|
||||||
$scope.repo = null;
|
|
||||||
$scope.permissions = null;
|
$scope.permissions = null;
|
||||||
$rootScope.title = 'Unknown Repository';
|
$rootScope.title = 'Unknown Repository';
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
<i class="icon-hdd icon-large"></i> <span style="color: #aaa;"> {{repo.namespace}}</span> <span style="color: #ccc">/</span> {{repo.name}}
|
<i class="icon-hdd icon-large"></i> <span style="color: #aaa;"> {{repo.namespace}}</span> <span style="color: #ccc">/</span> {{repo.name}}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- User Access Permissions -->
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Access Permissions</div>
|
<div class="panel-heading">User Access Permissions</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|
||||||
<table class="permissions">
|
<table class="permissions">
|
||||||
|
@ -51,6 +52,33 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- Public/Private -->
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Repository Settings</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="repo-access-state" ng-show="!repo.is_public">
|
||||||
|
<div class="state-icon"><i class="icon-lock"></i></div>
|
||||||
|
|
||||||
|
This repository is currently <b>private</b>. Only users on the above access list may interact with it.
|
||||||
|
|
||||||
|
<div class="change-access">
|
||||||
|
<button class="btn btn-danger" ng-click="askChangeAccess('public')">Make Public</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="repo-access-state" ng-show="repo.is_public">
|
||||||
|
<div class="state-icon"><i class="icon-unlock-alt"></i></div>
|
||||||
|
|
||||||
|
This repository is currently <b>public</b> and visible to all users.
|
||||||
|
|
||||||
|
<div class="change-access">
|
||||||
|
<button class="btn btn-success" ng-click="askChangeAccess('private')">Make Private</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Modal message dialog -->
|
<!-- Modal message dialog -->
|
||||||
<div class="modal fade" id="cannotchangeModal">
|
<div class="modal fade" id="cannotchangeModal">
|
||||||
|
@ -71,6 +99,52 @@
|
||||||
</div><!-- /.modal -->
|
</div><!-- /.modal -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Modal message dialog -->
|
||||||
|
<div class="modal fade" id="makepublicModal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">Make Repository Public</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
Warning: This will allow <b>anyone</b> to pull from this repository
|
||||||
|
</div>
|
||||||
|
Are you sure you want to make this repository public?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger" ng-click="changeAccess('public')">Make Public</button>
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div><!-- /.modal-dialog -->
|
||||||
|
</div><!-- /.modal -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Modal message dialog -->
|
||||||
|
<div class="modal fade" id="makeprivateModal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">Make Repository Private</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
Warning: Only users on the permissions list will be able to access this repository.
|
||||||
|
</div>
|
||||||
|
Are you sure you want to make this repository private?
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-success" ng-click="changeAccess('private')">Make Private</button>
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div><!-- /.modal-dialog -->
|
||||||
|
</div><!-- /.modal -->
|
||||||
|
|
||||||
|
|
||||||
<!-- Modal message dialog -->
|
<!-- Modal message dialog -->
|
||||||
<div class="modal fade" id="onlyadminModal">
|
<div class="modal fade" id="onlyadminModal">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
|
|
|
@ -6,7 +6,12 @@
|
||||||
<!-- Repo Header -->
|
<!-- Repo Header -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h3>
|
<h3>
|
||||||
<i class="icon-hdd icon-large"></i> <span style="color: #aaa;"> {{repo.namespace}}</span> <span style="color: #ccc">/</span> {{repo.name}}
|
<span class="icon-container">
|
||||||
|
<i class="icon-lock icon-large" ng-show="!repo.is_public" title="Private Repository"></i>
|
||||||
|
<i class="icon-hdd icon-large"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span style="color: #aaa;"> {{repo.namespace}}</span> <span style="color: #ccc">/</span> {{repo.name}}
|
||||||
|
|
||||||
<span class="settings-cog" ng-show="repo.can_admin" title="Repository Settings">
|
<span class="settings-cog" ng-show="repo.can_admin" title="Repository Settings">
|
||||||
<a href="{{ '#/repository/' + repo.namespace + '/' + repo.name + '/admin' }}">
|
<a href="{{ '#/repository/' + repo.namespace + '/' + repo.name + '/admin' }}">
|
||||||
|
|
Reference in a new issue