2015-05-14 20:47:38 +00:00
|
|
|
""" List, create and manage repositories. """
|
|
|
|
|
2014-03-10 22:30:41 +00:00
|
|
|
import logging
|
2015-03-10 05:03:39 +00:00
|
|
|
import datetime
|
2015-09-15 18:33:35 +00:00
|
|
|
import features
|
2015-06-09 21:58:57 +00:00
|
|
|
|
2016-06-22 18:50:59 +00:00
|
|
|
from datetime import timedelta, datetime
|
2014-03-10 22:30:41 +00:00
|
|
|
|
2016-02-01 11:06:13 +00:00
|
|
|
from flask import request, abort
|
2014-03-10 22:30:41 +00:00
|
|
|
|
|
|
|
from data import model
|
2014-03-11 19:20:03 +00:00
|
|
|
from endpoints.api import (truthy_bool, format_date, nickname, log_action, validate_json_request,
|
2014-03-13 00:33:57 +00:00
|
|
|
require_repo_read, require_repo_write, require_repo_admin,
|
|
|
|
RepositoryParamResource, resource, query_param, parse_args, ApiResource,
|
2016-06-03 19:00:01 +00:00
|
|
|
request_error, require_scope, path_param, page_support, parse_args,
|
|
|
|
query_param, truthy_bool)
|
2016-04-11 20:20:11 +00:00
|
|
|
from endpoints.exception import Unauthorized, NotFound, InvalidRequest, ExceedsLicenseException
|
2015-11-04 21:11:15 +00:00
|
|
|
from endpoints.api.billing import lookup_allowed_private_repos, get_namespace_plan
|
2016-01-08 18:53:27 +00:00
|
|
|
from endpoints.api.subscribe import check_repository_usage
|
2014-08-19 23:05:28 +00:00
|
|
|
|
2014-03-18 23:21:27 +00:00
|
|
|
from auth.permissions import (ModifyRepositoryPermission, AdministerRepositoryPermission,
|
2015-07-15 21:25:41 +00:00
|
|
|
CreateRepositoryPermission)
|
2014-03-13 00:33:57 +00:00
|
|
|
from auth.auth_context import get_authenticated_user
|
2014-03-14 22:41:14 +00:00
|
|
|
from auth import scopes
|
2015-09-24 15:42:56 +00:00
|
|
|
from util.names import REPOSITORY_NAME_REGEX
|
2014-03-10 22:30:41 +00:00
|
|
|
|
2014-03-11 03:54:55 +00:00
|
|
|
|
2014-03-10 22:30:41 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2016-02-01 11:06:13 +00:00
|
|
|
REPOS_PER_PAGE = 100
|
2016-06-22 18:50:59 +00:00
|
|
|
MAX_DAYS_IN_3_MONTHS = 92
|
2014-03-10 22:30:41 +00:00
|
|
|
|
2015-09-15 18:33:35 +00:00
|
|
|
def check_allowed_private_repos(namespace):
|
|
|
|
""" Checks to see if the given namespace has reached its private repository limit. If so,
|
|
|
|
raises a ExceedsLicenseException.
|
|
|
|
"""
|
|
|
|
# Not enabled if billing is disabled.
|
|
|
|
if not features.BILLING:
|
|
|
|
return
|
|
|
|
|
|
|
|
if not lookup_allowed_private_repos(namespace):
|
|
|
|
raise ExceedsLicenseException()
|
|
|
|
|
|
|
|
|
2014-03-10 22:30:41 +00:00
|
|
|
@resource('/v1/repository')
|
2014-03-12 20:31:37 +00:00
|
|
|
class RepositoryList(ApiResource):
|
2014-03-11 19:20:03 +00:00
|
|
|
"""Operations for creating and listing repositories."""
|
2014-03-11 03:54:55 +00:00
|
|
|
schemas = {
|
|
|
|
'NewRepo': {
|
|
|
|
'type': 'object',
|
2014-03-11 19:20:03 +00:00
|
|
|
'description': 'Description of a new repository',
|
2014-03-17 16:25:41 +00:00
|
|
|
'required': [
|
|
|
|
'repository',
|
|
|
|
'visibility',
|
2014-03-18 19:58:37 +00:00
|
|
|
'description',
|
2014-03-17 16:25:41 +00:00
|
|
|
],
|
2014-03-11 03:54:55 +00:00
|
|
|
'properties': {
|
|
|
|
'repository': {
|
|
|
|
'type': 'string',
|
2014-03-11 19:20:03 +00:00
|
|
|
'description': 'Repository name',
|
2014-03-11 03:54:55 +00:00
|
|
|
},
|
|
|
|
'visibility': {
|
|
|
|
'type': 'string',
|
2014-03-11 19:20:03 +00:00
|
|
|
'description': 'Visibility which the repository will start with',
|
2014-03-11 03:54:55 +00:00
|
|
|
'enum': [
|
|
|
|
'public',
|
|
|
|
'private',
|
2014-03-13 00:33:57 +00:00
|
|
|
],
|
2014-03-11 03:54:55 +00:00
|
|
|
},
|
|
|
|
'namespace': {
|
|
|
|
'type': 'string',
|
2014-03-11 19:20:03 +00:00
|
|
|
'description': ('Namespace in which the repository should be created. If omitted, the '
|
|
|
|
'username of the caller is used'),
|
2014-03-11 03:54:55 +00:00
|
|
|
},
|
|
|
|
'description': {
|
|
|
|
'type': 'string',
|
2014-03-11 19:20:03 +00:00
|
|
|
'description': 'Markdown encoded description for the repository',
|
2014-03-11 03:54:55 +00:00
|
|
|
},
|
2014-03-13 20:31:37 +00:00
|
|
|
},
|
|
|
|
},
|
2014-03-11 03:54:55 +00:00
|
|
|
}
|
2014-03-10 22:30:41 +00:00
|
|
|
|
2014-03-13 00:33:57 +00:00
|
|
|
@require_scope(scopes.CREATE_REPO)
|
2014-03-10 22:30:41 +00:00
|
|
|
@nickname('createRepo')
|
2014-03-11 03:54:55 +00:00
|
|
|
@validate_json_request('NewRepo')
|
2014-03-10 22:30:41 +00:00
|
|
|
def post(self):
|
2014-03-11 19:20:03 +00:00
|
|
|
"""Create a new repository."""
|
2014-03-13 00:33:57 +00:00
|
|
|
owner = get_authenticated_user()
|
2014-03-11 03:54:55 +00:00
|
|
|
req = request.get_json()
|
2014-03-18 23:21:27 +00:00
|
|
|
|
|
|
|
if owner is None and 'namespace' not in 'req':
|
|
|
|
raise InvalidRequest('Must provide a namespace or must be logged in.')
|
|
|
|
|
2014-03-11 03:54:55 +00:00
|
|
|
namespace_name = req['namespace'] if 'namespace' in req else owner.username
|
|
|
|
|
|
|
|
permission = CreateRepositoryPermission(namespace_name)
|
|
|
|
if permission.can():
|
|
|
|
repository_name = req['repository']
|
|
|
|
visibility = req['visibility']
|
|
|
|
|
2015-07-15 21:25:41 +00:00
|
|
|
existing = model.repository.get_repository(namespace_name, repository_name)
|
2014-03-11 03:54:55 +00:00
|
|
|
if existing:
|
2014-03-17 20:57:35 +00:00
|
|
|
raise request_error(message='Repository already exists')
|
2014-03-11 03:54:55 +00:00
|
|
|
|
|
|
|
visibility = req['visibility']
|
2015-09-15 18:33:35 +00:00
|
|
|
if visibility == 'private':
|
|
|
|
check_allowed_private_repos(namespace_name)
|
2014-03-11 03:54:55 +00:00
|
|
|
|
2015-09-24 15:42:56 +00:00
|
|
|
# Verify that the repository name is valid.
|
|
|
|
if not REPOSITORY_NAME_REGEX.match(repository_name):
|
|
|
|
raise InvalidRequest('Invalid repository name')
|
|
|
|
|
2015-07-15 21:25:41 +00:00
|
|
|
repo = model.repository.create_repository(namespace_name, repository_name, owner, visibility)
|
2014-03-11 03:54:55 +00:00
|
|
|
repo.description = req['description']
|
|
|
|
repo.save()
|
|
|
|
|
2014-03-11 19:20:03 +00:00
|
|
|
log_action('create_repo', namespace_name, {'repo': repository_name,
|
|
|
|
'namespace': namespace_name}, repo=repo)
|
2014-03-13 00:33:57 +00:00
|
|
|
return {
|
2014-03-11 03:54:55 +00:00
|
|
|
'namespace': namespace_name,
|
|
|
|
'name': repository_name
|
2014-03-13 00:33:57 +00:00
|
|
|
}, 201
|
2014-03-11 03:54:55 +00:00
|
|
|
|
2014-03-17 20:57:35 +00:00
|
|
|
raise Unauthorized()
|
2014-03-10 22:30:41 +00:00
|
|
|
|
2015-07-21 21:20:24 +00:00
|
|
|
|
2014-03-19 16:09:07 +00:00
|
|
|
@require_scope(scopes.READ_REPO)
|
2014-03-10 22:30:41 +00:00
|
|
|
@nickname('listRepos')
|
2016-01-26 21:27:36 +00:00
|
|
|
@parse_args()
|
2015-07-21 21:20:24 +00:00
|
|
|
@query_param('namespace', 'Filters the repositories returned to this namespace', type=str)
|
|
|
|
@query_param('starred', 'Filters the repositories returned to those starred by the user',
|
|
|
|
type=truthy_bool, default=False)
|
|
|
|
@query_param('public', 'Adds any repositories visible to the user by virtue of being public',
|
2015-04-03 18:55:09 +00:00
|
|
|
type=truthy_bool, default=False)
|
2015-06-09 21:58:57 +00:00
|
|
|
@query_param('last_modified', 'Whether to include when the repository was last modified.',
|
|
|
|
type=truthy_bool, default=False)
|
|
|
|
@query_param('popularity', 'Whether to include the repository\'s popularity metric.',
|
|
|
|
type=truthy_bool, default=False)
|
2016-02-01 11:06:13 +00:00
|
|
|
@page_support()
|
|
|
|
def get(self, page_token, parsed_args):
|
2015-07-21 21:20:24 +00:00
|
|
|
""" Fetch the list of repositories visible to the current user under a variety of situations.
|
|
|
|
"""
|
2016-02-01 11:06:13 +00:00
|
|
|
# Ensure that the user requests either filtered by a namespace, only starred repositories,
|
|
|
|
# or public repositories. This ensures that the user is not requesting *all* visible repos,
|
|
|
|
# which can cause a surge in DB CPU usage.
|
2016-01-26 21:27:36 +00:00
|
|
|
if not parsed_args['namespace'] and not parsed_args['starred'] and not parsed_args['public']:
|
2015-10-05 21:11:49 +00:00
|
|
|
raise InvalidRequest('namespace, starred or public are required for this API call')
|
2015-02-24 22:50:54 +00:00
|
|
|
|
2016-02-01 11:06:13 +00:00
|
|
|
user = get_authenticated_user()
|
|
|
|
username = user.username if user else None
|
|
|
|
repo_query = None
|
|
|
|
|
|
|
|
# Lookup the requested repositories (either starred or non-starred.)
|
|
|
|
if parsed_args['starred']:
|
|
|
|
if not username:
|
|
|
|
# No repositories should be returned, as there is no user.
|
|
|
|
abort(400)
|
|
|
|
|
|
|
|
repo_query = model.repository.get_user_starred_repositories(user)
|
|
|
|
else:
|
|
|
|
repo_query = model.repository.get_visible_repositories(username=username,
|
|
|
|
include_public=parsed_args['public'],
|
|
|
|
namespace=parsed_args['namespace'])
|
|
|
|
|
|
|
|
# Note: We only limit repositories when there isn't a namespace or starred filter, as they
|
|
|
|
# result in far smaller queries.
|
|
|
|
if not parsed_args['namespace'] and not parsed_args['starred']:
|
2016-03-30 18:46:31 +00:00
|
|
|
repos, next_page_token = model.modelutil.paginate(repo_query, repo_query.c,
|
2016-06-30 21:31:35 +00:00
|
|
|
page_token=page_token, limit=REPOS_PER_PAGE,
|
|
|
|
id_field='rid')
|
2016-02-01 11:06:13 +00:00
|
|
|
else:
|
|
|
|
repos = list(repo_query)
|
|
|
|
next_page_token = None
|
2015-07-16 10:52:12 +00:00
|
|
|
|
|
|
|
# Collect the IDs of the repositories found for subequent lookup of popularity
|
|
|
|
# and/or last modified.
|
2016-02-01 11:06:13 +00:00
|
|
|
if parsed_args['last_modified'] or parsed_args['popularity']:
|
|
|
|
repository_ids = [repo.id for repo in repos]
|
2015-07-16 10:52:12 +00:00
|
|
|
|
2016-02-01 11:06:13 +00:00
|
|
|
if parsed_args['last_modified']:
|
|
|
|
last_modified_map = model.repository.get_when_last_modified(repository_ids)
|
|
|
|
|
|
|
|
if parsed_args['popularity']:
|
2016-06-22 18:50:59 +00:00
|
|
|
action_sum_map = model.log.get_repositories_action_sums(repository_ids)
|
2015-07-16 10:52:12 +00:00
|
|
|
|
2016-02-01 11:06:13 +00:00
|
|
|
# Collect the IDs of the repositories that are starred for the user, so we can mark them
|
|
|
|
# in the returned results.
|
|
|
|
star_set = set()
|
|
|
|
if username:
|
|
|
|
starred_repos = model.repository.get_user_starred_repositories(user)
|
|
|
|
star_set = {starred.id for starred in starred_repos}
|
2015-07-16 10:52:12 +00:00
|
|
|
|
2014-12-30 20:07:14 +00:00
|
|
|
def repo_view(repo_obj):
|
|
|
|
repo = {
|
2015-07-21 21:20:24 +00:00
|
|
|
'namespace': repo_obj.namespace_user.username,
|
|
|
|
'name': repo_obj.name,
|
|
|
|
'description': repo_obj.description,
|
2015-10-21 18:13:03 +00:00
|
|
|
'is_public': repo_obj.visibility_id == model.repository.get_public_repo_visibility().id,
|
2014-12-30 20:07:14 +00:00
|
|
|
}
|
2015-06-09 21:58:57 +00:00
|
|
|
|
2015-07-21 21:20:24 +00:00
|
|
|
repo_id = repo_obj.id
|
2015-07-16 10:52:12 +00:00
|
|
|
|
2016-01-26 21:27:36 +00:00
|
|
|
if parsed_args['last_modified']:
|
2015-07-16 10:52:12 +00:00
|
|
|
repo['last_modified'] = last_modified_map.get(repo_id)
|
2015-06-09 21:58:57 +00:00
|
|
|
|
2016-01-26 21:27:36 +00:00
|
|
|
if parsed_args['popularity']:
|
2016-06-22 18:50:59 +00:00
|
|
|
repo['popularity'] = action_sum_map.get(repo_id, 0)
|
2015-06-09 21:58:57 +00:00
|
|
|
|
2016-02-01 11:06:13 +00:00
|
|
|
if username:
|
|
|
|
repo['is_starred'] = repo_id in star_set
|
2015-06-09 21:58:57 +00:00
|
|
|
|
2014-12-30 20:07:14 +00:00
|
|
|
return repo
|
2014-03-10 22:30:41 +00:00
|
|
|
|
2015-07-21 21:20:24 +00:00
|
|
|
return {
|
2016-02-01 11:06:13 +00:00
|
|
|
'repositories': [repo_view(repo) for repo in repos]
|
|
|
|
}, next_page_token
|
2014-03-10 22:30:41 +00:00
|
|
|
|
|
|
|
|
2016-01-21 20:40:51 +00:00
|
|
|
@resource('/v1/repository/<apirepopath:repository>')
|
2014-08-19 23:05:28 +00:00
|
|
|
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
|
2014-03-10 22:30:41 +00:00
|
|
|
class Repository(RepositoryParamResource):
|
2014-03-11 19:20:03 +00:00
|
|
|
"""Operations for managing a specific repository."""
|
2014-03-13 00:33:57 +00:00
|
|
|
schemas = {
|
|
|
|
'RepoUpdate': {
|
|
|
|
'type': 'object',
|
|
|
|
'description': 'Fields which can be updated in a repository.',
|
2014-03-17 16:25:41 +00:00
|
|
|
'required': [
|
|
|
|
'description',
|
|
|
|
],
|
2014-03-13 00:33:57 +00:00
|
|
|
'properties': {
|
|
|
|
'description': {
|
|
|
|
'type': 'string',
|
|
|
|
'description': 'Markdown encoded description for the repository',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-03 19:00:01 +00:00
|
|
|
@parse_args()
|
2016-06-22 18:50:59 +00:00
|
|
|
@query_param('includeStats', 'Whether to include action statistics', type=truthy_bool,
|
2016-06-03 19:00:01 +00:00
|
|
|
default=False)
|
2014-03-10 22:30:41 +00:00
|
|
|
@require_repo_read
|
|
|
|
@nickname('getRepo')
|
2016-06-03 19:00:01 +00:00
|
|
|
def get(self, namespace, repository, parsed_args):
|
2014-03-11 19:20:03 +00:00
|
|
|
"""Fetch the specified repository."""
|
2014-03-10 22:30:41 +00:00
|
|
|
logger.debug('Get repo: %s/%s' % (namespace, repository))
|
|
|
|
|
|
|
|
def tag_view(tag):
|
2015-03-17 20:49:22 +00:00
|
|
|
tag_info = {
|
2014-03-10 22:30:41 +00:00
|
|
|
'name': tag.name,
|
2015-03-10 05:03:39 +00:00
|
|
|
'image_id': tag.image.docker_image_id,
|
2015-10-23 19:24:47 +00:00
|
|
|
'size': tag.image.aggregate_size
|
2014-03-10 22:30:41 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 20:49:22 +00:00
|
|
|
if tag.lifetime_start_ts > 0:
|
2016-06-22 18:50:59 +00:00
|
|
|
last_modified = format_date(datetime.fromtimestamp(tag.lifetime_start_ts))
|
2015-07-15 21:25:41 +00:00
|
|
|
tag_info['last_modified'] = last_modified
|
2015-03-17 20:49:22 +00:00
|
|
|
|
|
|
|
return tag_info
|
|
|
|
|
2015-07-15 21:25:41 +00:00
|
|
|
repo = model.repository.get_repository(namespace, repository)
|
2016-06-03 19:00:01 +00:00
|
|
|
stats = None
|
2014-03-10 22:30:41 +00:00
|
|
|
if repo:
|
2015-07-15 21:25:41 +00:00
|
|
|
tags = model.tag.list_repository_tags(namespace, repository, include_storage=True)
|
2014-03-10 22:30:41 +00:00
|
|
|
tag_dict = {tag.name: tag_view(tag) for tag in tags}
|
|
|
|
can_write = ModifyRepositoryPermission(namespace, repository).can()
|
|
|
|
can_admin = AdministerRepositoryPermission(namespace, repository).can()
|
|
|
|
|
2015-07-15 21:25:41 +00:00
|
|
|
is_starred = (model.repository.repository_is_starred(get_authenticated_user(), repo)
|
2015-03-10 05:03:39 +00:00
|
|
|
if get_authenticated_user() else False)
|
2015-07-15 21:25:41 +00:00
|
|
|
is_public = model.repository.is_repository_public(repo)
|
2015-03-10 05:03:39 +00:00
|
|
|
|
2016-06-03 19:00:01 +00:00
|
|
|
if parsed_args['includeStats']:
|
2016-06-22 18:50:59 +00:00
|
|
|
stats = []
|
|
|
|
found_dates = {}
|
|
|
|
|
|
|
|
start_date = datetime.now() - timedelta(days=MAX_DAYS_IN_3_MONTHS)
|
|
|
|
counts = model.log.get_repository_action_counts(repo, start_date)
|
|
|
|
for count in counts:
|
|
|
|
stats.append({
|
|
|
|
'date': count.date.isoformat(),
|
|
|
|
'count': count.count,
|
|
|
|
})
|
|
|
|
|
|
|
|
found_dates['%s/%s' % (count.date.month, count.date.day)] = True
|
|
|
|
|
|
|
|
# Fill in any missing stats with zeros.
|
2016-06-23 21:08:11 +00:00
|
|
|
for day in range(1, MAX_DAYS_IN_3_MONTHS):
|
2016-06-22 18:50:59 +00:00
|
|
|
day_date = datetime.now() - timedelta(days=day)
|
|
|
|
key = '%s/%s' % (day_date.month, day_date.day)
|
|
|
|
if not key in found_dates:
|
|
|
|
stats.append({
|
|
|
|
'date': day_date.date().isoformat(),
|
|
|
|
'count': 0,
|
|
|
|
})
|
2016-06-03 19:00:01 +00:00
|
|
|
|
|
|
|
repo_data = {
|
2014-03-10 22:30:41 +00:00
|
|
|
'namespace': namespace,
|
|
|
|
'name': repository,
|
|
|
|
'description': repo.description,
|
|
|
|
'tags': tag_dict,
|
|
|
|
'can_write': can_write,
|
|
|
|
'can_admin': can_admin,
|
|
|
|
'is_public': is_public,
|
2015-03-18 18:47:53 +00:00
|
|
|
'is_organization': repo.namespace_user.organization,
|
2015-03-10 05:03:39 +00:00
|
|
|
'is_starred': is_starred,
|
2015-03-11 00:22:46 +00:00
|
|
|
'status_token': repo.badge_token if not is_public else '',
|
2014-03-10 22:30:41 +00:00
|
|
|
}
|
|
|
|
|
2016-06-03 19:00:01 +00:00
|
|
|
if stats is not None:
|
|
|
|
repo_data['stats'] = stats
|
|
|
|
|
|
|
|
return repo_data
|
|
|
|
|
2014-03-17 20:57:35 +00:00
|
|
|
raise NotFound()
|
2014-11-24 21:07:38 +00:00
|
|
|
|
2014-03-13 00:33:57 +00:00
|
|
|
@require_repo_write
|
|
|
|
@nickname('updateRepo')
|
|
|
|
@validate_json_request('RepoUpdate')
|
|
|
|
def put(self, namespace, repository):
|
|
|
|
""" Update the description in the specified repository. """
|
2015-07-15 21:25:41 +00:00
|
|
|
repo = model.repository.get_repository(namespace, repository)
|
2014-03-13 00:33:57 +00:00
|
|
|
if repo:
|
|
|
|
values = request.get_json()
|
|
|
|
repo.description = values['description']
|
|
|
|
repo.save()
|
2014-11-24 21:07:38 +00:00
|
|
|
|
2014-03-13 00:33:57 +00:00
|
|
|
log_action('set_repo_description', namespace,
|
|
|
|
{'repo': repository, 'description': values['description']},
|
|
|
|
repo=repo)
|
|
|
|
return {
|
|
|
|
'success': True
|
|
|
|
}
|
2014-03-17 20:57:35 +00:00
|
|
|
raise NotFound()
|
2014-03-13 00:33:57 +00:00
|
|
|
|
|
|
|
@require_repo_admin
|
|
|
|
@nickname('deleteRepository')
|
|
|
|
def delete(self, namespace, repository):
|
2014-03-13 19:19:49 +00:00
|
|
|
""" Delete a repository. """
|
2015-07-15 21:25:41 +00:00
|
|
|
model.repository.purge_repository(namespace, repository)
|
2015-11-04 21:11:15 +00:00
|
|
|
user = model.user.get_namespace_user(namespace)
|
2016-01-07 19:34:19 +00:00
|
|
|
if features.BILLING:
|
|
|
|
plan = get_namespace_plan(namespace)
|
|
|
|
check_repository_usage(user, plan)
|
2014-03-13 00:33:57 +00:00
|
|
|
log_action('delete_repo', namespace,
|
|
|
|
{'repo': repository, 'namespace': namespace})
|
|
|
|
return 'Deleted', 204
|
|
|
|
|
|
|
|
|
2016-01-21 20:40:51 +00:00
|
|
|
@resource('/v1/repository/<apirepopath:repository>/changevisibility')
|
2014-08-19 23:05:28 +00:00
|
|
|
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
|
2014-03-13 00:33:57 +00:00
|
|
|
class RepositoryVisibility(RepositoryParamResource):
|
|
|
|
""" Custom verb for changing the visibility of the repository. """
|
|
|
|
schemas = {
|
|
|
|
'ChangeVisibility': {
|
|
|
|
'type': 'object',
|
|
|
|
'description': 'Change the visibility for the repository.',
|
2014-03-17 16:25:41 +00:00
|
|
|
'required': [
|
|
|
|
'visibility',
|
|
|
|
],
|
2014-03-13 00:33:57 +00:00
|
|
|
'properties': {
|
|
|
|
'visibility': {
|
|
|
|
'type': 'string',
|
|
|
|
'description': 'Visibility which the repository will start with',
|
|
|
|
'enum': [
|
|
|
|
'public',
|
|
|
|
'private',
|
|
|
|
],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@require_repo_admin
|
|
|
|
@nickname('changeRepoVisibility')
|
|
|
|
@validate_json_request('ChangeVisibility')
|
|
|
|
def post(self, namespace, repository):
|
|
|
|
""" Change the visibility of a repository. """
|
2015-07-15 21:25:41 +00:00
|
|
|
repo = model.repository.get_repository(namespace, repository)
|
2014-03-13 00:33:57 +00:00
|
|
|
if repo:
|
|
|
|
values = request.get_json()
|
2015-09-15 18:33:35 +00:00
|
|
|
visibility = values['visibility']
|
|
|
|
if visibility == 'private':
|
|
|
|
check_allowed_private_repos(namespace)
|
|
|
|
|
|
|
|
model.repository.set_repository_visibility(repo, visibility)
|
2014-03-13 00:33:57 +00:00
|
|
|
log_action('change_repo_visibility', namespace,
|
|
|
|
{'repo': repository, 'visibility': values['visibility']},
|
|
|
|
repo=repo)
|
2014-11-19 19:50:56 +00:00
|
|
|
return {'success': True}
|