This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/endpoints/api/repository.py

200 lines
6.6 KiB
Python

import logging
import json
from flask.ext.restful import Resource, reqparse, abort
from flask.ext.login import current_user
from data import model
from endpoints.api import (truthy_bool, format_date, nickname, log_action,
validate_json_request, require_repo_read,
RepositoryParamResource, resource, query_parameter,
parse_args)
from auth.permissions import (ReadRepositoryPermission,
ModifyRepositoryPermission,
AdministerRepositoryPermission)
logger = logging.getLogger(__name__)
@resource('/v1/repository')
class RepositoryList(Resource):
schemas = {
'NewRepo': {
'id': 'NewRepo',
'type': 'object',
'description': 'Description of a new repository.',
'required': [
'repository',
'visibility',
],
'properties': {
'repository': {
'type': 'string',
'description': 'Repository name.',
},
'visibility': {
'type': 'string',
'description': 'Visibility which the repository will start with.',
'enum': [
'public',
'private',
]
},
'namespace': {
'type': 'string',
'description': ('Namespace in which the repository should be '
'created. If omitted, the username of the caller is'
'used.'),
},
'description': {
'type': 'string',
'description': 'Markdown encoded description for the repository.',
},
}
}
}
@nickname('createRepo')
@validate_json_request('NewRepo')
def post(self):
owner = current_user.db_user()
req = request.get_json()
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']
existing = model.get_repository(namespace_name, repository_name)
if existing:
return request_error(message='Repository already exists')
visibility = req['visibility']
repo = model.create_repository(namespace_name, repository_name, owner,
visibility)
repo.description = req['description']
repo.save()
log_action('create_repo', namespace_name,
{'repo': repository_name, 'namespace': namespace_name},
repo=repo)
return jsonify({
'namespace': namespace_name,
'name': repository_name
})
abort(403)
@nickname('listRepos')
@parse_args
@query_parameter('page', 'Offset page number. (int)', type=int)
@query_parameter('limit', 'Limit on the number of results (int)', type=int)
@query_parameter('namespace', ('Namespace to use when querying for org '
'repositories.'), type=str)
@query_parameter('public', 'Whether to include public repositories.',
type=truthy_bool, default=True)
@query_parameter('private', 'Whether to inlcude private repositories.',
type=truthy_bool, default=True)
@query_parameter('sort', 'Whether to sort the results.', type=truthy_bool,
default=False)
@query_parameter('count', ('Whether to include a count of the total number '
'of results available.'), type=truthy_bool,
default=False)
def get(self, args):
def repo_view(repo_obj):
return {
'namespace': repo_obj.namespace,
'name': repo_obj.name,
'description': repo_obj.description,
'is_public': repo_obj.visibility.name == 'public',
}
username = None
if current_user.is_authenticated() and args['private']:
username = current_user.db_user().username
response = {}
repo_count = None
if args['count']:
repo_count = model.get_visible_repository_count(username,
include_public=args['public'],
namespace=args['namespace'])
response['count'] = repo_count
repo_query = model.get_visible_repositories(username, limit=args['limit'],
page=args['page'],
include_public=args['public'],
sort=args['sort'],
namespace=args['namespace'])
response['repositories'] = [repo_view(repo) for repo in repo_query]
return response
def image_view(image):
extended_props = image
if image.storage and image.storage.id:
extended_props = image.storage
command = extended_props.command
return {
'id': image.docker_image_id,
'created': format_date(extended_props.created),
'comment': extended_props.comment,
'command': json.loads(command) if command else None,
'ancestors': image.ancestors,
'dbid': image.id,
'size': extended_props.image_size,
}
@resource('/v1/repository/<path:repository>')
class Repository(RepositoryParamResource):
@require_repo_read
@nickname('getRepo')
def get(self, namespace, repository):
logger.debug('Get repo: %s/%s' % (namespace, repository))
def tag_view(tag):
image = model.get_tag_image(namespace, repository, tag.name)
if not image:
return {}
return {
'name': tag.name,
'image': image_view(image),
}
organization = None
try:
organization = model.get_organization(namespace)
except model.InvalidOrganizationException:
pass
is_public = model.repository_is_public(namespace, repository)
repo = model.get_repository(namespace, repository)
if repo:
tags = model.list_repository_tags(namespace, repository)
tag_dict = {tag.name: tag_view(tag) for tag in tags}
can_write = ModifyRepositoryPermission(namespace, repository).can()
can_admin = AdministerRepositoryPermission(namespace, repository).can()
active_builds = model.list_repository_builds(namespace, repository, 1,
include_inactive=False)
return {
'namespace': namespace,
'name': repository,
'description': repo.description,
'tags': tag_dict,
'can_write': can_write,
'can_admin': can_admin,
'is_public': is_public,
'is_building': len(list(active_builds)) > 0,
'is_organization': bool(organization),
'status_token': repo.badge_token if not is_public else ''
}
abort(404) # Not found