Accidental refactor, split out legacy.py into separate sumodules and update all call sites.
This commit is contained in:
parent
2109d24483
commit
3efaa255e8
92 changed files with 4458 additions and 4269 deletions
|
@ -249,7 +249,7 @@ def require_repo_permission(permission_class, scope, allow_public=False):
|
|||
permission = permission_class(namespace, repository)
|
||||
if (permission.can() or
|
||||
(allow_public and
|
||||
model.repository_is_public(namespace, repository))):
|
||||
model.repository.repository_is_public(namespace, repository))):
|
||||
return func(self, namespace, repository, *args, **kwargs)
|
||||
raise Unauthorized()
|
||||
return wrapped
|
||||
|
@ -376,8 +376,8 @@ def log_action(kind, user_or_orgname, metadata=None, repo=None):
|
|||
metadata['oauth_token_application'] = oauth_token.application.name
|
||||
|
||||
performer = get_authenticated_user()
|
||||
model.log_action(kind, user_or_orgname, performer=performer, ip=request.remote_addr,
|
||||
metadata=metadata, repository=repo)
|
||||
model.log.log_action(kind, user_or_orgname, performer=performer, ip=request.remote_addr,
|
||||
metadata=metadata, repository=repo)
|
||||
|
||||
|
||||
def define_json_response(schema_name):
|
||||
|
|
|
@ -6,7 +6,7 @@ from flask import request
|
|||
from app import billing
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, log_action,
|
||||
related_user_resource, internal_only, Unauthorized, NotFound,
|
||||
require_user_admin, show_if, hide_if, path_param, require_scope, abort)
|
||||
require_user_admin, show_if, path_param, require_scope, abort)
|
||||
from endpoints.api.subscribe import subscribe, subscription_view
|
||||
from auth.permissions import AdministerOrganizationPermission
|
||||
from auth.auth_context import get_authenticated_user
|
||||
|
@ -225,7 +225,7 @@ class OrganizationCard(ApiResource):
|
|||
""" Get the organization's credit card. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
return get_card(organization)
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -236,7 +236,7 @@ class OrganizationCard(ApiResource):
|
|||
""" Update the orgnaization's credit card. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
token = request.get_json()['token']
|
||||
response = set_card(organization, token)
|
||||
log_action('account_change_cc', orgname)
|
||||
|
@ -288,7 +288,7 @@ class UserPlan(ApiResource):
|
|||
""" Fetch any existing subscription for the user. """
|
||||
cus = None
|
||||
user = get_authenticated_user()
|
||||
private_repos = model.get_private_repo_count(user.username)
|
||||
private_repos = model.user.get_private_repo_count(user.username)
|
||||
|
||||
if user.stripe_id:
|
||||
try:
|
||||
|
@ -345,7 +345,7 @@ class OrganizationPlan(ApiResource):
|
|||
request_data = request.get_json()
|
||||
plan = request_data['plan']
|
||||
token = request_data['token'] if 'token' in request_data else None
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
return subscribe(organization, plan, token, True) # Business plan required
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -357,8 +357,8 @@ class OrganizationPlan(ApiResource):
|
|||
cus = None
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
private_repos = model.get_private_repo_count(orgname)
|
||||
organization = model.get_organization(orgname)
|
||||
private_repos = model.user.get_private_repo_count(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
if organization.stripe_id:
|
||||
try:
|
||||
cus = billing.Customer.retrieve(organization.stripe_id)
|
||||
|
@ -406,7 +406,7 @@ class OrganizationInvoiceList(ApiResource):
|
|||
""" List the invoices for the specified orgnaization. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
if not organization.stripe_id:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -519,7 +519,7 @@ class OrganizationInvoiceFieldList(ApiResource):
|
|||
""" List the invoice fields for the organization. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
if not organization.stripe_id:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -534,7 +534,7 @@ class OrganizationInvoiceFieldList(ApiResource):
|
|||
""" Creates a new invoice field. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
if not organization.stripe_id:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -558,7 +558,7 @@ class OrganizationInvoiceField(ApiResource):
|
|||
""" Deletes the invoice field for the current user. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
if not organization.stripe_id:
|
||||
raise NotFound()
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
import logging
|
||||
import json
|
||||
import time
|
||||
import datetime
|
||||
|
||||
from flask import request, redirect
|
||||
from flask import request
|
||||
|
||||
from app import app, userfiles as user_files, build_logs, log_archive, dockerfile_build_queue
|
||||
from endpoints.api import (RepositoryParamResource, parse_args, query_param, nickname, resource,
|
||||
|
@ -14,7 +13,8 @@ from endpoints.api import (RepositoryParamResource, parse_args, query_param, nic
|
|||
path_param, InvalidRequest, require_repo_admin)
|
||||
from endpoints.building import start_build, PreparedBuild
|
||||
from endpoints.trigger import BuildTriggerHandler
|
||||
from data import model, database
|
||||
from data import database
|
||||
from data import model
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth.permissions import (ReadRepositoryPermission, ModifyRepositoryPermission,
|
||||
AdministerRepositoryPermission, AdministerOrganizationPermission)
|
||||
|
@ -122,7 +122,7 @@ def build_status_view(build_obj):
|
|||
'status': status or {},
|
||||
'subdirectory': job_config.get('build_subdir', ''),
|
||||
'tags': job_config.get('docker_tags', []),
|
||||
'manual_user': job_config.get('manual_user', None),
|
||||
'manual_user': job_config.get('manual_user', None),
|
||||
'is_writer': can_write,
|
||||
'trigger': trigger_view(build_obj.trigger, can_read, can_admin, for_build=True),
|
||||
'trigger_metadata': job_config.get('trigger_metadata', None) if can_read else None,
|
||||
|
@ -192,7 +192,7 @@ class RepositoryBuildList(RepositoryParamResource):
|
|||
if since is not None:
|
||||
since = datetime.datetime.utcfromtimestamp(since)
|
||||
|
||||
builds = model.list_repository_builds(namespace, repository, limit, since=since)
|
||||
builds = model.build.list_repository_builds(namespace, repository, limit, since=since)
|
||||
return {
|
||||
'builds': [build_status_view(build) for build in builds]
|
||||
}
|
||||
|
@ -214,12 +214,13 @@ class RepositoryBuildList(RepositoryParamResource):
|
|||
if pull_robot_name:
|
||||
result = parse_robot_username(pull_robot_name)
|
||||
if result:
|
||||
pull_robot = model.lookup_robot(pull_robot_name)
|
||||
if not pull_robot:
|
||||
try:
|
||||
model.user.lookup_robot(pull_robot_name)
|
||||
except model.InvalidRobotException:
|
||||
raise NotFound()
|
||||
|
||||
# Make sure the user has administer permissions for the robot's namespace.
|
||||
(robot_namespace, shortname) = result
|
||||
(robot_namespace, _) = result
|
||||
if not AdministerOrganizationPermission(robot_namespace).can():
|
||||
raise Unauthorized()
|
||||
else:
|
||||
|
@ -228,14 +229,14 @@ class RepositoryBuildList(RepositoryParamResource):
|
|||
# Check if the dockerfile resource has already been used. If so, then it
|
||||
# can only be reused if the user has access to the repository in which the
|
||||
# dockerfile was previously built.
|
||||
associated_repository = model.get_repository_for_resource(dockerfile_id)
|
||||
associated_repository = model.build.get_repository_for_resource(dockerfile_id)
|
||||
if associated_repository:
|
||||
if not ModifyRepositoryPermission(associated_repository.namespace_user.username,
|
||||
associated_repository.name):
|
||||
raise Unauthorized()
|
||||
|
||||
# Start the build.
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
|
||||
prepared = PreparedBuild()
|
||||
prepared.build_name = user_files.get_file_checksum(dockerfile_id)
|
||||
|
@ -267,8 +268,8 @@ class RepositoryBuildResource(RepositoryParamResource):
|
|||
def get(self, namespace, repository, build_uuid):
|
||||
""" Returns information about a build. """
|
||||
try:
|
||||
build = model.get_repository_build(build_uuid)
|
||||
except model.InvalidRepositoryBuildException:
|
||||
build = model.build.get_repository_build(build_uuid)
|
||||
except model.build.InvalidRepositoryBuildException:
|
||||
raise NotFound()
|
||||
|
||||
return build_status_view(build)
|
||||
|
@ -278,14 +279,14 @@ class RepositoryBuildResource(RepositoryParamResource):
|
|||
def delete(self, namespace, repository, build_uuid):
|
||||
""" Cancels a repository build if it has not yet been picked up by a build worker. """
|
||||
try:
|
||||
build = model.get_repository_build(build_uuid)
|
||||
except model.InvalidRepositoryBuildException:
|
||||
build = model.build.get_repository_build(build_uuid)
|
||||
except model.build.InvalidRepositoryBuildException:
|
||||
raise NotFound()
|
||||
|
||||
if build.repository.name != repository or build.repository.namespace_user.username != namespace:
|
||||
raise NotFound()
|
||||
|
||||
if model.cancel_repository_build(build, dockerfile_build_queue):
|
||||
if model.build.cancel_repository_build(build, dockerfile_build_queue):
|
||||
return 'Okay', 201
|
||||
else:
|
||||
raise InvalidRequest('Build is currently running or has finished')
|
||||
|
@ -300,7 +301,7 @@ class RepositoryBuildStatus(RepositoryParamResource):
|
|||
@nickname('getRepoBuildStatus')
|
||||
def get(self, namespace, repository, build_uuid):
|
||||
""" Return the status for the builds specified by the build uuids. """
|
||||
build = model.get_repository_build(build_uuid)
|
||||
build = model.build.get_repository_build(build_uuid)
|
||||
if (not build or build.repository.name != repository or
|
||||
build.repository.namespace_user.username != namespace):
|
||||
raise NotFound()
|
||||
|
@ -319,7 +320,7 @@ class RepositoryBuildLogs(RepositoryParamResource):
|
|||
""" Return the build logs for the build specified by the build uuid. """
|
||||
response_obj = {}
|
||||
|
||||
build = model.get_repository_build(build_uuid)
|
||||
build = model.build.get_repository_build(build_uuid)
|
||||
if (not build or build.repository.name != repository or
|
||||
build.repository.namespace_user.username != namespace):
|
||||
raise NotFound()
|
||||
|
|
|
@ -24,7 +24,7 @@ def image_view(image, image_map, include_locations=True, include_ancestors=True)
|
|||
|
||||
return image_map[aid].docker_image_id
|
||||
|
||||
image_data = {
|
||||
image_data = {
|
||||
'id': image.docker_image_id,
|
||||
'created': format_date(extended_props.created),
|
||||
'comment': extended_props.comment,
|
||||
|
@ -60,8 +60,8 @@ class RepositoryImageList(RepositoryParamResource):
|
|||
@nickname('listRepositoryImages')
|
||||
def get(self, namespace, repository):
|
||||
""" List the images for the specified repository. """
|
||||
all_images = model.get_repository_images(namespace, repository)
|
||||
all_tags = model.list_repository_tags(namespace, repository)
|
||||
all_images = model.image.get_repository_images(namespace, repository)
|
||||
all_tags = model.tag.list_repository_tags(namespace, repository)
|
||||
|
||||
tags_by_image_id = defaultdict(list)
|
||||
found_image_ids = set()
|
||||
|
@ -96,13 +96,13 @@ class RepositoryImage(RepositoryParamResource):
|
|||
@nickname('getImage')
|
||||
def get(self, namespace, repository, image_id):
|
||||
""" Get the information available for the specified image. """
|
||||
image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if not image:
|
||||
raise NotFound()
|
||||
|
||||
# Lookup all the ancestor images for the image.
|
||||
image_map = {}
|
||||
for current_image in model.get_parent_images(namespace, repository, image):
|
||||
for current_image in model.image.get_parent_images(namespace, repository, image):
|
||||
image_map[str(current_image.id)] = current_image
|
||||
|
||||
return historical_image_view(image, image_map)
|
||||
|
@ -119,7 +119,7 @@ class RepositoryImageChanges(RepositoryParamResource):
|
|||
@nickname('getImageChanges')
|
||||
def get(self, namespace, repository, image_id):
|
||||
""" Get the list of changes for the specified image. """
|
||||
image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
|
||||
if not image:
|
||||
raise NotFound()
|
||||
|
|
|
@ -37,7 +37,7 @@ def log_view(log):
|
|||
def get_logs(start_time, end_time, performer_name=None, repository=None, namespace=None):
|
||||
performer = None
|
||||
if performer_name:
|
||||
performer = model.get_user(performer_name)
|
||||
performer = model.user.get_user(performer_name)
|
||||
|
||||
if start_time:
|
||||
try:
|
||||
|
@ -58,8 +58,8 @@ def get_logs(start_time, end_time, performer_name=None, repository=None, namespa
|
|||
if not end_time:
|
||||
end_time = datetime.today()
|
||||
|
||||
logs = model.list_logs(start_time, end_time, performer=performer, repository=repository,
|
||||
namespace=namespace)
|
||||
logs = model.log.list_logs(start_time, end_time, performer=performer, repository=repository,
|
||||
namespace=namespace)
|
||||
return {
|
||||
'start_time': format_date(start_time),
|
||||
'end_time': format_date(end_time),
|
||||
|
@ -78,7 +78,7 @@ class RepositoryLogs(RepositoryParamResource):
|
|||
@query_param('endtime', 'Latest time to which to get logs (%m/%d/%Y %Z)', type=str)
|
||||
def get(self, args, namespace, repository):
|
||||
""" List the logs for the specified repository. """
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
raise NotFound()
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import logging
|
|||
|
||||
from flask import request
|
||||
|
||||
import features
|
||||
|
||||
from app import billing as stripe, avatar
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error,
|
||||
related_user_resource, internal_only, Unauthorized, NotFound,
|
||||
|
@ -11,15 +13,13 @@ from endpoints.api import (resource, nickname, ApiResource, validate_json_reques
|
|||
require_scope)
|
||||
from endpoints.api.team import team_view
|
||||
from endpoints.api.user import User, PrivateRepositories
|
||||
from auth.permissions import (AdministerOrganizationPermission, OrganizationMemberPermission,
|
||||
from auth.permissions import (AdministerOrganizationPermission, OrganizationMemberPermission,
|
||||
CreateRepositoryPermission)
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from data import model
|
||||
from data.billing import get_plan
|
||||
|
||||
import features
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -38,7 +38,7 @@ def org_view(o, teams):
|
|||
}
|
||||
|
||||
if teams is not None:
|
||||
teams = sorted(teams, key=lambda team:team.id)
|
||||
teams = sorted(teams, key=lambda team: team.id)
|
||||
view['teams'] = {t.name : team_view(o.username, t) for t in teams}
|
||||
view['ordered_teams'] = [team.name for team in teams]
|
||||
|
||||
|
@ -84,22 +84,19 @@ class OrganizationList(ApiResource):
|
|||
existing = None
|
||||
|
||||
try:
|
||||
existing = model.get_organization(org_data['name'])
|
||||
existing = model.organization.get_organization(org_data['name'])
|
||||
except model.InvalidOrganizationException:
|
||||
pass
|
||||
|
||||
if not existing:
|
||||
try:
|
||||
existing = model.get_user(org_data['name'])
|
||||
except model.InvalidUserException:
|
||||
pass
|
||||
existing = model.user.get_user(org_data['name'])
|
||||
|
||||
if existing:
|
||||
msg = 'A user or organization with this name already exists'
|
||||
raise request_error(message=msg)
|
||||
|
||||
try:
|
||||
model.create_organization(org_data['name'], org_data['email'], user)
|
||||
model.organization.create_organization(org_data['name'], org_data['email'], user)
|
||||
return 'Created', 201
|
||||
except model.DataModelException as ex:
|
||||
raise request_error(exception=ex)
|
||||
|
@ -138,13 +135,13 @@ class Organization(ApiResource):
|
|||
def get(self, orgname):
|
||||
""" Get the details for the specified organization """
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
teams = None
|
||||
if OrganizationMemberPermission(orgname).can():
|
||||
teams = model.get_teams_within_org(org)
|
||||
teams = model.team.get_teams_within_org(org)
|
||||
|
||||
return org_view(org, teams)
|
||||
|
||||
|
@ -157,28 +154,28 @@ class Organization(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
org_data = request.get_json()
|
||||
if 'invoice_email' in org_data:
|
||||
logger.debug('Changing invoice_email for organization: %s', org.username)
|
||||
model.change_invoice_email(org, org_data['invoice_email'])
|
||||
model.user.change_invoice_email(org, org_data['invoice_email'])
|
||||
|
||||
if 'email' in org_data and org_data['email'] != org.email:
|
||||
new_email = org_data['email']
|
||||
if model.find_user_by_email(new_email):
|
||||
if model.user.find_user_by_email(new_email):
|
||||
raise request_error(message='E-mail address already used')
|
||||
|
||||
logger.debug('Changing email address for organization: %s', org.username)
|
||||
model.update_email(org, new_email)
|
||||
model.user.update_email(org, new_email)
|
||||
|
||||
if 'tag_expiration' in org_data:
|
||||
logger.debug('Changing organization tag expiration to: %ss', org_data['tag_expiration'])
|
||||
model.change_user_tag_expiration(org, org_data['tag_expiration'])
|
||||
model.user.change_user_tag_expiration(org, org_data['tag_expiration'])
|
||||
|
||||
teams = model.get_teams_within_org(org)
|
||||
teams = model.team.get_teams_within_org(org)
|
||||
return org_view(org, teams)
|
||||
raise Unauthorized()
|
||||
|
||||
|
@ -197,8 +194,8 @@ class OrgPrivateRepositories(ApiResource):
|
|||
""" Return whether or not this org is allowed to create new private repositories. """
|
||||
permission = CreateRepositoryPermission(orgname)
|
||||
if permission.can():
|
||||
organization = model.get_organization(orgname)
|
||||
private_repos = model.get_private_repo_count(organization.username)
|
||||
organization = model.organization.get_organization(orgname)
|
||||
private_repos = model.user.get_private_repo_count(organization.username)
|
||||
data = {
|
||||
'privateAllowed': False
|
||||
}
|
||||
|
@ -234,7 +231,7 @@ class OrganizationMemberList(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -242,7 +239,7 @@ class OrganizationMemberList(ApiResource):
|
|||
# will return an entry for *every team* a member is on, so we will have
|
||||
# duplicate keys (which is why we pre-build the dictionary).
|
||||
members_dict = {}
|
||||
members = model.list_organization_members_by_teams(org)
|
||||
members = model.team.list_organization_members_by_teams(org)
|
||||
for member in members:
|
||||
if member.user.robot:
|
||||
continue
|
||||
|
@ -264,7 +261,7 @@ class OrganizationMemberList(ApiResource):
|
|||
})
|
||||
|
||||
# Loop to add direct repository permissions.
|
||||
for permission in model.list_organization_member_permissions(org):
|
||||
for permission in model.permission.list_organization_member_permissions(org):
|
||||
username = permission.user.username
|
||||
if not username in members_dict:
|
||||
continue
|
||||
|
@ -292,17 +289,17 @@ class OrganizationMember(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
# Lookup the user.
|
||||
user = model.get_nonrobot_user(membername)
|
||||
user = model.user.get_nonrobot_user(membername)
|
||||
if not user:
|
||||
raise NotFound()
|
||||
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
# Remove the user from the organization.
|
||||
model.remove_organization_member(org, user)
|
||||
model.organization.remove_organization_member(org, user)
|
||||
return 'Deleted', 204
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -391,7 +388,7 @@ class OrganizationApplications(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -408,18 +405,16 @@ class OrganizationApplications(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
app_data = request.get_json()
|
||||
application = model.oauth.create_application(
|
||||
org, app_data['name'],
|
||||
app_data.get('application_uri', ''),
|
||||
app_data.get('redirect_uri', ''),
|
||||
description = app_data.get('description', ''),
|
||||
avatar_email = app_data.get('avatar_email', None),)
|
||||
|
||||
application = model.oauth.create_application(org, app_data['name'],
|
||||
app_data.get('application_uri', ''),
|
||||
app_data.get('redirect_uri', ''),
|
||||
description=app_data.get('description', ''),
|
||||
avatar_email=app_data.get('avatar_email', None))
|
||||
|
||||
app_data.update({
|
||||
'application_name': application.name,
|
||||
|
@ -479,7 +474,7 @@ class OrganizationApplicationResource(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -499,7 +494,7 @@ class OrganizationApplicationResource(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -532,7 +527,7 @@ class OrganizationApplicationResource(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -559,7 +554,7 @@ class OrganizationApplicationResetClientSecret(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ def wrap_role_view_user(role_json, user):
|
|||
role_json['name'] = user.username
|
||||
role_json['is_robot'] = user.robot
|
||||
if not user.robot:
|
||||
role_json['avatar'] = avatar.get_data_for_user(user)
|
||||
role_json['avatar'] = avatar.get_data_for_user(user)
|
||||
return role_json
|
||||
|
||||
|
||||
|
@ -46,7 +46,7 @@ class RepositoryTeamPermissionList(RepositoryParamResource):
|
|||
@nickname('listRepoTeamPermissions')
|
||||
def get(self, namespace, repository):
|
||||
""" List all team permission. """
|
||||
repo_perms = model.get_all_repo_teams(namespace, repository)
|
||||
repo_perms = model.permission.get_all_repo_teams(namespace, repository)
|
||||
|
||||
def wrapped_role_view(repo_perm):
|
||||
return wrap_role_view_team(role_view(repo_perm), repo_perm.team)
|
||||
|
@ -68,7 +68,7 @@ class RepositoryUserPermissionList(RepositoryParamResource):
|
|||
# Lookup the organization (if any).
|
||||
org = None
|
||||
try:
|
||||
org = model.get_organization(namespace) # Will raise an error if not org
|
||||
org = model.organization.get_organization(namespace) # Will raise an error if not org
|
||||
except model.InvalidOrganizationException:
|
||||
# This repository isn't under an org
|
||||
pass
|
||||
|
@ -80,7 +80,7 @@ class RepositoryUserPermissionList(RepositoryParamResource):
|
|||
role_view_func = wrapped_role_view
|
||||
|
||||
if org:
|
||||
org_members = model.get_organization_member_set(namespace)
|
||||
org_members = model.organization.get_organization_member_set(namespace)
|
||||
current_func = role_view_func
|
||||
|
||||
def wrapped_role_org_view(repo_perm):
|
||||
|
@ -90,7 +90,7 @@ class RepositoryUserPermissionList(RepositoryParamResource):
|
|||
role_view_func = wrapped_role_org_view
|
||||
|
||||
# Load and return the permissions.
|
||||
repo_perms = model.get_all_repo_users(namespace, repository)
|
||||
repo_perms = model.user.get_all_repo_users(namespace, repository)
|
||||
return {
|
||||
'permissions': {perm.user.username: role_view_func(perm)
|
||||
for perm in repo_perms}
|
||||
|
@ -107,15 +107,15 @@ class RepositoryUserTransitivePermission(RepositoryParamResource):
|
|||
@nickname('getUserTransitivePermission')
|
||||
def get(self, namespace, repository, username):
|
||||
""" Get the fetch the permission for the specified user. """
|
||||
user = model.get_user(username)
|
||||
user = model.user.get_user(username)
|
||||
if not user:
|
||||
raise NotFound
|
||||
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
raise NotFound
|
||||
|
||||
permissions = list(model.get_user_repo_permissions(user, repo))
|
||||
permissions = list(model.permission.get_user_repo_permissions(user, repo))
|
||||
return {
|
||||
'permissions': [role_view(permission) for permission in permissions]
|
||||
}
|
||||
|
@ -152,14 +152,13 @@ class RepositoryUserPermission(RepositoryParamResource):
|
|||
@nickname('getUserPermissions')
|
||||
def get(self, namespace, repository, username):
|
||||
""" Get the Fetch the permission for the specified user. """
|
||||
logger.debug('Get repo: %s/%s permissions for user %s' %
|
||||
(namespace, repository, username))
|
||||
perm = model.get_user_reponame_permission(username, namespace, repository)
|
||||
logger.debug('Get repo: %s/%s permissions for user %s', namespace, repository, username)
|
||||
perm = model.permission.get_user_reponame_permission(username, namespace, repository)
|
||||
perm_view = wrap_role_view_user(role_view(perm), perm.user)
|
||||
|
||||
try:
|
||||
model.get_organization(namespace)
|
||||
org_members = model.get_organization_member_set(namespace)
|
||||
model.organization.get_organization(namespace)
|
||||
org_members = model.organization.get_organization_member_set(namespace)
|
||||
perm_view = wrap_role_view_org(perm_view, perm.user, org_members)
|
||||
except model.InvalidOrganizationException:
|
||||
# This repository is not part of an organization
|
||||
|
@ -174,20 +173,19 @@ class RepositoryUserPermission(RepositoryParamResource):
|
|||
""" Update the perimssions for an existing repository. """
|
||||
new_permission = request.get_json()
|
||||
|
||||
logger.debug('Setting permission to: %s for user %s' %
|
||||
(new_permission['role'], username))
|
||||
logger.debug('Setting permission to: %s for user %s', new_permission['role'], username)
|
||||
|
||||
try:
|
||||
perm = model.set_user_repo_permission(username, namespace, repository,
|
||||
new_permission['role'])
|
||||
except model.InvalidUsernameException as ex:
|
||||
perm = model.permission.set_user_repo_permission(username, namespace, repository,
|
||||
new_permission['role'])
|
||||
except model.DataModelException as ex:
|
||||
raise request_error(exception=ex)
|
||||
|
||||
perm_view = wrap_role_view_user(role_view(perm), perm.user)
|
||||
|
||||
try:
|
||||
model.get_organization(namespace)
|
||||
org_members = model.get_organization_member_set(namespace)
|
||||
model.organization.get_organization(namespace)
|
||||
org_members = model.organization.get_organization_member_set(namespace)
|
||||
perm_view = wrap_role_view_org(perm_view, perm.user, org_members)
|
||||
except model.InvalidOrganizationException:
|
||||
# This repository is not part of an organization
|
||||
|
@ -198,7 +196,7 @@ class RepositoryUserPermission(RepositoryParamResource):
|
|||
log_action('change_repo_permission', namespace,
|
||||
{'username': username, 'repo': repository,
|
||||
'role': new_permission['role']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return perm_view, 200
|
||||
|
||||
|
@ -207,13 +205,13 @@ class RepositoryUserPermission(RepositoryParamResource):
|
|||
def delete(self, namespace, repository, username):
|
||||
""" Delete the permission for the user. """
|
||||
try:
|
||||
model.delete_user_permission(username, namespace, repository)
|
||||
model.permission.delete_user_permission(username, namespace, repository)
|
||||
except model.DataModelException as ex:
|
||||
raise request_error(exception=ex)
|
||||
|
||||
log_action('delete_repo_permission', namespace,
|
||||
{'username': username, 'repo': repository},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return 'Deleted', 204
|
||||
|
||||
|
@ -249,9 +247,8 @@ class RepositoryTeamPermission(RepositoryParamResource):
|
|||
@nickname('getTeamPermissions')
|
||||
def get(self, namespace, repository, teamname):
|
||||
""" Fetch the permission for the specified team. """
|
||||
logger.debug('Get repo: %s/%s permissions for team %s' %
|
||||
(namespace, repository, teamname))
|
||||
perm = model.get_team_reponame_permission(teamname, namespace, repository)
|
||||
logger.debug('Get repo: %s/%s permissions for team %s', namespace, repository, teamname)
|
||||
perm = model.permission.get_team_reponame_permission(teamname, namespace, repository)
|
||||
return role_view(perm)
|
||||
|
||||
@require_repo_admin
|
||||
|
@ -261,16 +258,15 @@ class RepositoryTeamPermission(RepositoryParamResource):
|
|||
""" Update the existing team permission. """
|
||||
new_permission = request.get_json()
|
||||
|
||||
logger.debug('Setting permission to: %s for team %s' %
|
||||
(new_permission['role'], teamname))
|
||||
logger.debug('Setting permission to: %s for team %s', new_permission['role'], teamname)
|
||||
|
||||
perm = model.set_team_repo_permission(teamname, namespace, repository,
|
||||
new_permission['role'])
|
||||
perm = model.permission.set_team_repo_permission(teamname, namespace, repository,
|
||||
new_permission['role'])
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'team': teamname, 'repo': repository,
|
||||
'role': new_permission['role']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return wrap_role_view_team(role_view(perm), perm.team), 200
|
||||
|
||||
|
@ -278,10 +274,10 @@ class RepositoryTeamPermission(RepositoryParamResource):
|
|||
@nickname('deleteTeamPermissions')
|
||||
def delete(self, namespace, repository, teamname):
|
||||
""" Delete the permission for the specified team. """
|
||||
model.delete_team_permission(teamname, namespace, repository)
|
||||
model.permission.delete_team_permission(teamname, namespace, repository)
|
||||
|
||||
log_action('delete_repo_permission', namespace,
|
||||
{'team': teamname, 'repo': repository},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return 'Deleted', 204
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
from flask import request
|
||||
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error,
|
||||
log_action, Unauthorized, NotFound, internal_only, path_param,
|
||||
require_scope)
|
||||
log_action, Unauthorized, NotFound, path_param, require_scope)
|
||||
from auth.permissions import AdministerOrganizationPermission
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
|
@ -129,12 +128,12 @@ class PermissionPrototypeList(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
permissions = model.get_prototype_permissions(org)
|
||||
org_members = model.get_organization_member_set(orgname)
|
||||
permissions = model.permission.get_prototype_permissions(org)
|
||||
org_members = model.organization.get_organization_member_set(orgname)
|
||||
return {'prototypes': [prototype_view(p, org_members) for p in permissions]}
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -147,7 +146,7 @@ class PermissionPrototypeList(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -165,9 +164,9 @@ class PermissionPrototypeList(ApiResource):
|
|||
delegate_username = delegate_name if delegate_kind == 'user' else None
|
||||
delegate_teamname = delegate_name if delegate_kind == 'team' else None
|
||||
|
||||
activating_user = (model.get_user(activating_username) if activating_username else None)
|
||||
delegate_user = (model.get_user(delegate_username) if delegate_username else None)
|
||||
delegate_team = (model.get_organization_team(orgname, delegate_teamname)
|
||||
activating_user = (model.user.get_user(activating_username) if activating_username else None)
|
||||
delegate_user = (model.user.get_user(delegate_username) if delegate_username else None)
|
||||
delegate_team = (model.team.get_organization_team(orgname, delegate_teamname)
|
||||
if delegate_teamname else None)
|
||||
|
||||
if activating_username and not activating_user:
|
||||
|
@ -178,10 +177,10 @@ class PermissionPrototypeList(ApiResource):
|
|||
|
||||
role_name = details['role']
|
||||
|
||||
prototype = model.add_prototype_permission(org, role_name, activating_user,
|
||||
delegate_user, delegate_team)
|
||||
prototype = model.permission.add_prototype_permission(org, role_name, activating_user,
|
||||
delegate_user, delegate_team)
|
||||
log_prototype_action('create_prototype_permission', orgname, prototype)
|
||||
org_members = model.get_organization_member_set(orgname)
|
||||
org_members = model.organization.get_organization_member_set(orgname)
|
||||
return prototype_view(prototype, org_members)
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -221,11 +220,11 @@ class PermissionPrototype(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
prototype = model.delete_prototype_permission(org, prototypeid)
|
||||
prototype = model.permission.delete_prototype_permission(org, prototypeid)
|
||||
if not prototype:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -243,23 +242,23 @@ class PermissionPrototype(ApiResource):
|
|||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
try:
|
||||
org = model.get_organization(orgname)
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
raise NotFound()
|
||||
|
||||
existing = model.get_prototype_permission(org, prototypeid)
|
||||
existing = model.permission.get_prototype_permission(org, prototypeid)
|
||||
if not existing:
|
||||
raise NotFound()
|
||||
|
||||
details = request.get_json()
|
||||
role_name = details['role']
|
||||
prototype = model.update_prototype_permission(org, prototypeid, role_name)
|
||||
prototype = model.permission.update_prototype_permission(org, prototypeid, role_name)
|
||||
if not prototype:
|
||||
raise NotFound()
|
||||
|
||||
log_prototype_action('modify_prototype_permission', orgname, prototype,
|
||||
original_role=existing.role.name)
|
||||
org_members = model.get_organization_member_set(orgname)
|
||||
org_members = model.organization.get_organization_member_set(orgname)
|
||||
return prototype_view(prototype, org_members)
|
||||
|
||||
raise Unauthorized()
|
||||
|
|
|
@ -18,6 +18,7 @@ import features
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def record_view(record):
|
||||
return {
|
||||
'email': record.email,
|
||||
|
@ -38,7 +39,7 @@ class RepositoryAuthorizedEmail(RepositoryParamResource):
|
|||
@nickname('checkRepoEmailAuthorized')
|
||||
def get(self, namespace, repository, email):
|
||||
""" Checks to see if the given e-mail address is authorized on this repository. """
|
||||
record = model.get_email_authorized_for_repo(namespace, repository, email)
|
||||
record = model.repository.get_email_authorized_for_repo(namespace, repository, email)
|
||||
if not record:
|
||||
abort(404)
|
||||
|
||||
|
@ -51,12 +52,12 @@ class RepositoryAuthorizedEmail(RepositoryParamResource):
|
|||
""" Starts the authorization process for an e-mail address on a repository. """
|
||||
|
||||
with tf(db):
|
||||
record = model.get_email_authorized_for_repo(namespace, repository, email)
|
||||
record = model.repository.get_email_authorized_for_repo(namespace, repository, email)
|
||||
if record and record.confirmed:
|
||||
return record_view(record)
|
||||
|
||||
if not record:
|
||||
record = model.create_email_authorization_for_repo(namespace, repository, email)
|
||||
record = model.repository.create_email_authorization_for_repo(namespace, repository, email)
|
||||
|
||||
send_repo_authorization_email(namespace, repository, email, record.code)
|
||||
return record_view(record)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
""" List, create and manage repositories. """
|
||||
|
||||
import logging
|
||||
import json
|
||||
import datetime
|
||||
|
||||
from datetime import timedelta
|
||||
|
@ -9,9 +8,8 @@ from datetime import timedelta
|
|||
from flask import request
|
||||
|
||||
from data import model
|
||||
from data.model import Namespace
|
||||
from data.database import (Repository as RepositoryTable, Visibility, RepositoryTag,
|
||||
RepositoryActionCount, fn)
|
||||
RepositoryActionCount, Namespace, fn)
|
||||
|
||||
from endpoints.api import (truthy_bool, format_date, nickname, log_action, validate_json_request,
|
||||
require_repo_read, require_repo_write, require_repo_admin,
|
||||
|
@ -20,7 +18,7 @@ from endpoints.api import (truthy_bool, format_date, nickname, log_action, valid
|
|||
path_param)
|
||||
|
||||
from auth.permissions import (ModifyRepositoryPermission, AdministerRepositoryPermission,
|
||||
CreateRepositoryPermission, ReadRepositoryPermission)
|
||||
CreateRepositoryPermission)
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
|
||||
|
@ -85,13 +83,13 @@ class RepositoryList(ApiResource):
|
|||
repository_name = req['repository']
|
||||
visibility = req['visibility']
|
||||
|
||||
existing = model.get_repository(namespace_name, repository_name)
|
||||
existing = model.repository.get_repository(namespace_name, repository_name)
|
||||
if existing:
|
||||
raise request_error(message='Repository already exists')
|
||||
|
||||
visibility = req['visibility']
|
||||
|
||||
repo = model.create_repository(namespace_name, repository_name, owner, visibility)
|
||||
repo = model.repository.create_repository(namespace_name, repository_name, owner, visibility)
|
||||
repo.description = req['description']
|
||||
repo.save()
|
||||
|
||||
|
@ -124,7 +122,7 @@ class RepositoryList(ApiResource):
|
|||
"""Fetch the list of repositories under a variety of situations."""
|
||||
username = None
|
||||
if get_authenticated_user():
|
||||
starred_repos = model.get_user_starred_repositories(get_authenticated_user())
|
||||
starred_repos = model.repository.get_user_starred_repositories(get_authenticated_user())
|
||||
star_lookup = set([repo.id for repo in starred_repos])
|
||||
|
||||
if args['private']:
|
||||
|
@ -133,22 +131,22 @@ class RepositoryList(ApiResource):
|
|||
response = {}
|
||||
|
||||
# Find the matching repositories.
|
||||
repo_query = model.get_visible_repositories(username,
|
||||
limit=args['limit'],
|
||||
page=args['page'],
|
||||
include_public=args['public'],
|
||||
namespace=args['namespace'],
|
||||
namespace_only=args['namespace_only'])
|
||||
repo_query = model.repository.get_visible_repositories(username,
|
||||
limit=args['limit'],
|
||||
page=args['page'],
|
||||
include_public=args['public'],
|
||||
namespace=args['namespace'],
|
||||
namespace_only=args['namespace_only'])
|
||||
|
||||
# Collect the IDs of the repositories found for subequent lookup of popularity
|
||||
# and/or last modified.
|
||||
repository_ids = [repo.get(RepositoryTable.id) for repo in repo_query]
|
||||
|
||||
if args['last_modified']:
|
||||
last_modified_map = model.get_when_last_modified(repository_ids)
|
||||
last_modified_map = model.repository.get_when_last_modified(repository_ids)
|
||||
|
||||
if args['popularity']:
|
||||
action_count_map = model.get_action_counts(repository_ids)
|
||||
action_count_map = model.repository.get_action_counts(repository_ids)
|
||||
|
||||
def repo_view(repo_obj):
|
||||
repo = {
|
||||
|
@ -210,26 +208,27 @@ class Repository(RepositoryParamResource):
|
|||
}
|
||||
|
||||
if tag.lifetime_start_ts > 0:
|
||||
tag_info['last_modified'] = format_date(datetime.datetime.fromtimestamp(tag.lifetime_start_ts))
|
||||
last_modified = format_date(datetime.datetime.fromtimestamp(tag.lifetime_start_ts))
|
||||
tag_info['last_modified'] = last_modified
|
||||
|
||||
return tag_info
|
||||
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if repo:
|
||||
tags = model.list_repository_tags(namespace, repository, include_storage=True)
|
||||
tags = model.tag.list_repository_tags(namespace, repository, include_storage=True)
|
||||
tag_dict = {tag.name: tag_view(tag) for tag in tags}
|
||||
can_write = ModifyRepositoryPermission(namespace, repository).can()
|
||||
can_admin = AdministerRepositoryPermission(namespace, repository).can()
|
||||
|
||||
is_starred = (model.repository_is_starred(get_authenticated_user(), repo)
|
||||
is_starred = (model.repository.repository_is_starred(get_authenticated_user(), repo)
|
||||
if get_authenticated_user() else False)
|
||||
is_public = model.is_repository_public(repo)
|
||||
is_public = model.repository.is_repository_public(repo)
|
||||
|
||||
(pull_today, pull_thirty_day) = model.get_repository_pulls(repo, timedelta(days=1),
|
||||
timedelta(days=30))
|
||||
(pull_today, pull_thirty_day) = model.log.get_repository_pulls(repo, timedelta(days=1),
|
||||
timedelta(days=30))
|
||||
|
||||
(push_today, push_thirty_day) = model.get_repository_pushes(repo, timedelta(days=1),
|
||||
timedelta(days=30))
|
||||
(push_today, push_thirty_day) = model.log.get_repository_pushes(repo, timedelta(days=1),
|
||||
timedelta(days=30))
|
||||
|
||||
return {
|
||||
'namespace': namespace,
|
||||
|
@ -261,7 +260,7 @@ class Repository(RepositoryParamResource):
|
|||
@validate_json_request('RepoUpdate')
|
||||
def put(self, namespace, repository):
|
||||
""" Update the description in the specified repository. """
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if repo:
|
||||
values = request.get_json()
|
||||
repo.description = values['description']
|
||||
|
@ -279,7 +278,7 @@ class Repository(RepositoryParamResource):
|
|||
@nickname('deleteRepository')
|
||||
def delete(self, namespace, repository):
|
||||
""" Delete a repository. """
|
||||
model.purge_repository(namespace, repository)
|
||||
model.repository.purge_repository(namespace, repository)
|
||||
log_action('delete_repo', namespace,
|
||||
{'repo': repository, 'namespace': namespace})
|
||||
return 'Deleted', 204
|
||||
|
@ -315,10 +314,10 @@ class RepositoryVisibility(RepositoryParamResource):
|
|||
@validate_json_request('ChangeVisibility')
|
||||
def post(self, namespace, repository):
|
||||
""" Change the visibility of a repository. """
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if repo:
|
||||
values = request.get_json()
|
||||
model.set_repository_visibility(repo, values['visibility'])
|
||||
model.repository.set_repository_visibility(repo, values['visibility'])
|
||||
log_action('change_repo_visibility', namespace,
|
||||
{'repo': repository, 'visibility': values['visibility']},
|
||||
repo=repo)
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
import json
|
||||
|
||||
from flask import request, abort
|
||||
from flask import request
|
||||
|
||||
from app import notification_queue
|
||||
from endpoints.api import (RepositoryParamResource, nickname, resource, require_repo_admin,
|
||||
log_action, validate_json_request, api, NotFound, request_error,
|
||||
log_action, validate_json_request, NotFound, request_error,
|
||||
path_param)
|
||||
from endpoints.notificationevent import NotificationEvent
|
||||
from endpoints.notificationmethod import (NotificationMethod,
|
||||
|
@ -15,17 +15,17 @@ from endpoints.notificationhelper import build_notification_data
|
|||
from data import model
|
||||
|
||||
|
||||
def notification_view(notification):
|
||||
def notification_view(note):
|
||||
config = {}
|
||||
try:
|
||||
config = json.loads(notification.config_json)
|
||||
config = json.loads(note.config_json)
|
||||
except:
|
||||
config = {}
|
||||
|
||||
return {
|
||||
'uuid': notification.uuid,
|
||||
'event': notification.event.name,
|
||||
'method': notification.method.name,
|
||||
'uuid': note.uuid,
|
||||
'event': note.event.name,
|
||||
'method': note.method.name,
|
||||
'config': config
|
||||
}
|
||||
|
||||
|
@ -66,25 +66,25 @@ class RepositoryNotificationList(RepositoryParamResource):
|
|||
@validate_json_request('NotificationCreateRequest')
|
||||
def post(self, namespace, repository):
|
||||
""" Create a new notification for the specified repository. """
|
||||
repo = model.get_repository(namespace, repository)
|
||||
json = request.get_json()
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
parsed = request.get_json()
|
||||
|
||||
method_handler = NotificationMethod.get_method(json['method'])
|
||||
method_handler = NotificationMethod.get_method(parsed['method'])
|
||||
if not method_handler:
|
||||
raise request_error(message='Unknown method')
|
||||
|
||||
try:
|
||||
method_handler.validate(repo, json['config'])
|
||||
method_handler.validate(repo, parsed['config'])
|
||||
except CannotValidateNotificationMethodException as ex:
|
||||
raise request_error(message=ex.message)
|
||||
|
||||
notification = model.create_repo_notification(repo, json['event'], json['method'],
|
||||
json['config'])
|
||||
new_notification = model.notification.create_repo_notification(repo, parsed['event'],
|
||||
parsed['method'], parsed['config'])
|
||||
|
||||
resp = notification_view(notification)
|
||||
resp = notification_view(new_notification)
|
||||
log_action('add_repo_notification', namespace,
|
||||
{'repo': repository, 'notification_id': notification.uuid,
|
||||
'event': json['event'], 'method': json['method']},
|
||||
{'repo': repository, 'notification_id': new_notification.uuid,
|
||||
'event': parsed['event'], 'method': parsed['method']},
|
||||
repo=repo)
|
||||
return resp, 201
|
||||
|
||||
|
@ -92,7 +92,7 @@ class RepositoryNotificationList(RepositoryParamResource):
|
|||
@nickname('listRepoNotifications')
|
||||
def get(self, namespace, repository):
|
||||
""" List the notifications for the specified repository. """
|
||||
notifications = model.list_repo_notifications(namespace, repository)
|
||||
notifications = model.notification.list_repo_notifications(namespace, repository)
|
||||
return {
|
||||
'notifications': [notification_view(n) for n in notifications]
|
||||
}
|
||||
|
@ -108,25 +108,25 @@ class RepositoryNotification(RepositoryParamResource):
|
|||
def get(self, namespace, repository, uuid):
|
||||
""" Get information for the specified notification. """
|
||||
try:
|
||||
notification = model.get_repo_notification(uuid)
|
||||
found = model.notification.get_repo_notification(uuid)
|
||||
except model.InvalidNotificationException:
|
||||
raise NotFound()
|
||||
|
||||
if (notification.repository.namespace_user.username != namespace or
|
||||
notification.repository.name != repository):
|
||||
if (found.repository.namespace_user.username != namespace or
|
||||
found.repository.name != repository):
|
||||
raise NotFound()
|
||||
|
||||
return notification_view(notification)
|
||||
return notification_view(found)
|
||||
|
||||
@require_repo_admin
|
||||
@nickname('deleteRepoNotification')
|
||||
def delete(self, namespace, repository, uuid):
|
||||
""" Deletes the specified notification. """
|
||||
notification = model.delete_repo_notification(namespace, repository, uuid)
|
||||
deleted = model.notification.delete_repo_notification(namespace, repository, uuid)
|
||||
log_action('delete_repo_notification', namespace,
|
||||
{'repo': repository, 'notification_id': uuid,
|
||||
'event': notification.event.name, 'method': notification.method.name},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
'event': deleted.event.name, 'method': deleted.method.name},
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return 'No Content', 204
|
||||
|
||||
|
@ -141,18 +141,18 @@ class TestRepositoryNotification(RepositoryParamResource):
|
|||
def post(self, namespace, repository, uuid):
|
||||
""" Queues a test notification for this repository. """
|
||||
try:
|
||||
notification = model.get_repo_notification(uuid)
|
||||
test_note = model.notification.get_repo_notification(uuid)
|
||||
except model.InvalidNotificationException:
|
||||
raise NotFound()
|
||||
|
||||
if (notification.repository.namespace_user.username != namespace or
|
||||
notification.repository.name != repository):
|
||||
if (test_note.repository.namespace_user.username != namespace or
|
||||
test_note.repository.name != repository):
|
||||
raise NotFound()
|
||||
|
||||
event_info = NotificationEvent.get_event(notification.event.name)
|
||||
sample_data = event_info.get_sample_data(repository=notification.repository)
|
||||
notification_data = build_notification_data(notification, sample_data)
|
||||
notification_queue.put([notification.repository.namespace_user.username, repository,
|
||||
notification.event.name], json.dumps(notification_data))
|
||||
event_info = NotificationEvent.get_event(test_note.event.name)
|
||||
sample_data = event_info.get_sample_data(repository=test_note.repository)
|
||||
notification_data = build_notification_data(test_note, sample_data)
|
||||
notification_queue.put([test_note.repository.namespace_user.username, repository,
|
||||
test_note.event.name], json.dumps(notification_data))
|
||||
|
||||
return {}
|
||||
|
|
|
@ -45,7 +45,7 @@ class RepositoryTokenList(RepositoryParamResource):
|
|||
@nickname('listRepoTokens')
|
||||
def get(self, namespace, repository):
|
||||
""" List the tokens for the specified repository. """
|
||||
tokens = model.get_repository_delegate_tokens(namespace, repository)
|
||||
tokens = model.token.get_repository_delegate_tokens(namespace, repository)
|
||||
|
||||
return {
|
||||
'tokens': {token.code: token_view(token) for token in tokens}
|
||||
|
@ -58,12 +58,11 @@ class RepositoryTokenList(RepositoryParamResource):
|
|||
""" Create a new repository token. """
|
||||
token_params = request.get_json()
|
||||
|
||||
token = model.create_delegate_token(namespace, repository,
|
||||
token_params['friendlyName'])
|
||||
token = model.token.create_delegate_token(namespace, repository, token_params['friendlyName'])
|
||||
|
||||
log_action('add_repo_accesstoken', namespace,
|
||||
{'repo': repository, 'token': token_params['friendlyName']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return token_view(token), 201
|
||||
|
||||
|
@ -99,7 +98,7 @@ class RepositoryToken(RepositoryParamResource):
|
|||
def get(self, namespace, repository, code):
|
||||
""" Fetch the specified repository token information. """
|
||||
try:
|
||||
perm = model.get_repo_delegate_token(namespace, repository, code)
|
||||
perm = model.token.get_repo_delegate_token(namespace, repository, code)
|
||||
except model.InvalidTokenException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -115,13 +114,13 @@ class RepositoryToken(RepositoryParamResource):
|
|||
logger.debug('Setting permission to: %s for code %s' %
|
||||
(new_permission['role'], code))
|
||||
|
||||
token = model.set_repo_delegate_token_role(namespace, repository, code,
|
||||
new_permission['role'])
|
||||
token = model.token.set_repo_delegate_token_role(namespace, repository, code,
|
||||
new_permission['role'])
|
||||
|
||||
log_action('change_repo_permission', namespace,
|
||||
{'repo': repository, 'token': token.friendly_name, 'code': code,
|
||||
'role': new_permission['role']},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return token_view(token)
|
||||
|
||||
|
@ -129,11 +128,11 @@ class RepositoryToken(RepositoryParamResource):
|
|||
@nickname('deleteToken')
|
||||
def delete(self, namespace, repository, code):
|
||||
""" Delete the repository token. """
|
||||
token = model.delete_delegate_token(namespace, repository, code)
|
||||
token = model.token.delete_delegate_token(namespace, repository, code)
|
||||
|
||||
log_action('delete_repo_accesstoken', namespace,
|
||||
{'repo': repository, 'token': token.friendly_name,
|
||||
'code': code},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return 'Deleted', 204
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
""" Manage user and organization robot accounts. """
|
||||
|
||||
from endpoints.api import (resource, nickname, ApiResource, log_action, related_user_resource,
|
||||
Unauthorized, require_user_admin, internal_only, require_scope,
|
||||
path_param, parse_args, truthy_bool, query_param)
|
||||
Unauthorized, require_user_admin, require_scope, path_param, parse_args,
|
||||
truthy_bool, query_param)
|
||||
from auth.permissions import AdministerOrganizationPermission, OrganizationMemberPermission
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
|
@ -30,7 +30,8 @@ def permission_view(permission):
|
|||
|
||||
|
||||
def robots_list(prefix, include_permissions=False):
|
||||
tuples = model.list_entity_robot_permission_teams(prefix, include_permissions=include_permissions)
|
||||
tuples = model.user.list_entity_robot_permission_teams(prefix,
|
||||
include_permissions=include_permissions)
|
||||
|
||||
robots = {}
|
||||
robot_teams = set()
|
||||
|
@ -85,7 +86,8 @@ class UserRobotList(ApiResource):
|
|||
|
||||
|
||||
@resource('/v1/user/robots/<robot_shortname>')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@path_param('robot_shortname',
|
||||
'The short name for the robot, without any user or organization prefix')
|
||||
class UserRobot(ApiResource):
|
||||
""" Resource for managing a user's robots. """
|
||||
@require_user_admin
|
||||
|
@ -93,7 +95,7 @@ class UserRobot(ApiResource):
|
|||
def get(self, robot_shortname):
|
||||
""" Returns the user's robot with the specified name. """
|
||||
parent = get_authenticated_user()
|
||||
robot, password = model.get_robot(robot_shortname, parent)
|
||||
robot, password = model.user.get_robot(robot_shortname, parent)
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
@require_user_admin
|
||||
|
@ -101,7 +103,7 @@ class UserRobot(ApiResource):
|
|||
def put(self, robot_shortname):
|
||||
""" Create a new user robot with the specified name. """
|
||||
parent = get_authenticated_user()
|
||||
robot, password = model.create_robot(robot_shortname, parent)
|
||||
robot, password = model.user.create_robot(robot_shortname, parent)
|
||||
log_action('create_robot', parent.username, {'robot': robot_shortname})
|
||||
return robot_view(robot.username, password), 201
|
||||
|
||||
|
@ -110,7 +112,7 @@ class UserRobot(ApiResource):
|
|||
def delete(self, robot_shortname):
|
||||
""" Delete an existing robot. """
|
||||
parent = get_authenticated_user()
|
||||
model.delete_robot(format_robot_username(parent.username, robot_shortname))
|
||||
model.user.delete_robot(format_robot_username(parent.username, robot_shortname))
|
||||
log_action('delete_robot', parent.username, {'robot': robot_shortname})
|
||||
return 'Deleted', 204
|
||||
|
||||
|
@ -137,7 +139,8 @@ class OrgRobotList(ApiResource):
|
|||
|
||||
@resource('/v1/organization/<orgname>/robots/<robot_shortname>')
|
||||
@path_param('orgname', 'The name of the organization')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@path_param('robot_shortname',
|
||||
'The short name for the robot, without any user or organization prefix')
|
||||
@related_user_resource(UserRobot)
|
||||
class OrgRobot(ApiResource):
|
||||
""" Resource for managing an organization's robots. """
|
||||
|
@ -147,8 +150,8 @@ class OrgRobot(ApiResource):
|
|||
""" Returns the organization's robot with the specified name. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
parent = model.get_organization(orgname)
|
||||
robot, password = model.get_robot(robot_shortname, parent)
|
||||
parent = model.organization.get_organization(orgname)
|
||||
robot, password = model.user.get_robot(robot_shortname, parent)
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -159,9 +162,9 @@ class OrgRobot(ApiResource):
|
|||
""" Create a new robot in the organization. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
parent = model.get_organization(orgname)
|
||||
robot, password = model.create_robot(robot_shortname, parent)
|
||||
log_action('create_robot', orgname, {'robot': robot_shortname})
|
||||
parent = model.organization.get_organization(orgname)
|
||||
robot, password = model.user.create_robot(robot_shortname, parent)
|
||||
log_action('create_robot', orgname, {'robot': robot_shortname})
|
||||
return robot_view(robot.username, password), 201
|
||||
|
||||
raise Unauthorized()
|
||||
|
@ -172,7 +175,7 @@ class OrgRobot(ApiResource):
|
|||
""" Delete an existing organization robot. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
model.delete_robot(format_robot_username(orgname, robot_shortname))
|
||||
model.user.delete_robot(format_robot_username(orgname, robot_shortname))
|
||||
log_action('delete_robot', orgname, {'robot': robot_shortname})
|
||||
return 'Deleted', 204
|
||||
|
||||
|
@ -180,7 +183,8 @@ class OrgRobot(ApiResource):
|
|||
|
||||
|
||||
@resource('/v1/user/robots/<robot_shortname>/permissions')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@path_param('robot_shortname',
|
||||
'The short name for the robot, without any user or organization prefix')
|
||||
class UserRobotPermissions(ApiResource):
|
||||
""" Resource for listing the permissions a user's robot has in the system. """
|
||||
@require_user_admin
|
||||
|
@ -188,8 +192,8 @@ class UserRobotPermissions(ApiResource):
|
|||
def get(self, robot_shortname):
|
||||
""" Returns the list of repository permissions for the user's robot. """
|
||||
parent = get_authenticated_user()
|
||||
robot, password = model.get_robot(robot_shortname, parent)
|
||||
permissions = model.list_robot_permissions(robot.username)
|
||||
robot, _ = model.user.get_robot(robot_shortname, parent)
|
||||
permissions = model.permission.list_robot_permissions(robot.username)
|
||||
|
||||
return {
|
||||
'permissions': [permission_view(permission) for permission in permissions]
|
||||
|
@ -198,7 +202,8 @@ class UserRobotPermissions(ApiResource):
|
|||
|
||||
@resource('/v1/organization/<orgname>/robots/<robot_shortname>/permissions')
|
||||
@path_param('orgname', 'The name of the organization')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@path_param('robot_shortname',
|
||||
'The short name for the robot, without any user or organization prefix')
|
||||
@related_user_resource(UserRobotPermissions)
|
||||
class OrgRobotPermissions(ApiResource):
|
||||
""" Resource for listing the permissions an org's robot has in the system. """
|
||||
|
@ -208,9 +213,9 @@ class OrgRobotPermissions(ApiResource):
|
|||
""" Returns the list of repository permissions for the org's robot. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
parent = model.get_organization(orgname)
|
||||
robot, password = model.get_robot(robot_shortname, parent)
|
||||
permissions = model.list_robot_permissions(robot.username)
|
||||
parent = model.organization.get_organization(orgname)
|
||||
robot, _ = model.user.get_robot(robot_shortname, parent)
|
||||
permissions = model.permission.list_robot_permissions(robot.username)
|
||||
|
||||
return {
|
||||
'permissions': [permission_view(permission) for permission in permissions]
|
||||
|
@ -220,7 +225,8 @@ class OrgRobotPermissions(ApiResource):
|
|||
|
||||
|
||||
@resource('/v1/user/robots/<robot_shortname>/regenerate')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@path_param('robot_shortname',
|
||||
'The short name for the robot, without any user or organization prefix')
|
||||
class RegenerateUserRobot(ApiResource):
|
||||
""" Resource for regenerate an organization's robot's token. """
|
||||
@require_user_admin
|
||||
|
@ -228,14 +234,15 @@ class RegenerateUserRobot(ApiResource):
|
|||
def post(self, robot_shortname):
|
||||
""" Regenerates the token for a user's robot. """
|
||||
parent = get_authenticated_user()
|
||||
robot, password = model.regenerate_robot_token(robot_shortname, parent)
|
||||
log_action('regenerate_robot_token', parent.username, {'robot': robot_shortname})
|
||||
robot, password = model.user.regenerate_robot_token(robot_shortname, parent)
|
||||
log_action('regenerate_robot_token', parent.username, {'robot': robot_shortname})
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
|
||||
@resource('/v1/organization/<orgname>/robots/<robot_shortname>/regenerate')
|
||||
@path_param('orgname', 'The name of the organization')
|
||||
@path_param('robot_shortname', 'The short name for the robot, without any user or organization prefix')
|
||||
@path_param('robot_shortname',
|
||||
'The short name for the robot, without any user or organization prefix')
|
||||
@related_user_resource(RegenerateUserRobot)
|
||||
class RegenerateOrgRobot(ApiResource):
|
||||
""" Resource for regenerate an organization's robot's token. """
|
||||
|
@ -245,9 +252,9 @@ class RegenerateOrgRobot(ApiResource):
|
|||
""" Regenerates the token for an organization robot. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
parent = model.get_organization(orgname)
|
||||
robot, password = model.regenerate_robot_token(robot_shortname, parent)
|
||||
log_action('regenerate_robot_token', orgname, {'robot': robot_shortname})
|
||||
parent = model.organization.get_organization(orgname)
|
||||
robot, password = model.user.regenerate_robot_token(robot_shortname, parent)
|
||||
log_action('regenerate_robot_token', orgname, {'robot': robot_shortname})
|
||||
return robot_view(robot.username, password)
|
||||
|
||||
raise Unauthorized()
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
from endpoints.api import (ApiResource, parse_args, query_param, truthy_bool, nickname, resource,
|
||||
require_scope, path_param)
|
||||
from data import model
|
||||
from auth.permissions import (OrganizationMemberPermission, ViewTeamPermission,
|
||||
ReadRepositoryPermission, UserAdminPermission,
|
||||
AdministerOrganizationPermission, ReadRepositoryPermission)
|
||||
from auth.permissions import (OrganizationMemberPermission, ReadRepositoryPermission,
|
||||
UserAdminPermission, AdministerOrganizationPermission,
|
||||
ReadRepositoryPermission)
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from app import avatar, get_app_url
|
||||
from app import avatar
|
||||
from operator import itemgetter
|
||||
from stringscore import liquidmetal
|
||||
from util.names import parse_robot_username
|
||||
|
@ -35,7 +35,7 @@ class EntitySearch(ApiResource):
|
|||
organization = None
|
||||
|
||||
try:
|
||||
organization = model.get_organization(namespace_name)
|
||||
organization = model.organization.get_organization(namespace_name)
|
||||
|
||||
# namespace name was an org
|
||||
permission = OrganizationMemberPermission(namespace_name)
|
||||
|
@ -43,7 +43,7 @@ class EntitySearch(ApiResource):
|
|||
robot_namespace = namespace_name
|
||||
|
||||
if args['includeTeams']:
|
||||
teams = model.get_matching_teams(prefix, organization)
|
||||
teams = model.team.get_matching_teams(prefix, organization)
|
||||
|
||||
if args['includeOrgs'] and AdministerOrganizationPermission(namespace_name) \
|
||||
and namespace_name.startswith(prefix):
|
||||
|
@ -54,7 +54,7 @@ class EntitySearch(ApiResource):
|
|||
'avatar': avatar.get_data_for_org(organization),
|
||||
}]
|
||||
|
||||
except model.InvalidOrganizationException:
|
||||
except model.organization.InvalidOrganizationException:
|
||||
# namespace name was a user
|
||||
user = get_authenticated_user()
|
||||
if user and user.username == namespace_name:
|
||||
|
@ -63,7 +63,7 @@ class EntitySearch(ApiResource):
|
|||
if admin_permission.can():
|
||||
robot_namespace = namespace_name
|
||||
|
||||
users = model.get_matching_users(prefix, robot_namespace, organization)
|
||||
users = model.user.get_matching_users(prefix, robot_namespace, organization)
|
||||
|
||||
def entity_team_view(team):
|
||||
result = {
|
||||
|
@ -95,18 +95,6 @@ class EntitySearch(ApiResource):
|
|||
}
|
||||
|
||||
|
||||
def team_view(orgname, team):
|
||||
view_permission = ViewTeamPermission(orgname, team.name)
|
||||
role = model.get_team_org_role(team).name
|
||||
return {
|
||||
'id': team.id,
|
||||
'name': team.name,
|
||||
'description': team.description,
|
||||
'can_view': view_permission.can(),
|
||||
'role': role
|
||||
}
|
||||
|
||||
|
||||
@resource('/v1/find/repository')
|
||||
class FindRepositories(ApiResource):
|
||||
""" Resource for finding repositories. """
|
||||
|
@ -130,7 +118,7 @@ class FindRepositories(ApiResource):
|
|||
if user is not None:
|
||||
username = user.username
|
||||
|
||||
matching = model.get_matching_repositories(prefix, username)
|
||||
matching = model.repository.get_matching_repositories(prefix, username)
|
||||
return {
|
||||
'repositories': [repo_view(repo) for repo in matching
|
||||
if (repo.visibility.name == 'public' or
|
||||
|
@ -174,7 +162,7 @@ def search_entity_view(username, entity, get_short_name=None):
|
|||
|
||||
def conduct_team_search(username, query, encountered_teams, results):
|
||||
""" Finds the matching teams where the user is a member. """
|
||||
matching_teams = model.get_matching_user_teams(query, get_authenticated_user(), limit=5)
|
||||
matching_teams = model.team.get_matching_user_teams(query, get_authenticated_user(), limit=5)
|
||||
for team in matching_teams:
|
||||
if team.id in encountered_teams:
|
||||
continue
|
||||
|
@ -193,7 +181,7 @@ def conduct_team_search(username, query, encountered_teams, results):
|
|||
|
||||
def conduct_admined_team_search(username, query, encountered_teams, results):
|
||||
""" Finds matching teams in orgs admined by the user. """
|
||||
matching_teams = model.get_matching_admined_teams(query, get_authenticated_user(), limit=5)
|
||||
matching_teams = model.team.get_matching_admined_teams(query, get_authenticated_user(), limit=5)
|
||||
for team in matching_teams:
|
||||
if team.id in encountered_teams:
|
||||
continue
|
||||
|
@ -212,14 +200,15 @@ def conduct_admined_team_search(username, query, encountered_teams, results):
|
|||
|
||||
def conduct_repo_search(username, query, results):
|
||||
""" Finds matching repositories. """
|
||||
def can_read(repository):
|
||||
if repository.is_public:
|
||||
def can_read(repo):
|
||||
if repo.is_public:
|
||||
return True
|
||||
|
||||
return ReadRepositoryPermission(repository.namespace_user.username, repository.name).can()
|
||||
return ReadRepositoryPermission(repo.namespace_user.username, repo.name).can()
|
||||
|
||||
only_public = username is None
|
||||
matching_repos = model.get_sorted_matching_repositories(query, only_public, can_read, limit=5)
|
||||
matching_repos = model.repository.get_sorted_matching_repositories(query, only_public, can_read,
|
||||
limit=5)
|
||||
|
||||
for repo in matching_repos:
|
||||
repo_score = math.log(repo.count or 1, 10) or 1
|
||||
|
@ -242,7 +231,7 @@ def conduct_repo_search(username, query, results):
|
|||
|
||||
def conduct_namespace_search(username, query, results):
|
||||
""" Finds matching users and organizations. """
|
||||
matching_entities = model.get_matching_user_namespaces(query, username, limit=5)
|
||||
matching_entities = model.user.get_matching_user_namespaces(query, username, limit=5)
|
||||
for entity in matching_entities:
|
||||
results.append(search_entity_view(username, entity))
|
||||
|
||||
|
@ -252,7 +241,7 @@ def conduct_robot_search(username, query, results):
|
|||
def get_short_name(name):
|
||||
return parse_robot_username(name)[1]
|
||||
|
||||
matching_robots = model.get_matching_robots(query, username, limit=5)
|
||||
matching_robots = model.user.get_matching_robots(query, username, limit=5)
|
||||
for robot in matching_robots:
|
||||
results.append(search_entity_view(username, robot, get_short_name))
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ from data.billing import PLANS
|
|||
|
||||
import features
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -50,12 +51,12 @@ def subscribe(user, plan, token, require_business_plan):
|
|||
raise NotFound()
|
||||
|
||||
if (require_business_plan and not plan_found['bus_features'] and not
|
||||
plan_found['price'] == 0):
|
||||
plan_found['price'] == 0):
|
||||
logger.warning('Business attempting to subscribe to personal plan: %s',
|
||||
user.username)
|
||||
raise request_error(message='No matching plan found')
|
||||
|
||||
private_repos = model.get_private_repo_count(user.username)
|
||||
private_repos = model.user.get_private_repo_count(user.username)
|
||||
|
||||
# This is the default response
|
||||
response_json = {
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import signal
|
||||
|
||||
from flask import abort, Response
|
||||
from flask import abort
|
||||
from endpoints.api import (ApiResource, nickname, resource, internal_only, show_if,
|
||||
require_fresh_login, request, validate_json_request, verify_not_prod)
|
||||
|
||||
|
@ -14,17 +13,17 @@ from app import app, CONFIG_PROVIDER, superusers
|
|||
from data import model
|
||||
from data.database import configure
|
||||
from auth.permissions import SuperUserPermission
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from data.database import User
|
||||
from util.config.configutil import add_enterprise_config_defaults
|
||||
from util.config.provider import CannotWriteConfigException
|
||||
from util.config.validator import validate_service_for_config, CONFIG_FILENAMES
|
||||
from data.runmigration import run_alembic_migration
|
||||
|
||||
import features
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def database_is_valid():
|
||||
""" Returns whether the database, as configured, is valid. """
|
||||
if app.config['TESTING']:
|
||||
|
@ -310,7 +309,7 @@ class SuperUserCreateInitialSuperUser(ApiResource):
|
|||
email = data['email']
|
||||
|
||||
# Create the user in the database.
|
||||
superuser = model.create_user(username, password, email, auto_verify=True)
|
||||
superuser = model.user.create_user(username, password, email, auto_verify=True)
|
||||
|
||||
# Add the user to the config.
|
||||
config_object = CONFIG_PROVIDER.get_yaml()
|
||||
|
|
|
@ -2,33 +2,31 @@
|
|||
|
||||
import string
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
|
||||
from random import SystemRandom
|
||||
from app import app, avatar, superusers, authentication
|
||||
from flask import request
|
||||
|
||||
from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error,
|
||||
log_action, internal_only, NotFound, require_user_admin, format_date,
|
||||
InvalidToken, require_scope, format_date, hide_if, show_if, parse_args,
|
||||
query_param, abort, require_fresh_login, path_param, verify_not_prod)
|
||||
|
||||
from endpoints.api.logs import get_logs
|
||||
|
||||
from data import model
|
||||
from auth.permissions import SuperUserPermission
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from util.useremails import send_confirmation_email, send_recovery_email
|
||||
|
||||
import features
|
||||
|
||||
from app import app, avatar, superusers, authentication
|
||||
from endpoints.api import (ApiResource, nickname, resource, validate_json_request,
|
||||
internal_only, require_scope, show_if, parse_args,
|
||||
query_param, abort, require_fresh_login, path_param, verify_not_prod)
|
||||
from endpoints.api.logs import get_logs
|
||||
from data import model
|
||||
from auth.permissions import SuperUserPermission
|
||||
from auth import scopes
|
||||
from util.useremails import send_confirmation_email, send_recovery_email
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_immediate_subdirectories(directory):
|
||||
return [name for name in os.listdir(directory) if os.path.isdir(os.path.join(directory, name))]
|
||||
|
||||
|
||||
def get_services():
|
||||
services = set(get_immediate_subdirectories(app.config['SYSTEM_SERVICES_PATH']))
|
||||
services = services - set(app.config['SYSTEM_SERVICE_BLACKLIST'])
|
||||
|
@ -55,7 +53,7 @@ class SuperUserGetLogsForService(ApiResource):
|
|||
with open(app.config['SYSTEM_LOGS_FILE'], 'r') as f:
|
||||
logs = [line for line in f if line.find(service + '[') >= 0]
|
||||
|
||||
except Exception as ex:
|
||||
except Exception:
|
||||
logger.exception('Cannot read logs')
|
||||
abort(400)
|
||||
|
||||
|
@ -102,7 +100,6 @@ class SuperUserLogs(ApiResource):
|
|||
def get(self, args):
|
||||
""" List the usage logs for the current system. """
|
||||
if SuperUserPermission().can():
|
||||
performer_name = args['performer']
|
||||
start_time = args['starttime']
|
||||
end_time = args['endtime']
|
||||
|
||||
|
@ -144,7 +141,7 @@ class ChangeLog(ApiResource):
|
|||
def get(self):
|
||||
""" Returns the change log for this installation. """
|
||||
if SuperUserPermission().can():
|
||||
with open ('CHANGELOG.md', 'r') as f:
|
||||
with open('CHANGELOG.md', 'r') as f:
|
||||
return {
|
||||
'log': f.read()
|
||||
}
|
||||
|
@ -165,7 +162,7 @@ class SuperUserOrganizationList(ApiResource):
|
|||
def get(self):
|
||||
""" Returns a list of all organizations in the system. """
|
||||
if SuperUserPermission().can():
|
||||
orgs = model.get_organizations()
|
||||
orgs = model.organization.get_organizations()
|
||||
return {
|
||||
'organizations': [org_view(org) for org in orgs]
|
||||
}
|
||||
|
@ -204,7 +201,7 @@ class SuperUserList(ApiResource):
|
|||
def get(self):
|
||||
""" Returns a list of all users in the system. """
|
||||
if SuperUserPermission().can():
|
||||
users = model.get_active_users()
|
||||
users = model.user.get_active_users()
|
||||
return {
|
||||
'users': [user_view(user) for user in users]
|
||||
}
|
||||
|
@ -226,14 +223,14 @@ class SuperUserList(ApiResource):
|
|||
|
||||
# Generate a temporary password for the user.
|
||||
random = SystemRandom()
|
||||
password = ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(32)])
|
||||
password = ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(32)])
|
||||
|
||||
# Create the user.
|
||||
user = model.create_user(username, password, email, auto_verify=not features.MAILING)
|
||||
user = model.user.create_user(username, password, email, auto_verify=not features.MAILING)
|
||||
|
||||
# If mailing is turned on, send the user a verification email.
|
||||
if features.MAILING:
|
||||
confirmation = model.create_confirm_email_code(user)
|
||||
confirmation = model.user.create_confirm_email_code(user)
|
||||
send_confirmation_email(user.username, user.email, confirmation.code)
|
||||
|
||||
return {
|
||||
|
@ -258,14 +255,14 @@ class SuperUserSendRecoveryEmail(ApiResource):
|
|||
@require_scope(scopes.SUPERUSER)
|
||||
def post(self, username):
|
||||
if SuperUserPermission().can():
|
||||
user = model.get_nonrobot_user(username)
|
||||
user = model.user.get_nonrobot_user(username)
|
||||
if not user:
|
||||
abort(404)
|
||||
|
||||
if superusers.is_superuser(username):
|
||||
abort(403)
|
||||
abort(403)
|
||||
|
||||
code = model.create_reset_password_email_code(user.email)
|
||||
code = model.user.create_reset_password_email_code(user.email)
|
||||
send_recovery_email(user.email, code.code)
|
||||
return {
|
||||
'email': user.email
|
||||
|
@ -309,7 +306,7 @@ class SuperUserManagement(ApiResource):
|
|||
def get(self, username):
|
||||
""" Returns information about the specified user. """
|
||||
if SuperUserPermission().can():
|
||||
user = model.get_nonrobot_user(username)
|
||||
user = model.user.get_nonrobot_user(username)
|
||||
if not user:
|
||||
abort(404)
|
||||
|
||||
|
@ -324,14 +321,14 @@ class SuperUserManagement(ApiResource):
|
|||
def delete(self, username):
|
||||
""" Deletes the specified user. """
|
||||
if SuperUserPermission().can():
|
||||
user = model.get_nonrobot_user(username)
|
||||
user = model.user.get_nonrobot_user(username)
|
||||
if not user:
|
||||
abort(404)
|
||||
|
||||
if superusers.is_superuser(username):
|
||||
abort(403)
|
||||
abort(403)
|
||||
|
||||
model.delete_user(user)
|
||||
model.user.delete_user(user)
|
||||
return 'Deleted', 204
|
||||
|
||||
abort(403)
|
||||
|
@ -344,26 +341,26 @@ class SuperUserManagement(ApiResource):
|
|||
def put(self, username):
|
||||
""" Updates information about the specified user. """
|
||||
if SuperUserPermission().can():
|
||||
user = model.get_nonrobot_user(username)
|
||||
if not user:
|
||||
abort(404)
|
||||
user = model.user.get_nonrobot_user(username)
|
||||
if not user:
|
||||
abort(404)
|
||||
|
||||
if superusers.is_superuser(username):
|
||||
abort(403)
|
||||
if superusers.is_superuser(username):
|
||||
abort(403)
|
||||
|
||||
user_data = request.get_json()
|
||||
if 'password' in user_data:
|
||||
model.change_password(user, user_data['password'])
|
||||
user_data = request.get_json()
|
||||
if 'password' in user_data:
|
||||
model.user.change_password(user, user_data['password'])
|
||||
|
||||
if 'email' in user_data:
|
||||
model.update_email(user, user_data['email'], auto_verify=True)
|
||||
if 'email' in user_data:
|
||||
model.user.update_email(user, user_data['email'], auto_verify=True)
|
||||
|
||||
if 'enabled' in user_data:
|
||||
# Disable/enable the user.
|
||||
user.enabled = bool(user_data['enabled'])
|
||||
user.save()
|
||||
if 'enabled' in user_data:
|
||||
# Disable/enable the user.
|
||||
user.enabled = bool(user_data['enabled'])
|
||||
user.save()
|
||||
|
||||
return user_view(user, password=user_data.get('password'))
|
||||
return user_view(user, password=user_data.get('password'))
|
||||
|
||||
abort(403)
|
||||
|
||||
|
@ -395,9 +392,9 @@ class SuperUserOrganizationManagement(ApiResource):
|
|||
def delete(self, name):
|
||||
""" Deletes the specified organization. """
|
||||
if SuperUserPermission().can():
|
||||
org = model.get_organization(name)
|
||||
org = model.organization.get_organization(name)
|
||||
|
||||
model.delete_user(org)
|
||||
model.user.delete_user(org)
|
||||
return 'Deleted', 204
|
||||
|
||||
abort(403)
|
||||
|
@ -410,12 +407,12 @@ class SuperUserOrganizationManagement(ApiResource):
|
|||
def put(self, name):
|
||||
""" Updates information about the specified user. """
|
||||
if SuperUserPermission().can():
|
||||
org = model.get_organization(name)
|
||||
org_data = request.get_json()
|
||||
org = model.organization.get_organization(name)
|
||||
org_data = request.get_json()
|
||||
|
||||
if 'name' in org_data:
|
||||
org = model.change_username(org.id, org_data['name'])
|
||||
if 'name' in org_data:
|
||||
org = model.user.change_username(org.id, org_data['name'])
|
||||
|
||||
return org_view(org)
|
||||
return org_view(org)
|
||||
|
||||
abort(403)
|
||||
|
|
|
@ -4,14 +4,11 @@ from flask import request, abort
|
|||
|
||||
from endpoints.api import (resource, nickname, require_repo_read, require_repo_write,
|
||||
RepositoryParamResource, log_action, NotFound, validate_json_request,
|
||||
path_param, format_date, parse_args, query_param)
|
||||
path_param, parse_args, query_param)
|
||||
from endpoints.api.image import image_view
|
||||
from data import model
|
||||
from auth.auth_context import get_authenticated_user
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
|
||||
@resource('/v1/repository/<repopath:repository>/tag/')
|
||||
@path_param('repository', 'The full path of the repository. e.g. namespace/name')
|
||||
|
@ -25,7 +22,7 @@ class ListRepositoryTags(RepositoryParamResource):
|
|||
@query_param('page', 'Page index for the results. Default 1.', type=int, default=1)
|
||||
@nickname('listRepoTags')
|
||||
def get(self, args, namespace, repository):
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
abort(404)
|
||||
|
||||
|
@ -51,8 +48,8 @@ class ListRepositoryTags(RepositoryParamResource):
|
|||
|
||||
# Note: We ask for limit+1 here, so we can check to see if there are
|
||||
# additional pages of results.
|
||||
tags = model.list_repository_tag_history(repo, page=page, size=limit+1,
|
||||
specific_tag=specific_tag)
|
||||
tags = model.tag.list_repository_tag_history(repo, page=page, size=limit+1,
|
||||
specific_tag=specific_tag)
|
||||
|
||||
tags = list(tags)
|
||||
return {
|
||||
|
@ -90,27 +87,27 @@ class RepositoryTag(RepositoryParamResource):
|
|||
def put(self, namespace, repository, tag):
|
||||
""" Change which image a tag points to or create a new tag."""
|
||||
image_id = request.get_json()['image']
|
||||
image = model.get_repo_image(namespace, repository, image_id)
|
||||
image = model.image.get_repo_image(namespace, repository, image_id)
|
||||
if not image:
|
||||
raise NotFound()
|
||||
|
||||
original_image_id = None
|
||||
try:
|
||||
original_tag_image = model.get_tag_image(namespace, repository, tag)
|
||||
original_tag_image = model.tag.get_tag_image(namespace, repository, tag)
|
||||
if original_tag_image:
|
||||
original_image_id = original_tag_image.docker_image_id
|
||||
except model.DataModelException:
|
||||
# This is a new tag.
|
||||
pass
|
||||
|
||||
model.create_or_update_tag(namespace, repository, tag, image_id)
|
||||
model.garbage_collect_repository(namespace, repository)
|
||||
model.tag.create_or_update_tag(namespace, repository, tag, image_id)
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
username = get_authenticated_user().username
|
||||
log_action('move_tag' if original_image_id else 'create_tag', namespace,
|
||||
{'username': username, 'repo': repository, 'tag': tag,
|
||||
'image': image_id, 'original_image': original_image_id},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return 'Updated', 201
|
||||
|
||||
|
@ -118,13 +115,13 @@ class RepositoryTag(RepositoryParamResource):
|
|||
@nickname('deleteFullTag')
|
||||
def delete(self, namespace, repository, tag):
|
||||
""" Delete the specified repository tag. """
|
||||
model.delete_tag(namespace, repository, tag)
|
||||
model.garbage_collect_repository(namespace, repository)
|
||||
model.tag.delete_tag(namespace, repository, tag)
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
username = get_authenticated_user().username
|
||||
log_action('delete_tag', namespace,
|
||||
{'username': username, 'repo': repository, 'tag': tag},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return 'Deleted', 204
|
||||
|
||||
|
@ -139,11 +136,11 @@ class RepositoryTagImages(RepositoryParamResource):
|
|||
def get(self, namespace, repository, tag):
|
||||
""" List the images for the specified repository tag. """
|
||||
try:
|
||||
tag_image = model.get_tag_image(namespace, repository, tag)
|
||||
tag_image = model.tag.get_tag_image(namespace, repository, tag)
|
||||
except model.DataModelException:
|
||||
raise NotFound()
|
||||
|
||||
parent_images = model.get_parent_images(namespace, repository, tag_image)
|
||||
parent_images = model.image.get_parent_images(namespace, repository, tag_image)
|
||||
image_map = {}
|
||||
for image in parent_images:
|
||||
image_map[str(image.id)] = image
|
||||
|
@ -186,21 +183,21 @@ class RevertTag(RepositoryParamResource):
|
|||
def post(self, namespace, repository, tag):
|
||||
""" Reverts a repository tag back to a previous image in the repository. """
|
||||
try:
|
||||
tag_image = model.get_tag_image(namespace, repository, tag)
|
||||
tag_image = model.tag.get_tag_image(namespace, repository, tag)
|
||||
except model.DataModelException:
|
||||
raise NotFound()
|
||||
|
||||
# Revert the tag back to the previous image.
|
||||
image_id = request.get_json()['image']
|
||||
model.revert_tag(tag_image.repository, tag, image_id)
|
||||
model.garbage_collect_repository(namespace, repository)
|
||||
model.tag.revert_tag(tag_image.repository, tag, image_id)
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
# Log the reversion.
|
||||
username = get_authenticated_user().username
|
||||
log_action('revert_tag', namespace,
|
||||
{'username': username, 'repo': repository, 'tag': tag,
|
||||
'image': image_id, 'original_image': tag_image.docker_image_id},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
return {
|
||||
'image_id': image_id,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
from flask import request
|
||||
|
||||
import features
|
||||
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error,
|
||||
log_action, Unauthorized, NotFound, internal_only, require_scope,
|
||||
path_param, query_param, truthy_bool, parse_args, require_user_admin,
|
||||
|
@ -13,12 +15,11 @@ from data import model
|
|||
from util.useremails import send_org_invite_email
|
||||
from app import avatar
|
||||
|
||||
import features
|
||||
|
||||
def try_accept_invite(code, user):
|
||||
(team, inviter) = model.confirm_team_invite(code, user)
|
||||
(team, inviter) = model.team.confirm_team_invite(code, user)
|
||||
|
||||
model.delete_matching_notifications(user, 'org_team_invite', code=code)
|
||||
model.notification.delete_matching_notifications(user, 'org_team_invite', code=code)
|
||||
|
||||
orgname = team.organization.username
|
||||
log_action('org_team_member_invite_accepted', orgname, {
|
||||
|
@ -31,15 +32,15 @@ def try_accept_invite(code, user):
|
|||
|
||||
|
||||
def handle_addinvite_team(inviter, team, user=None, email=None):
|
||||
invite = model.add_or_invite_to_team(inviter, team, user, email,
|
||||
requires_invite = features.MAILING)
|
||||
invite = model.team.add_or_invite_to_team(inviter, team, user, email,
|
||||
requires_invite=features.MAILING)
|
||||
if not invite:
|
||||
# User was added to the team directly.
|
||||
return
|
||||
|
||||
orgname = team.organization.username
|
||||
if user:
|
||||
model.create_notification('org_team_invite', user, metadata = {
|
||||
model.notification.create_notification('org_team_invite', user, metadata={
|
||||
'code': invite.invite_token,
|
||||
'inviter': inviter.username,
|
||||
'org': orgname,
|
||||
|
@ -52,7 +53,7 @@ def handle_addinvite_team(inviter, team, user=None, email=None):
|
|||
|
||||
def team_view(orgname, team):
|
||||
view_permission = ViewTeamPermission(orgname, team.name)
|
||||
role = model.get_team_org_role(team).name
|
||||
role = model.team.get_team_org_role(team).name
|
||||
return {
|
||||
'name': team.name,
|
||||
'description': team.description,
|
||||
|
@ -126,15 +127,15 @@ class OrganizationTeam(ApiResource):
|
|||
details = request.get_json()
|
||||
is_existing = False
|
||||
try:
|
||||
team = model.get_organization_team(orgname, teamname)
|
||||
team = model.team.get_organization_team(orgname, teamname)
|
||||
is_existing = True
|
||||
except model.InvalidTeamException:
|
||||
# Create the new team.
|
||||
description = details['description'] if 'description' in details else ''
|
||||
role = details['role'] if 'role' in details else 'member'
|
||||
|
||||
org = model.get_organization(orgname)
|
||||
team = model.create_team(teamname, org, role, description)
|
||||
org = model.organization.get_organization(orgname)
|
||||
team = model.team.create_team(teamname, org, role, description)
|
||||
log_action('org_create_team', orgname, {'team': teamname})
|
||||
|
||||
if is_existing:
|
||||
|
@ -146,10 +147,10 @@ class OrganizationTeam(ApiResource):
|
|||
{'team': teamname, 'description': team.description})
|
||||
|
||||
if 'role' in details:
|
||||
role = model.get_team_org_role(team).name
|
||||
role = model.team.get_team_org_role(team).name
|
||||
if role != details['role']:
|
||||
team = model.set_team_org_permission(team, details['role'],
|
||||
get_authenticated_user().username)
|
||||
team = model.team.set_team_org_permission(team, details['role'],
|
||||
get_authenticated_user().username)
|
||||
log_action('org_set_team_role', orgname, {'team': teamname, 'role': details['role']})
|
||||
|
||||
return team_view(orgname, team), 200
|
||||
|
@ -162,7 +163,7 @@ class OrganizationTeam(ApiResource):
|
|||
""" Delete the specified team. """
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can():
|
||||
model.remove_team(orgname, teamname, get_authenticated_user().username)
|
||||
model.team.remove_team(orgname, teamname, get_authenticated_user().username)
|
||||
log_action('org_delete_team', orgname, {'team': teamname})
|
||||
return 'Deleted', 204
|
||||
|
||||
|
@ -176,7 +177,8 @@ class TeamMemberList(ApiResource):
|
|||
""" Resource for managing the list of members for a team. """
|
||||
@require_scope(scopes.ORG_ADMIN)
|
||||
@parse_args
|
||||
@query_param('includePending', 'Whether to include pending members', type=truthy_bool, default=False)
|
||||
@query_param('includePending', 'Whether to include pending members', type=truthy_bool,
|
||||
default=False)
|
||||
@nickname('getOrganizationTeamMembers')
|
||||
def get(self, args, orgname, teamname):
|
||||
""" Retrieve the list of members for the specified team. """
|
||||
|
@ -186,15 +188,15 @@ class TeamMemberList(ApiResource):
|
|||
if view_permission.can():
|
||||
team = None
|
||||
try:
|
||||
team = model.get_organization_team(orgname, teamname)
|
||||
team = model.team.get_organization_team(orgname, teamname)
|
||||
except model.InvalidTeamException:
|
||||
raise NotFound()
|
||||
|
||||
members = model.get_organization_team_members(team.id)
|
||||
members = model.organization.get_organization_team_members(team.id)
|
||||
invites = []
|
||||
|
||||
if args['includePending'] and edit_permission.can():
|
||||
invites = model.get_organization_team_member_invites(team.id)
|
||||
invites = model.team.get_organization_team_member_invites(team.id)
|
||||
|
||||
data = {
|
||||
'members': [member_view(m) for m in members] + [invite_view(i) for i in invites],
|
||||
|
@ -224,12 +226,12 @@ class TeamMember(ApiResource):
|
|||
|
||||
# Find the team.
|
||||
try:
|
||||
team = model.get_organization_team(orgname, teamname)
|
||||
team = model.team.get_organization_team(orgname, teamname)
|
||||
except model.InvalidTeamException:
|
||||
raise NotFound()
|
||||
|
||||
# Find the user.
|
||||
user = model.get_user(membername)
|
||||
user = model.user.get_user(membername)
|
||||
if not user:
|
||||
raise request_error(message='Unknown user')
|
||||
|
||||
|
@ -263,18 +265,18 @@ class TeamMember(ApiResource):
|
|||
|
||||
# Find the team.
|
||||
try:
|
||||
team = model.get_organization_team(orgname, teamname)
|
||||
team = model.team.get_organization_team(orgname, teamname)
|
||||
except model.InvalidTeamException:
|
||||
raise NotFound()
|
||||
|
||||
# Find the member.
|
||||
member = model.get_user(membername)
|
||||
member = model.user.get_user(membername)
|
||||
if not member:
|
||||
raise NotFound()
|
||||
|
||||
# First attempt to delete an invite for the user to this team. If none found,
|
||||
# then we try to remove the user directly.
|
||||
if model.delete_team_user_invite(team, member):
|
||||
if model.team.delete_team_user_invite(team, member):
|
||||
log_action('org_delete_team_member_invite', orgname, {
|
||||
'user': membername,
|
||||
'team': teamname,
|
||||
|
@ -282,7 +284,7 @@ class TeamMember(ApiResource):
|
|||
})
|
||||
return 'Deleted', 204
|
||||
|
||||
model.remove_user_from_team(orgname, teamname, membername, invoking_user)
|
||||
model.team.remove_user_from_team(orgname, teamname, membername, invoking_user)
|
||||
log_action('org_remove_team_member', orgname, {'member': membername, 'team': teamname})
|
||||
return 'Deleted', 204
|
||||
|
||||
|
@ -303,7 +305,7 @@ class InviteTeamMember(ApiResource):
|
|||
|
||||
# Find the team.
|
||||
try:
|
||||
team = model.get_organization_team(orgname, teamname)
|
||||
team = model.team.get_organization_team(orgname, teamname)
|
||||
except model.InvalidTeamException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -329,12 +331,12 @@ class InviteTeamMember(ApiResource):
|
|||
|
||||
# Find the team.
|
||||
try:
|
||||
team = model.get_organization_team(orgname, teamname)
|
||||
team = model.team.get_organization_team(orgname, teamname)
|
||||
except model.InvalidTeamException:
|
||||
raise NotFound()
|
||||
|
||||
# Delete the invite.
|
||||
model.delete_team_email_invite(team, email)
|
||||
model.team.delete_team_email_invite(team, email)
|
||||
log_action('org_delete_team_member_invite', orgname, {
|
||||
'email': email,
|
||||
'team': teamname,
|
||||
|
@ -369,15 +371,16 @@ class TeamMemberInvite(ApiResource):
|
|||
@require_user_admin
|
||||
def delete(self, code):
|
||||
""" Delete an existing member of a team. """
|
||||
(team, inviter) = model.delete_team_invite(code, get_authenticated_user())
|
||||
(team, inviter) = model.team.delete_team_invite(code, user_obj=get_authenticated_user())
|
||||
|
||||
model.delete_matching_notifications(get_authenticated_user(), 'org_team_invite', code=code)
|
||||
model.notification.delete_matching_notifications(get_authenticated_user(), 'org_team_invite',
|
||||
code=code)
|
||||
|
||||
orgname = team.organization.username
|
||||
log_action('org_team_member_invite_declined', orgname, {
|
||||
'member': get_authenticated_user().username,
|
||||
'team': team.name,
|
||||
'inviter': inviter.username
|
||||
'member': get_authenticated_user().username,
|
||||
'team': team.name,
|
||||
'inviter': inviter.username
|
||||
})
|
||||
|
||||
return 'Deleted', 204
|
||||
|
|
|
@ -12,14 +12,14 @@ from endpoints.api import (RepositoryParamResource, nickname, resource, require_
|
|||
log_action, request_error, query_param, parse_args, internal_only,
|
||||
validate_json_request, api, Unauthorized, NotFound, InvalidRequest,
|
||||
path_param)
|
||||
from endpoints.api.build import (build_status_view, trigger_view, RepositoryBuildStatus,
|
||||
get_trigger_config)
|
||||
from endpoints.api.build import build_status_view, trigger_view, RepositoryBuildStatus
|
||||
from endpoints.building import start_build
|
||||
from endpoints.trigger import (BuildTriggerHandler, TriggerDeactivationException,
|
||||
TriggerActivationException, EmptyRepositoryException,
|
||||
RepositoryReadException, TriggerStartException)
|
||||
from data import model
|
||||
from auth.permissions import UserAdminPermission, AdministerOrganizationPermission, ReadRepositoryPermission
|
||||
from auth.permissions import (UserAdminPermission, AdministerOrganizationPermission,
|
||||
ReadRepositoryPermission)
|
||||
from util.names import parse_robot_username
|
||||
from util.dockerfileparse import parse_dockerfile
|
||||
|
||||
|
@ -41,7 +41,7 @@ class BuildTriggerList(RepositoryParamResource):
|
|||
@nickname('listBuildTriggers')
|
||||
def get(self, namespace, repository):
|
||||
""" List the triggers for the specified repository. """
|
||||
triggers = model.list_build_triggers(namespace, repository)
|
||||
triggers = model.build.list_build_triggers(namespace, repository)
|
||||
return {
|
||||
'triggers': [trigger_view(trigger, can_admin=True) for trigger in triggers]
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ class BuildTrigger(RepositoryParamResource):
|
|||
def get(self, namespace, repository, trigger_uuid):
|
||||
""" Get information for the specified build trigger. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -69,7 +69,7 @@ class BuildTrigger(RepositoryParamResource):
|
|||
def delete(self, namespace, repository, trigger_uuid):
|
||||
""" Delete the specified build trigger. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -84,7 +84,7 @@ class BuildTrigger(RepositoryParamResource):
|
|||
log_action('delete_repo_trigger', namespace,
|
||||
{'repo': repository, 'trigger_id': trigger_uuid,
|
||||
'service': trigger.service.name},
|
||||
repo=model.get_repository(namespace, repository))
|
||||
repo=model.repository.get_repository(namespace, repository))
|
||||
|
||||
trigger.delete_instance(recursive=True)
|
||||
|
||||
|
@ -114,7 +114,7 @@ class BuildTriggerSubdirs(RepositoryParamResource):
|
|||
def post(self, namespace, repository, trigger_uuid):
|
||||
""" List the subdirectories available for the specified build trigger and source. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -175,7 +175,7 @@ class BuildTriggerActivate(RepositoryParamResource):
|
|||
def post(self, namespace, repository, trigger_uuid):
|
||||
""" Activate the specified build trigger. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -188,8 +188,9 @@ class BuildTriggerActivate(RepositoryParamResource):
|
|||
# Update the pull robot (if any).
|
||||
pull_robot_name = request.get_json().get('pull_robot', None)
|
||||
if pull_robot_name:
|
||||
pull_robot = model.lookup_robot(pull_robot_name)
|
||||
if not pull_robot:
|
||||
try:
|
||||
pull_robot = model.user.lookup_robot(pull_robot_name)
|
||||
except model.InvalidRobotException:
|
||||
raise NotFound()
|
||||
|
||||
# Make sure the user has administer permissions for the robot's namespace.
|
||||
|
@ -208,8 +209,8 @@ class BuildTriggerActivate(RepositoryParamResource):
|
|||
new_config_dict = request.get_json()['config']
|
||||
|
||||
write_token_name = 'Build Trigger: %s' % trigger.service.name
|
||||
write_token = model.create_delegate_token(namespace, repository, write_token_name,
|
||||
'write')
|
||||
write_token = model.token.create_delegate_token(namespace, repository, write_token_name,
|
||||
'write')
|
||||
|
||||
try:
|
||||
path = url_for('webhooks.build_trigger_webhook', trigger_uuid=trigger.uuid)
|
||||
|
@ -233,7 +234,7 @@ class BuildTriggerActivate(RepositoryParamResource):
|
|||
trigger.save()
|
||||
|
||||
# Log the trigger setup.
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
log_action('setup_repo_trigger', namespace,
|
||||
{'repo': repository, 'namespace': namespace,
|
||||
'trigger_id': trigger.uuid, 'service': trigger.service.name,
|
||||
|
@ -275,7 +276,7 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
|||
def post(self, namespace, repository, trigger_uuid):
|
||||
""" Analyze the specified build trigger configuration. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -324,7 +325,7 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
|||
}
|
||||
|
||||
(base_namespace, base_repository) = result
|
||||
found_repository = model.get_repository(base_namespace, base_repository)
|
||||
found_repository = model.repository.get_repository(base_namespace, base_repository)
|
||||
if not found_repository:
|
||||
return {
|
||||
'status': 'error',
|
||||
|
@ -361,7 +362,7 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
|||
(robot_namespace, shortname) = parse_robot_username(user.username)
|
||||
return AdministerOrganizationPermission(robot_namespace).can()
|
||||
|
||||
repo_users = list(model.get_all_repo_users_transitive(base_namespace, base_repository))
|
||||
repo_users = list(model.user.get_all_repo_users_transitive(base_namespace, base_repository))
|
||||
read_robots = [robot_view(user) for user in repo_users if is_valid_robot(user)]
|
||||
|
||||
return {
|
||||
|
@ -399,7 +400,7 @@ class ActivateBuildTrigger(RepositoryParamResource):
|
|||
'properties': {
|
||||
'branch_name': {
|
||||
'type': 'string',
|
||||
'description': '(SCM only) If specified, the name of the branch to build.'
|
||||
'description': '(SCM only) If specified, the name of the branch to model.build.'
|
||||
},
|
||||
'commit_sha': {
|
||||
'type': 'string',
|
||||
|
@ -415,7 +416,7 @@ class ActivateBuildTrigger(RepositoryParamResource):
|
|||
def post(self, namespace, repository, trigger_uuid):
|
||||
""" Manually start a build from the specified trigger. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -424,8 +425,8 @@ class ActivateBuildTrigger(RepositoryParamResource):
|
|||
raise InvalidRequest('Trigger is not active.')
|
||||
|
||||
try:
|
||||
repo = model.get_repository(namespace, repository)
|
||||
pull_robot_name = model.get_pull_robot_name(trigger)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
pull_robot_name = model.build.get_pull_robot_name(trigger)
|
||||
|
||||
run_parameters = request.get_json()
|
||||
prepared = handler.manual_start(run_parameters=run_parameters)
|
||||
|
@ -454,10 +455,9 @@ class TriggerBuildList(RepositoryParamResource):
|
|||
def get(self, args, namespace, repository, trigger_uuid):
|
||||
""" List the builds started by the specified trigger. """
|
||||
limit = args['limit']
|
||||
builds = list(model.list_trigger_builds(namespace, repository,
|
||||
trigger_uuid, limit))
|
||||
builds = model.build.list_trigger_builds(namespace, repository, trigger_uuid, limit)
|
||||
return {
|
||||
'builds': [build_status_view(build) for build in builds]
|
||||
'builds': [build_status_view(bld) for bld in builds]
|
||||
}
|
||||
|
||||
|
||||
|
@ -471,7 +471,7 @@ class BuildTriggerFieldValues(RepositoryParamResource):
|
|||
def post(self, namespace, repository, trigger_uuid, field_name):
|
||||
""" List the field values for a custom run field. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -502,7 +502,7 @@ class BuildTriggerSources(RepositoryParamResource):
|
|||
def get(self, namespace, repository, trigger_uuid):
|
||||
""" List the build sources for the trigger configuration thus far. """
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
raise NotFound()
|
||||
|
||||
|
|
|
@ -3,33 +3,33 @@
|
|||
import logging
|
||||
import json
|
||||
|
||||
from random import SystemRandom
|
||||
from flask import request, abort
|
||||
from flask.ext.login import logout_user
|
||||
from flask.ext.principal import identity_changed, AnonymousIdentity
|
||||
from peewee import IntegrityError
|
||||
|
||||
import features
|
||||
|
||||
from app import app, billing as stripe, authentication, avatar
|
||||
from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error,
|
||||
log_action, internal_only, NotFound, require_user_admin, parse_args,
|
||||
query_param, InvalidToken, require_scope, format_date, hide_if, show_if,
|
||||
query_param, InvalidToken, require_scope, format_date, show_if,
|
||||
license_error, require_fresh_login, path_param, define_json_response,
|
||||
RepositoryParamResource)
|
||||
from endpoints.api.subscribe import subscribe
|
||||
from endpoints.common import common_login
|
||||
from endpoints.decorators import anon_allowed
|
||||
from endpoints.api.team import try_accept_invite
|
||||
|
||||
from data import model
|
||||
from data.billing import get_plan
|
||||
from auth.permissions import (AdministerOrganizationPermission, CreateRepositoryPermission,
|
||||
UserAdminPermission, UserReadPermission, SuperUserPermission)
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from util.useremails import (send_confirmation_email, send_recovery_email, send_change_email, send_password_changed)
|
||||
from util.useremails import (send_confirmation_email, send_recovery_email, send_change_email,
|
||||
send_password_changed)
|
||||
from util.names import parse_single_urn
|
||||
|
||||
import features
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -45,7 +45,7 @@ def user_view(user):
|
|||
'preferred_namespace': not (o.stripe_id is None)
|
||||
}
|
||||
|
||||
organizations = model.get_user_organizations(user.username)
|
||||
organizations = model.organization.get_user_organizations(user.username)
|
||||
|
||||
def login_view(login):
|
||||
try:
|
||||
|
@ -59,7 +59,7 @@ def user_view(user):
|
|||
'metadata': metadata
|
||||
}
|
||||
|
||||
logins = model.list_federated_logins(user)
|
||||
logins = model.user.list_federated_logins(user)
|
||||
|
||||
user_response = {
|
||||
'anonymous': False,
|
||||
|
@ -89,14 +89,14 @@ def user_view(user):
|
|||
return user_response
|
||||
|
||||
|
||||
def notification_view(notification):
|
||||
def notification_view(note):
|
||||
return {
|
||||
'id': notification.uuid,
|
||||
'organization': notification.target.username if notification.target.organization else None,
|
||||
'kind': notification.kind.name,
|
||||
'created': format_date(notification.created),
|
||||
'metadata': json.loads(notification.metadata_json),
|
||||
'dismissed': notification.dismissed
|
||||
'id': note.uuid,
|
||||
'organization': note.target.username if note.target.organization else None,
|
||||
'kind': note.kind.name,
|
||||
'created': format_date(note.created),
|
||||
'metadata': json.loads(note.metadata_json),
|
||||
'dismissed': note.dismissed
|
||||
}
|
||||
|
||||
|
||||
|
@ -238,7 +238,7 @@ class User(ApiResource):
|
|||
log_action('account_change_password', user.username)
|
||||
|
||||
# Change the user's password.
|
||||
model.change_password(user, user_data['password'])
|
||||
model.user.change_password(user, user_data['password'])
|
||||
|
||||
# Login again to reset their session cookie.
|
||||
common_login(user)
|
||||
|
@ -248,36 +248,36 @@ class User(ApiResource):
|
|||
|
||||
if 'invoice_email' in user_data:
|
||||
logger.debug('Changing invoice_email for user: %s', user.username)
|
||||
model.change_invoice_email(user, user_data['invoice_email'])
|
||||
model.user.change_invoice_email(user, user_data['invoice_email'])
|
||||
|
||||
if 'tag_expiration' in user_data:
|
||||
logger.debug('Changing user tag expiration to: %ss', user_data['tag_expiration'])
|
||||
model.change_user_tag_expiration(user, user_data['tag_expiration'])
|
||||
model.user.change_user_tag_expiration(user, user_data['tag_expiration'])
|
||||
|
||||
if 'email' in user_data and user_data['email'] != user.email:
|
||||
new_email = user_data['email']
|
||||
if model.find_user_by_email(new_email):
|
||||
if model.user.find_user_by_email(new_email):
|
||||
# Email already used.
|
||||
raise request_error(message='E-mail address already used')
|
||||
|
||||
if features.MAILING:
|
||||
logger.debug('Sending email to change email address for user: %s',
|
||||
user.username)
|
||||
code = model.create_confirm_email_code(user, new_email=new_email)
|
||||
code = model.user.create_confirm_email_code(user, new_email=new_email)
|
||||
send_change_email(user.username, user_data['email'], code.code)
|
||||
else:
|
||||
model.update_email(user, new_email, auto_verify=not features.MAILING)
|
||||
model.user.update_email(user, new_email, auto_verify=not features.MAILING)
|
||||
|
||||
if ('username' in user_data and user_data['username'] != user.username and
|
||||
features.USER_RENAME):
|
||||
new_username = user_data['username']
|
||||
if model.get_user_or_org(new_username) is not None:
|
||||
if model.user.get_user_or_org(new_username) is not None:
|
||||
# Username already used
|
||||
raise request_error(message='Username is already in use')
|
||||
|
||||
model.change_username(user.id, new_username)
|
||||
model.user.change_username(user.id, new_username)
|
||||
|
||||
except model.InvalidPasswordException, ex:
|
||||
except model.user.InvalidPasswordException, ex:
|
||||
raise request_error(exception=ex)
|
||||
|
||||
return user_view(user)
|
||||
|
@ -291,12 +291,12 @@ class User(ApiResource):
|
|||
user_data = request.get_json()
|
||||
invite_code = user_data.get('invite_code', '')
|
||||
|
||||
existing_user = model.get_nonrobot_user(user_data['username'])
|
||||
existing_user = model.user.get_nonrobot_user(user_data['username'])
|
||||
if existing_user:
|
||||
raise request_error(message='The username already exists')
|
||||
|
||||
try:
|
||||
new_user = model.create_user(user_data['username'], user_data['password'],
|
||||
new_user = model.user.create_user(user_data['username'], user_data['password'],
|
||||
user_data['email'], auto_verify=not features.MAILING)
|
||||
|
||||
# Handle any invite codes.
|
||||
|
@ -306,12 +306,12 @@ class User(ApiResource):
|
|||
# Add the user to the team.
|
||||
try:
|
||||
try_accept_invite(invite_code, new_user)
|
||||
except model.DataModelException:
|
||||
except model.user.DataModelException:
|
||||
pass
|
||||
|
||||
|
||||
if features.MAILING:
|
||||
code = model.create_confirm_email_code(new_user)
|
||||
code = model.user.create_confirm_email_code(new_user)
|
||||
send_confirmation_email(new_user.username, new_user.email, code.code)
|
||||
return {
|
||||
'awaiting_verification': True
|
||||
|
@ -320,9 +320,9 @@ class User(ApiResource):
|
|||
common_login(new_user)
|
||||
return user_view(new_user)
|
||||
|
||||
except model.TooManyUsersException as ex:
|
||||
except model.user.TooManyUsersException as ex:
|
||||
raise license_error(exception=ex)
|
||||
except model.DataModelException as ex:
|
||||
except model.user.DataModelException as ex:
|
||||
raise request_error(exception=ex)
|
||||
|
||||
@resource('/v1/user/private')
|
||||
|
@ -336,7 +336,7 @@ class PrivateRepositories(ApiResource):
|
|||
""" Get the number of private repos this user has, and whether they are allowed to create more.
|
||||
"""
|
||||
user = get_authenticated_user()
|
||||
private_repos = model.get_private_repo_count(user.username)
|
||||
private_repos = model.user.get_private_repo_count(user.username)
|
||||
repos_allowed = 0
|
||||
|
||||
if user.stripe_id:
|
||||
|
@ -396,7 +396,7 @@ def conduct_signin(username_or_email, password):
|
|||
verified = None
|
||||
try:
|
||||
(verified, error_message) = authentication.verify_user(username_or_email, password)
|
||||
except model.TooManyUsersException as ex:
|
||||
except model.user.TooManyUsersException as ex:
|
||||
raise license_error(exception=ex)
|
||||
|
||||
if verified:
|
||||
|
@ -457,15 +457,14 @@ class ConvertToOrganization(ApiResource):
|
|||
# Ensure that the sign in credentials work.
|
||||
admin_username = convert_data['adminUser']
|
||||
admin_password = convert_data['adminPassword']
|
||||
(admin_user, error_message) = authentication.verify_user(admin_username, admin_password)
|
||||
(admin_user, _) = authentication.verify_user(admin_username, admin_password)
|
||||
if not admin_user:
|
||||
raise request_error(reason='invaliduser',
|
||||
message='The admin user credentials are not valid')
|
||||
message='The admin user credentials are not valid')
|
||||
|
||||
# Ensure that the new admin user is the not user being converted.
|
||||
if admin_user.id == user.id:
|
||||
raise request_error(reason='invaliduser',
|
||||
message='The admin user is not valid')
|
||||
raise request_error(reason='invaliduser', message='The admin user is not valid')
|
||||
|
||||
# Subscribe the organization to the new plan.
|
||||
if features.BILLING:
|
||||
|
@ -473,7 +472,7 @@ class ConvertToOrganization(ApiResource):
|
|||
subscribe(user, plan, None, True) # Require business plans
|
||||
|
||||
# Convert the user to an organization.
|
||||
model.convert_user_to_organization(user, admin_user)
|
||||
model.organization.convert_user_to_organization(user, admin_user)
|
||||
log_action('account_convert', user.username)
|
||||
|
||||
# And finally login with the admin credentials.
|
||||
|
@ -583,7 +582,7 @@ class DetachExternal(ApiResource):
|
|||
@nickname('detachExternalLogin')
|
||||
def post(self, servicename):
|
||||
""" Request that the current user be detached from the external login service. """
|
||||
model.detach_external_login(get_authenticated_user(), servicename)
|
||||
model.user.detach_external_login(get_authenticated_user(), servicename)
|
||||
return {'success': True}
|
||||
|
||||
|
||||
|
@ -614,7 +613,7 @@ class Recovery(ApiResource):
|
|||
def post(self):
|
||||
""" Request a password recovery email."""
|
||||
email = request.get_json()['email']
|
||||
code = model.create_reset_password_email_code(email)
|
||||
code = model.user.create_reset_password_email_code(email)
|
||||
send_recovery_email(email, code.code)
|
||||
return 'Created', 201
|
||||
|
||||
|
@ -631,7 +630,8 @@ class UserNotificationList(ApiResource):
|
|||
page = args['page']
|
||||
limit = args['limit']
|
||||
|
||||
notifications = list(model.list_notifications(get_authenticated_user(), page=page, limit=limit + 1))
|
||||
notifications = list(model.notification.list_notifications(get_authenticated_user(), page=page,
|
||||
limit=limit + 1))
|
||||
has_more = False
|
||||
|
||||
if len(notifications) > limit:
|
||||
|
@ -639,7 +639,7 @@ class UserNotificationList(ApiResource):
|
|||
notifications = notifications[0:limit]
|
||||
|
||||
return {
|
||||
'notifications': [notification_view(notification) for notification in notifications],
|
||||
'notifications': [notification_view(note) for note in notifications],
|
||||
'additional': has_more
|
||||
}
|
||||
|
||||
|
@ -665,24 +665,24 @@ class UserNotification(ApiResource):
|
|||
@require_user_admin
|
||||
@nickname('getUserNotification')
|
||||
def get(self, uuid):
|
||||
notification = model.lookup_notification(get_authenticated_user(), uuid)
|
||||
if not notification:
|
||||
note = model.notification.lookup_notification(get_authenticated_user(), uuid)
|
||||
if not note:
|
||||
raise NotFound()
|
||||
|
||||
return notification_view(notification)
|
||||
return notification_view(note)
|
||||
|
||||
@require_user_admin
|
||||
@nickname('updateUserNotification')
|
||||
@validate_json_request('UpdateNotification')
|
||||
def put(self, uuid):
|
||||
notification = model.lookup_notification(get_authenticated_user(), uuid)
|
||||
if not notification:
|
||||
note = model.notification.lookup_notification(get_authenticated_user(), uuid)
|
||||
if not note:
|
||||
raise NotFound()
|
||||
|
||||
notification.dismissed = request.get_json().get('dismissed', False)
|
||||
notification.save()
|
||||
note.dismissed = request.get_json().get('dismissed', False)
|
||||
note.save()
|
||||
|
||||
return notification_view(notification)
|
||||
return notification_view(note)
|
||||
|
||||
|
||||
def authorization_view(access_token):
|
||||
|
@ -733,8 +733,7 @@ class UserAuthorization(ApiResource):
|
|||
@require_user_admin
|
||||
@nickname('deleteUserAuthorization')
|
||||
def delete(self, access_token_uuid):
|
||||
access_token = model.oauth.lookup_access_token_for_user(get_authenticated_user(),
|
||||
access_token_uuid)
|
||||
access_token = model.oauth.lookup_access_token_for_user(get_authenticated_user(), access_token_uuid)
|
||||
if not access_token:
|
||||
raise NotFound()
|
||||
|
||||
|
@ -774,9 +773,8 @@ class StarredRepositoryList(ApiResource):
|
|||
""" List all starred repositories. """
|
||||
page = args['page']
|
||||
limit = args['limit']
|
||||
starred_repos = model.get_user_starred_repositories(get_authenticated_user(),
|
||||
page=page,
|
||||
limit=limit)
|
||||
starred_repos = model.repository.get_user_starred_repositories(get_authenticated_user(),
|
||||
page=page, limit=limit)
|
||||
def repo_view(repo_obj):
|
||||
return {
|
||||
'namespace': repo_obj.namespace_user.username,
|
||||
|
@ -797,11 +795,11 @@ class StarredRepositoryList(ApiResource):
|
|||
req = request.get_json()
|
||||
namespace = req['namespace']
|
||||
repository = req['repository']
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
|
||||
if repo:
|
||||
try:
|
||||
model.star_repository(user, repo)
|
||||
model.repository.star_repository(user, repo)
|
||||
except IntegrityError:
|
||||
pass
|
||||
|
||||
|
@ -820,10 +818,10 @@ class StarredRepository(RepositoryParamResource):
|
|||
def delete(self, namespace, repository):
|
||||
""" Removes a star from a repository. """
|
||||
user = get_authenticated_user()
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
|
||||
if repo:
|
||||
model.unstar_repository(user, repo)
|
||||
model.repository.unstar_repository(user, repo)
|
||||
return 'Deleted', 204
|
||||
|
||||
|
||||
|
@ -833,7 +831,7 @@ class Users(ApiResource):
|
|||
@nickname('getUserInformation')
|
||||
def get(self, username):
|
||||
""" Get user information for the specified user. """
|
||||
user = model.get_nonrobot_user(username)
|
||||
user = model.user.get_nonrobot_user(username)
|
||||
if user is None:
|
||||
abort(404)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ bitbuckettrigger = Blueprint('bitbuckettrigger', __name__)
|
|||
@route_show_if(features.BITBUCKET_BUILD)
|
||||
@require_session_login
|
||||
def attach_bitbucket_build_trigger(trigger_uuid):
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
if not trigger or trigger.service.name != BitbucketBuildTrigger.service_name():
|
||||
abort(404)
|
||||
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
import logging
|
||||
import json
|
||||
|
||||
from flask import request
|
||||
|
||||
from app import app, dockerfile_build_queue
|
||||
from data import model
|
||||
from data.database import db
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from endpoints.notificationhelper import spawn_notification
|
||||
from flask import request
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start_build(repository, prepared_build, pull_robot_name=None):
|
||||
host = app.config['SERVER_HOSTNAME']
|
||||
repo_path = '%s/%s/%s' % (host, repository.namespace_user.username, repository.name)
|
||||
|
||||
token = model.create_access_token(repository, 'write', kind='build-worker',
|
||||
friendly_name='Repository Build Token')
|
||||
new_token = model.token.create_access_token(repository, 'write', kind='build-worker',
|
||||
friendly_name='Repository Build Token')
|
||||
logger.debug('Creating build %s with repo %s tags %s',
|
||||
prepared_build.build_name, repo_path, prepared_build.tags)
|
||||
|
||||
|
@ -29,15 +32,17 @@ def start_build(repository, prepared_build, pull_robot_name=None):
|
|||
}
|
||||
|
||||
with app.config['DB_TRANSACTION_FACTORY'](db):
|
||||
build_request = model.create_repository_build(repository, token, job_config,
|
||||
prepared_build.dockerfile_id,
|
||||
prepared_build.build_name,
|
||||
prepared_build.trigger,
|
||||
pull_robot_name=pull_robot_name)
|
||||
build_request = model.build.create_repository_build(repository, new_token, job_config,
|
||||
prepared_build.dockerfile_id,
|
||||
prepared_build.build_name,
|
||||
prepared_build.trigger,
|
||||
pull_robot_name=pull_robot_name)
|
||||
|
||||
pull_creds = model.user.get_pull_credentials(pull_robot_name) if pull_robot_name else None
|
||||
|
||||
json_data = json.dumps({
|
||||
'build_uuid': build_request.uuid,
|
||||
'pull_credentials': model.get_pull_credentials(pull_robot_name) if pull_robot_name else None
|
||||
'pull_credentials': pull_creds
|
||||
})
|
||||
|
||||
queue_id = dockerfile_build_queue.put([repository.namespace_user.username, repository.name],
|
||||
|
@ -62,8 +67,8 @@ def start_build(repository, prepared_build, pull_robot_name=None):
|
|||
event_log_metadata['trigger_kind'] = prepared_build.trigger.service.name
|
||||
event_log_metadata['trigger_metadata'] = prepared_build.metadata or {}
|
||||
|
||||
model.log_action('build_dockerfile', repository.namespace_user.username, ip=request.remote_addr,
|
||||
metadata=event_log_metadata, repository=repository)
|
||||
model.log.log_action('build_dockerfile', repository.namespace_user.username,
|
||||
ip=request.remote_addr, metadata=event_log_metadata, repository=repository)
|
||||
|
||||
spawn_notification(repository, 'build_queued', event_log_metadata,
|
||||
subpage='build/%s' % build_request.uuid,
|
||||
|
|
|
@ -199,11 +199,12 @@ def render_page_template(name, **kwargs):
|
|||
|
||||
|
||||
def check_repository_usage(user_or_org, plan_found):
|
||||
private_repos = model.get_private_repo_count(user_or_org.username)
|
||||
private_repos = model.user.get_private_repo_count(user_or_org.username)
|
||||
repos_allowed = plan_found['privateRepos']
|
||||
|
||||
if private_repos > repos_allowed:
|
||||
model.create_notification('over_private_usage', user_or_org, {'namespace': user_or_org.username})
|
||||
model.notification.create_notification('over_private_usage', user_or_org,
|
||||
{'namespace': user_or_org.username})
|
||||
else:
|
||||
model.delete_notifications_by_kind(user_or_org, 'over_private_usage')
|
||||
model.notification.delete_notifications_by_kind(user_or_org, 'over_private_usage')
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@ def attach_github_build_trigger(namespace, repository):
|
|||
if permission.can():
|
||||
code = request.args.get('code')
|
||||
token = github_trigger.exchange_code_for_token(app.config, client, code)
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
msg = 'Invalid repository: %s/%s' % (namespace, repository)
|
||||
abort(404, message=msg)
|
||||
|
||||
trigger = model.create_build_trigger(repo, 'github', token, current_user.db_user())
|
||||
trigger = model.build.create_build_trigger(repo, 'github', token, current_user.db_user())
|
||||
repo_path = '%s/%s' % (namespace, repository)
|
||||
full_url = '%s%s%s' % (url_for('web.repository', path=repo_path), '?tab=builds&newtrigger=',
|
||||
trigger.uuid)
|
||||
|
|
|
@ -9,7 +9,6 @@ from auth.permissions import AdministerRepositoryPermission
|
|||
from data import model
|
||||
from endpoints.common import route_show_if
|
||||
from util.http import abort
|
||||
from util.names import parse_repository_name
|
||||
|
||||
import features
|
||||
|
||||
|
@ -40,14 +39,15 @@ def attach_gitlab_build_trigger():
|
|||
msg = 'Could not exchange token. It may have expired.'
|
||||
abort(404, message=msg)
|
||||
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
msg = 'Invalid repository: %s/%s' % (namespace, repository)
|
||||
abort(404, message=msg)
|
||||
|
||||
trigger = model.create_build_trigger(repo, 'gitlab', token, current_user.db_user())
|
||||
trigger = model.build.create_build_trigger(repo, 'gitlab', token, current_user.db_user())
|
||||
repo_path = '%s/%s' % (namespace, repository)
|
||||
full_url = '%s%s%s' % (url_for('web.repository', path=repo_path), '?tab=builds&newtrigger=', trigger.uuid)
|
||||
full_url = '%s%s%s' % (url_for('web.repository', path=repo_path), '?tab=builds&newtrigger=',
|
||||
trigger.uuid)
|
||||
|
||||
logger.debug('Redirecting to full url: %s', full_url)
|
||||
return redirect(full_url)
|
||||
|
|
|
@ -54,8 +54,9 @@ def spawn_notification(repo, event_name, extra_data={}, subpage=None, pathargs=[
|
|||
performer_data=None):
|
||||
event_data = build_event_data(repo, extra_data=extra_data, subpage=subpage)
|
||||
|
||||
notifications = model.list_repo_notifications(repo.namespace_user.username, repo.name,
|
||||
event_name=event_name)
|
||||
notifications = model.notification.list_repo_notifications(repo.namespace_user.username,
|
||||
repo.name,
|
||||
event_name=event_name)
|
||||
for notification in list(notifications):
|
||||
notification_data = build_notification_data(notification, event_data, performer_data)
|
||||
path = [repo.namespace_user.username, repo.name, event_name] + pathargs
|
||||
|
|
|
@ -38,11 +38,11 @@ class NotificationMethod(object):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
"""
|
||||
Performs the notification method.
|
||||
|
||||
notification: The noticication record itself.
|
||||
notification_obj: The noticication record itself.
|
||||
event_handler: The NotificationEvent handler.
|
||||
notification_data: The dict of notification data placed in the queue.
|
||||
"""
|
||||
|
@ -71,14 +71,14 @@ class QuayNotificationMethod(NotificationMethod):
|
|||
target_info = config_data['target']
|
||||
|
||||
if target_info['kind'] == 'user':
|
||||
target = model.get_nonrobot_user(target_info['name'])
|
||||
target = model.user.get_nonrobot_user(target_info['name'])
|
||||
if not target:
|
||||
# Just to be safe.
|
||||
return (True, 'Unknown user %s' % target_info['name'], [])
|
||||
|
||||
return (True, None, [target])
|
||||
elif target_info['kind'] == 'org':
|
||||
target = model.get_organization(target_info['name'])
|
||||
target = model.organization.get_organization(target_info['name'])
|
||||
if not target:
|
||||
# Just to be safe.
|
||||
return (True, 'Unknown organization %s' % target_info['name'], None)
|
||||
|
@ -90,33 +90,34 @@ class QuayNotificationMethod(NotificationMethod):
|
|||
return (True, None, [target])
|
||||
elif target_info['kind'] == 'team':
|
||||
# Lookup the team.
|
||||
team = None
|
||||
org_team = None
|
||||
try:
|
||||
team = model.get_organization_team(repository.namespace_user.username, target_info['name'])
|
||||
org_team = model.team.get_organization_team(repository.namespace_user.username,
|
||||
target_info['name'])
|
||||
except model.InvalidTeamException:
|
||||
# Probably deleted.
|
||||
return (True, 'Unknown team %s' % target_info['name'], None)
|
||||
|
||||
# Lookup the team's members
|
||||
return (True, None, model.get_organization_team_members(team.id))
|
||||
return (True, None, model.organization.get_organization_team_members(org_team.id))
|
||||
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
repository = notification.repository
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
repository = notification_obj.repository
|
||||
if not repository:
|
||||
# Probably deleted.
|
||||
return
|
||||
|
||||
# Lookup the target user or team to which we'll send the notification.
|
||||
config_data = json.loads(notification.config_json)
|
||||
config_data = json.loads(notification_obj.config_json)
|
||||
status, err_message, target_users = self.find_targets(repository, config_data)
|
||||
if not status:
|
||||
raise NotificationMethodPerformException(err_message)
|
||||
|
||||
# For each of the target users, create a notification.
|
||||
for target_user in set(target_users or []):
|
||||
model.create_notification(event_handler.event_name(), target_user,
|
||||
metadata=notification_data['event_data'])
|
||||
model.notification.create_notification(event_handler.event_name(), target_user,
|
||||
metadata=notification_data['event_data'])
|
||||
|
||||
|
||||
class EmailMethod(NotificationMethod):
|
||||
|
@ -129,16 +130,16 @@ class EmailMethod(NotificationMethod):
|
|||
if not email:
|
||||
raise CannotValidateNotificationMethodException('Missing e-mail address')
|
||||
|
||||
record = model.get_email_authorized_for_repo(repository.namespace_user.username,
|
||||
repository.name, email)
|
||||
record = model.repository.get_email_authorized_for_repo(repository.namespace_user.username,
|
||||
repository.name, email)
|
||||
if not record or not record.confirmed:
|
||||
raise CannotValidateNotificationMethodException('The specified e-mail address '
|
||||
'is not authorized to receive '
|
||||
'notifications for this repository')
|
||||
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
config_data = json.loads(notification.config_json)
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
config_data = json.loads(notification_obj.config_json)
|
||||
email = config_data.get('email', '')
|
||||
if not email:
|
||||
return
|
||||
|
@ -166,8 +167,8 @@ class WebhookMethod(NotificationMethod):
|
|||
if not url:
|
||||
raise CannotValidateNotificationMethodException('Missing webhook URL')
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
config_data = json.loads(notification.config_json)
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
config_data = json.loads(notification_obj.config_json)
|
||||
url = config_data.get('url', '')
|
||||
if not url:
|
||||
return
|
||||
|
@ -201,13 +202,13 @@ class FlowdockMethod(NotificationMethod):
|
|||
if not token:
|
||||
raise CannotValidateNotificationMethodException('Missing Flowdock API Token')
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
config_data = json.loads(notification.config_json)
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
config_data = json.loads(notification_obj.config_json)
|
||||
token = config_data.get('flow_api_token', '')
|
||||
if not token:
|
||||
return
|
||||
|
||||
owner = model.get_user_or_org(notification.repository.namespace_user.username)
|
||||
owner = model.user.get_user_or_org(notification_obj.repository.namespace_user.username)
|
||||
if not owner:
|
||||
# Something went wrong.
|
||||
return
|
||||
|
@ -220,8 +221,8 @@ class FlowdockMethod(NotificationMethod):
|
|||
'subject': event_handler.get_summary(notification_data['event_data'], notification_data),
|
||||
'content': event_handler.get_message(notification_data['event_data'], notification_data),
|
||||
'from_name': owner.username,
|
||||
'project': (notification.repository.namespace_user.username + ' ' +
|
||||
notification.repository.name),
|
||||
'project': (notification_obj.repository.namespace_user.username + ' ' +
|
||||
notification_obj.repository.name),
|
||||
'tags': ['#' + event_handler.event_name()],
|
||||
'link': notification_data['event_data']['homepage']
|
||||
}
|
||||
|
@ -254,8 +255,8 @@ class HipchatMethod(NotificationMethod):
|
|||
if not config_data.get('room_id', ''):
|
||||
raise CannotValidateNotificationMethodException('Missing Hipchat Room ID')
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
config_data = json.loads(notification.config_json)
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
config_data = json.loads(notification_obj.config_json)
|
||||
|
||||
token = config_data.get('notification_token', '')
|
||||
room_id = config_data.get('room_id', '')
|
||||
|
@ -263,7 +264,7 @@ class HipchatMethod(NotificationMethod):
|
|||
if not token or not room_id:
|
||||
return
|
||||
|
||||
owner = model.get_user_or_org(notification.repository.namespace_user.username)
|
||||
owner = model.user.get_user_or_org(notification_obj.repository.namespace_user.username)
|
||||
if not owner:
|
||||
# Something went wrong.
|
||||
return
|
||||
|
@ -367,14 +368,14 @@ class SlackMethod(NotificationMethod):
|
|||
message = message.replace('<br>', '\n')
|
||||
return adjust_tags(message)
|
||||
|
||||
def perform(self, notification, event_handler, notification_data):
|
||||
config_data = json.loads(notification.config_json)
|
||||
def perform(self, notification_obj, event_handler, notification_data):
|
||||
config_data = json.loads(notification_obj.config_json)
|
||||
|
||||
url = config_data.get('url', '')
|
||||
if not url:
|
||||
return
|
||||
|
||||
owner = model.get_user_or_org(notification.repository.namespace_user.username)
|
||||
owner = model.user.get_user_or_org(notification_obj.repository.namespace_user.username)
|
||||
if not owner:
|
||||
# Something went wrong.
|
||||
return
|
||||
|
|
|
@ -41,7 +41,7 @@ def get_user(service, token):
|
|||
|
||||
def conduct_oauth_login(service, user_id, username, email, metadata={}):
|
||||
service_name = service.service_name()
|
||||
to_login = model.verify_federated_login(service_name.lower(), user_id)
|
||||
to_login = model.user.verify_federated_login(service_name.lower(), user_id)
|
||||
if not to_login:
|
||||
# See if we can create a new user.
|
||||
if not features.USER_CREATION:
|
||||
|
@ -52,22 +52,22 @@ def conduct_oauth_login(service, user_id, username, email, metadata={}):
|
|||
try:
|
||||
new_username = None
|
||||
for valid in generate_valid_usernames(username):
|
||||
if model.get_user_or_org(valid):
|
||||
if model.user.get_user_or_org(valid):
|
||||
continue
|
||||
|
||||
new_username = valid
|
||||
break
|
||||
|
||||
to_login = model.create_federated_user(new_username, email, service_name.lower(),
|
||||
user_id, set_password_notification=True,
|
||||
metadata=metadata)
|
||||
to_login = model.user.create_federated_user(new_username, email, service_name.lower(),
|
||||
user_id, set_password_notification=True,
|
||||
metadata=metadata)
|
||||
|
||||
# Success, tell analytics
|
||||
analytics.track(to_login.username, 'register', {'service': service_name.lower()})
|
||||
|
||||
state = request.args.get('state', None)
|
||||
if state:
|
||||
logger.debug('Aliasing with state: %s' % state)
|
||||
logger.debug('Aliasing with state: %s', state)
|
||||
analytics.alias(to_login.username, state)
|
||||
|
||||
except model.InvalidEmailAddressException as ieex:
|
||||
|
@ -200,7 +200,7 @@ def google_oauth_attach():
|
|||
}
|
||||
|
||||
try:
|
||||
model.attach_federated_login(user_obj, 'google', google_id, metadata=metadata)
|
||||
model.user.attach_federated_login(user_obj, 'google', google_id, metadata=metadata)
|
||||
except IntegrityError:
|
||||
err = 'Google account %s is already attached to a %s account' % (
|
||||
username, app.config['REGISTRY_TITLE_SHORT'])
|
||||
|
@ -228,7 +228,7 @@ def github_oauth_attach():
|
|||
}
|
||||
|
||||
try:
|
||||
model.attach_federated_login(user_obj, 'github', github_id, metadata=metadata)
|
||||
model.user.attach_federated_login(user_obj, 'github', github_id, metadata=metadata)
|
||||
except IntegrityError:
|
||||
err = 'Github account %s is already attached to a %s account' % (
|
||||
username, app.config['REGISTRY_TITLE_SHORT'])
|
||||
|
|
|
@ -67,9 +67,7 @@ def track_and_log(event_name, repo, **kwargs):
|
|||
|
||||
# Log the action to the database.
|
||||
logger.debug('Logging the %s to logs system', event_name)
|
||||
model.log_action(event_name, namespace,
|
||||
performer=authenticated_user,
|
||||
ip=request.remote_addr, metadata=metadata,
|
||||
repository=repo)
|
||||
model.log.log_action(event_name, namespace, performer=authenticated_user, ip=request.remote_addr,
|
||||
metadata=metadata, repository=repo)
|
||||
|
||||
logger.debug('Track and log of %s complete', event_name)
|
||||
|
|
|
@ -227,11 +227,11 @@ class BuildTriggerHandler(object):
|
|||
def put_config_key(self, key, value):
|
||||
""" Updates a config key in the trigger, saving it to the DB. """
|
||||
self.config[key] = value
|
||||
model.update_build_trigger(self.trigger, self.config)
|
||||
model.build.update_build_trigger(self.trigger, self.config)
|
||||
|
||||
def set_auth_token(self, auth_token):
|
||||
""" Sets the auth token for the trigger, saving it to the DB. """
|
||||
model.update_build_trigger(self.trigger, self.config, auth_token=auth_token)
|
||||
model.build.update_build_trigger(self.trigger, self.config, auth_token=auth_token)
|
||||
|
||||
def get_dockerfile_path(self):
|
||||
""" Returns the normalized path to the Dockerfile found in the subdirectory
|
||||
|
|
|
@ -26,4 +26,4 @@ def ping():
|
|||
|
||||
from endpoints.v1 import index
|
||||
from endpoints.v1 import registry
|
||||
from endpoints.v1 import tags
|
||||
from endpoints.v1 import tag
|
|
@ -2,20 +2,17 @@ import json
|
|||
import logging
|
||||
import urlparse
|
||||
|
||||
from flask import request, make_response, jsonify, session, Blueprint
|
||||
from flask import request, make_response, jsonify, session
|
||||
from functools import wraps
|
||||
from collections import OrderedDict
|
||||
|
||||
from data import model
|
||||
from data.model import oauth
|
||||
from app import app, authentication, userevents, storage
|
||||
from auth.auth import process_auth, generate_signed_token
|
||||
from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token
|
||||
from util.names import parse_repository_name
|
||||
from util.useremails import send_confirmation_email
|
||||
from auth.permissions import (ModifyRepositoryPermission, UserAdminPermission,
|
||||
ReadRepositoryPermission, CreateRepositoryPermission,
|
||||
AlwaysFailPermission, repository_read_grant, repository_write_grant)
|
||||
repository_read_grant, repository_write_grant)
|
||||
|
||||
from util.http import abort
|
||||
from endpoints.v1 import v1_bp
|
||||
|
@ -23,8 +20,6 @@ from endpoints.trackhelper import track_and_log
|
|||
from endpoints.notificationhelper import spawn_notification
|
||||
from endpoints.decorators import anon_protect, anon_allowed
|
||||
|
||||
import features
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -90,13 +85,13 @@ def create_user():
|
|||
|
||||
if username == '$token':
|
||||
try:
|
||||
model.load_token_data(password)
|
||||
model.token.load_token_data(password)
|
||||
return success
|
||||
except model.InvalidTokenException:
|
||||
abort(400, 'Invalid access token.', issue='invalid-access-token')
|
||||
|
||||
elif username == '$oauthtoken':
|
||||
validated = oauth.validate_access_token(password)
|
||||
validated = model.oauth.validate_access_token(password)
|
||||
if validated is not None:
|
||||
return success
|
||||
else:
|
||||
|
@ -104,7 +99,7 @@ def create_user():
|
|||
|
||||
elif '+' in username:
|
||||
try:
|
||||
model.verify_robot(username, password)
|
||||
model.user.verify_robot(username, password)
|
||||
return success
|
||||
except model.InvalidRobotException:
|
||||
abort(400, 'Invalid robot account or password.',
|
||||
|
@ -157,12 +152,11 @@ def update_user(username):
|
|||
|
||||
if 'password' in update_request:
|
||||
logger.debug('Updating user password')
|
||||
model.change_password(get_authenticated_user(),
|
||||
update_request['password'])
|
||||
model.user.change_password(get_authenticated_user(), update_request['password'])
|
||||
|
||||
if 'email' in update_request:
|
||||
logger.debug('Updating user email')
|
||||
model.update_email(get_authenticated_user(), update_request['email'])
|
||||
model.user.update_email(get_authenticated_user(), update_request['email'])
|
||||
|
||||
return jsonify({
|
||||
'username': get_authenticated_user().username,
|
||||
|
@ -178,11 +172,8 @@ def update_user(username):
|
|||
@generate_headers(scope=GrantType.WRITE_REPOSITORY, add_grant_for_status=201)
|
||||
@anon_allowed
|
||||
def create_repository(namespace, repository):
|
||||
logger.debug('Parsing image descriptions for repository %s/%s', namespace, repository)
|
||||
image_descriptions = json.loads(request.data.decode('utf8'))
|
||||
|
||||
logger.debug('Looking up repository %s/%s', namespace, repository)
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
|
||||
logger.debug('Found repository %s/%s', namespace, repository)
|
||||
if not repo and get_authenticated_user() is None:
|
||||
|
@ -201,18 +192,16 @@ def create_repository(namespace, repository):
|
|||
else:
|
||||
permission = CreateRepositoryPermission(namespace)
|
||||
if not permission.can():
|
||||
logger.info('Attempt to create a new repo %s/%s with insufficient perms', namespace, repository)
|
||||
abort(403,
|
||||
message='You do not have permission to create repositories in namespace "%(namespace)s"',
|
||||
issue='no-create-permission',
|
||||
namespace=namespace)
|
||||
logger.info('Attempt to create a new repo %s/%s with insufficient perms', namespace,
|
||||
repository)
|
||||
msg = 'You do not have permission to create repositories in namespace "%(namespace)s"'
|
||||
abort(403, message=msg, issue='no-create-permission', namespace=namespace)
|
||||
|
||||
# Attempt to create the new repository.
|
||||
logger.debug('Creating repository %s/%s with owner: %s', namespace, repository,
|
||||
get_authenticated_user().username)
|
||||
|
||||
repo = model.create_repository(namespace, repository,
|
||||
get_authenticated_user())
|
||||
repo = model.repository.create_repository(namespace, repository, get_authenticated_user())
|
||||
|
||||
if get_authenticated_user():
|
||||
user_event_data = {
|
||||
|
@ -237,13 +226,13 @@ def update_images(namespace, repository):
|
|||
|
||||
if permission.can():
|
||||
logger.debug('Looking up repository')
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
# Make sure the repo actually exists.
|
||||
abort(404, message='Unknown repository', issue='unknown-repo')
|
||||
|
||||
logger.debug('GCing repository')
|
||||
model.garbage_collect_repository(namespace, repository)
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
# Generate a job for each notification that has been added to this repo
|
||||
logger.debug('Adding notifications for repository')
|
||||
|
@ -269,10 +258,10 @@ def get_repository_images(namespace, repository):
|
|||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
# TODO invalidate token?
|
||||
if permission.can() or model.repository_is_public(namespace, repository):
|
||||
if permission.can() or model.repository.repository_is_public(namespace, repository):
|
||||
# We can't rely on permissions to tell us if a repo exists anymore
|
||||
logger.debug('Looking up repository')
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo:
|
||||
abort(404, message='Unknown repository', issue='unknown-repo')
|
||||
|
||||
|
@ -320,7 +309,7 @@ def get_search():
|
|||
username = user.username
|
||||
|
||||
if query:
|
||||
matching = model.get_matching_repositories(query, username)
|
||||
matching = model.repository.get_matching_repositories(query, username)
|
||||
else:
|
||||
matching = []
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import logging
|
||||
import json
|
||||
|
||||
from flask import (make_response, request, session, Response, redirect,
|
||||
Blueprint, abort as flask_abort)
|
||||
from flask import make_response, request, session, Response, redirect, abort as flask_abort
|
||||
from functools import wraps
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
|
@ -61,7 +60,7 @@ def require_completion(f):
|
|||
@wraps(f)
|
||||
def wrapper(namespace, repository, *args, **kwargs):
|
||||
image_id = kwargs['image_id']
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if image_is_uploading(repo_image):
|
||||
abort(400, 'Image %(image_id)s is being uploaded, retry later',
|
||||
issue='upload-in-progress', image_id=kwargs['image_id'])
|
||||
|
@ -104,9 +103,9 @@ def head_image_layer(namespace, repository, image_id, headers):
|
|||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
logger.debug('Checking repo permissions')
|
||||
if permission.can() or model.repository_is_public(namespace, repository):
|
||||
if permission.can() or model.repository.repository_is_public(namespace, repository):
|
||||
logger.debug('Looking up repo image')
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if not repo_image:
|
||||
logger.debug('Image not found')
|
||||
abort(404, 'Image %(image_id)s not found', issue='unknown-image',
|
||||
|
@ -138,9 +137,9 @@ def get_image_layer(namespace, repository, image_id, headers):
|
|||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
logger.debug('Checking repo permissions')
|
||||
if permission.can() or model.repository_is_public(namespace, repository):
|
||||
if permission.can() or model.repository.repository_is_public(namespace, repository):
|
||||
logger.debug('Looking up repo image')
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if not repo_image:
|
||||
logger.debug('Image not found')
|
||||
abort(404, 'Image %(image_id)s not found', issue='unknown-image',
|
||||
|
@ -183,7 +182,7 @@ def put_image_layer(namespace, repository, image_id):
|
|||
abort(403)
|
||||
|
||||
logger.debug('Retrieving image')
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
try:
|
||||
logger.debug('Retrieving image data')
|
||||
uuid = repo_image.storage.uuid
|
||||
|
@ -236,17 +235,16 @@ def put_image_layer(namespace, repository, image_id):
|
|||
|
||||
try:
|
||||
# Save the size of the image.
|
||||
model.set_image_size(image_id, namespace, repository, size_info.compressed_size,
|
||||
size_info.uncompressed_size)
|
||||
model.image.set_image_size(image_id, namespace, repository, size_info.compressed_size,
|
||||
size_info.uncompressed_size)
|
||||
|
||||
if requires_tarsum:
|
||||
tmp.seek(0)
|
||||
csums.append(checksums.compute_tarsum(tmp, json_data))
|
||||
tmp.close()
|
||||
|
||||
except (IOError, checksums.TarError) as e:
|
||||
logger.debug('put_image_layer: Error when computing tarsum '
|
||||
'{0}'.format(e))
|
||||
except (IOError, checksums.TarError) as exc:
|
||||
logger.debug('put_image_layer: Error when computing tarsum %s', exc)
|
||||
|
||||
if repo_image.storage.checksum is None:
|
||||
# We don't have a checksum stored yet, that's fine skipping the check.
|
||||
|
@ -268,7 +266,7 @@ def put_image_layer(namespace, repository, image_id):
|
|||
# The layer is ready for download, send a job to the work queue to
|
||||
# process it.
|
||||
logger.debug('Adding layer to diff queue')
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
image_diff_queue.put([repo.namespace_user.username, repository, image_id], json.dumps({
|
||||
'namespace_user_id': repo.namespace_user.id,
|
||||
'repository': repository,
|
||||
|
@ -310,7 +308,7 @@ def put_image_checksum(namespace, repository, image_id):
|
|||
issue='missing-checksum-cookie', image_id=image_id)
|
||||
|
||||
logger.debug('Looking up repo image')
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if not repo_image or not repo_image.storage:
|
||||
abort(404, 'Image not found: %(image_id)s', issue='unknown-image', image_id=image_id)
|
||||
|
||||
|
@ -331,8 +329,8 @@ def put_image_checksum(namespace, repository, image_id):
|
|||
abort(400, err)
|
||||
|
||||
if checksum not in session.get('checksum', []):
|
||||
logger.debug('session checksums: %s' % session.get('checksum', []))
|
||||
logger.debug('client supplied checksum: %s' % checksum)
|
||||
logger.debug('session checksums: %s', session.get('checksum', []))
|
||||
logger.debug('client supplied checksum: %s', checksum)
|
||||
logger.debug('put_image_checksum: Wrong checksum')
|
||||
abort(400, 'Checksum mismatch for image: %(image_id)s',
|
||||
issue='checksum-mismatch', image_id=image_id)
|
||||
|
@ -343,7 +341,7 @@ def put_image_checksum(namespace, repository, image_id):
|
|||
# The layer is ready for download, send a job to the work queue to
|
||||
# process it.
|
||||
logger.debug('Adding layer to diff queue')
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
image_diff_queue.put([repo.namespace_user.username, repository, image_id], json.dumps({
|
||||
'namespace_user_id': repo.namespace_user.id,
|
||||
'repository': repository,
|
||||
|
@ -362,12 +360,11 @@ def put_image_checksum(namespace, repository, image_id):
|
|||
def get_image_json(namespace, repository, image_id, headers):
|
||||
logger.debug('Checking repo permissions')
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
if not permission.can() and not model.repository_is_public(namespace,
|
||||
repository):
|
||||
if not permission.can() and not model.repository.repository_is_public(namespace, repository):
|
||||
abort(403)
|
||||
|
||||
logger.debug('Looking up repo image')
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
|
||||
logger.debug('Looking up repo layer data')
|
||||
try:
|
||||
|
@ -394,12 +391,11 @@ def get_image_json(namespace, repository, image_id, headers):
|
|||
def get_image_ancestry(namespace, repository, image_id, headers):
|
||||
logger.debug('Checking repo permissions')
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
if not permission.can() and not model.repository_is_public(namespace,
|
||||
repository):
|
||||
if not permission.can() and not model.repository.repository_is_public(namespace, repository):
|
||||
abort(403)
|
||||
|
||||
logger.debug('Looking up repo image')
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
|
||||
logger.debug('Looking up image data')
|
||||
try:
|
||||
|
@ -465,22 +461,23 @@ def put_image_json(namespace, repository, image_id):
|
|||
|
||||
logger.debug('Looking up repo image')
|
||||
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if repo is None:
|
||||
abort(404, 'Repository does not exist: %(namespace)s/%(repository)s', issue='no-repo',
|
||||
namespace=namespace, repository=repository)
|
||||
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if not repo_image:
|
||||
username = (get_authenticated_user() and get_authenticated_user().username or
|
||||
get_grant_user_context())
|
||||
logger.debug('Image not found, creating image with initiating user context: %s', username)
|
||||
repo_image = model.find_create_or_link_image(image_id, repo, username, {},
|
||||
store.preferred_locations[0])
|
||||
repo_image = model.image.find_create_or_link_image(image_id, repo, username, {},
|
||||
store.preferred_locations[0])
|
||||
|
||||
# Create a temporary tag to prevent this image from getting garbage collected while the push
|
||||
# is in progress.
|
||||
model.create_temporary_hidden_tag(repo, repo_image, app.config['PUSH_TEMP_TAG_EXPIRATION_SEC'])
|
||||
model.tag.create_temporary_hidden_tag(repo, repo_image,
|
||||
app.config['PUSH_TEMP_TAG_EXPIRATION_SEC'])
|
||||
|
||||
uuid = repo_image.storage.uuid
|
||||
|
||||
|
@ -493,7 +490,7 @@ def put_image_json(namespace, repository, image_id):
|
|||
parent_image = None
|
||||
if parent_id:
|
||||
logger.debug('Looking up parent image')
|
||||
parent_image = model.get_repo_image_extended(namespace, repository, parent_id)
|
||||
parent_image = model.image.get_repo_image_extended(namespace, repository, parent_id)
|
||||
|
||||
parent_uuid = parent_image and parent_image.storage.uuid
|
||||
parent_locations = parent_image and parent_image.storage.locations
|
||||
|
@ -523,9 +520,8 @@ def put_image_json(namespace, repository, image_id):
|
|||
command = json.dumps(command_list) if command_list else None
|
||||
|
||||
logger.debug('Setting image metadata')
|
||||
model.set_image_metadata(image_id, namespace, repository,
|
||||
data.get('created'), data.get('comment'), command,
|
||||
parent_image)
|
||||
model.image.set_image_metadata(image_id, namespace, repository, data.get('created'),
|
||||
data.get('comment'), command, parent_image)
|
||||
|
||||
logger.debug('Putting json path')
|
||||
store.put_content(repo_image.storage.locations, json_path, request.data)
|
||||
|
@ -536,7 +532,7 @@ def put_image_json(namespace, repository, image_id):
|
|||
generate_ancestry(image_id, uuid, repo_image.storage.locations, parent_id, parent_uuid,
|
||||
parent_locations)
|
||||
except IOError as ioe:
|
||||
logger.debug('Error when generating ancestry: %s' % ioe.message)
|
||||
logger.debug('Error when generating ancestry: %s', ioe.message)
|
||||
abort(404)
|
||||
|
||||
logger.debug('Done')
|
||||
|
@ -544,9 +540,9 @@ def put_image_json(namespace, repository, image_id):
|
|||
|
||||
|
||||
def process_image_changes(namespace, repository, image_id):
|
||||
logger.debug('Generating diffs for image: %s' % image_id)
|
||||
logger.debug('Generating diffs for image: %s', image_id)
|
||||
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, image_id)
|
||||
if not repo_image:
|
||||
logger.warning('No image for id: %s', image_id)
|
||||
return None, None
|
||||
|
@ -557,11 +553,11 @@ def process_image_changes(namespace, repository, image_id):
|
|||
image_trie_path = store.image_file_trie_path(uuid)
|
||||
|
||||
if store.exists(repo_image.storage.locations, image_diffs_path):
|
||||
logger.debug('Diffs already exist for image: %s' % image_id)
|
||||
logger.debug('Diffs already exist for image: %s', image_id)
|
||||
return image_trie_path, repo_image.storage.locations
|
||||
|
||||
image = model.get_image_by_id(namespace, repository, image_id)
|
||||
parents = model.get_parent_images(namespace, repository, image)
|
||||
image = model.image.get_image_by_id(namespace, repository, image_id)
|
||||
parents = model.image.get_parent_images(namespace, repository, image)
|
||||
|
||||
# Compute the diffs and fs for the parent first if necessary
|
||||
parent_trie_path = None
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import logging
|
||||
import json
|
||||
|
||||
from flask import abort, request, jsonify, make_response, Blueprint, session
|
||||
from flask import abort, request, jsonify, make_response, session
|
||||
|
||||
from app import app
|
||||
from util.names import parse_repository_name
|
||||
|
@ -17,32 +17,30 @@ from endpoints.v1 import v1_bp
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@v1_bp.route('/repositories/<path:repository>/tags',
|
||||
methods=['GET'])
|
||||
@v1_bp.route('/repositories/<path:repository>/tags', methods=['GET'])
|
||||
@process_auth
|
||||
@anon_protect
|
||||
@parse_repository_name
|
||||
def get_tags(namespace, repository):
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
if permission.can() or model.repository_is_public(namespace, repository):
|
||||
tags = model.list_repository_tags(namespace, repository)
|
||||
if permission.can() or model.repository.repository_is_public(namespace, repository):
|
||||
tags = model.tag.list_repository_tags(namespace, repository)
|
||||
tag_map = {tag.name: tag.image.docker_image_id for tag in tags}
|
||||
return jsonify(tag_map)
|
||||
|
||||
abort(403)
|
||||
|
||||
|
||||
@v1_bp.route('/repositories/<path:repository>/tags/<tag>',
|
||||
methods=['GET'])
|
||||
@v1_bp.route('/repositories/<path:repository>/tags/<tag>', methods=['GET'])
|
||||
@process_auth
|
||||
@anon_protect
|
||||
@parse_repository_name
|
||||
def get_tag(namespace, repository, tag):
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
if permission.can() or model.repository_is_public(namespace, repository):
|
||||
tag_image = model.get_tag_image(namespace, repository, tag)
|
||||
if permission.can() or model.repository.repository_is_public(namespace, repository):
|
||||
tag_image = model.tag.get_tag_image(namespace, repository, tag)
|
||||
resp = make_response('"%s"' % tag_image.docker_image_id)
|
||||
resp.headers['Content-Type'] = 'application/json'
|
||||
return resp
|
||||
|
@ -50,8 +48,7 @@ def get_tag(namespace, repository, tag):
|
|||
abort(403)
|
||||
|
||||
|
||||
@v1_bp.route('/repositories/<path:repository>/tags/<tag>',
|
||||
methods=['PUT'])
|
||||
@v1_bp.route('/repositories/<path:repository>/tags/<tag>', methods=['PUT'])
|
||||
@process_auth
|
||||
@anon_protect
|
||||
@parse_repository_name
|
||||
|
@ -60,7 +57,7 @@ def put_tag(namespace, repository, tag):
|
|||
|
||||
if permission.can():
|
||||
docker_image_id = json.loads(request.data)
|
||||
model.create_or_update_tag(namespace, repository, tag, docker_image_id)
|
||||
model.tag.create_or_update_tag(namespace, repository, tag, docker_image_id)
|
||||
|
||||
# Store the updated tag.
|
||||
if not 'pushed_tags' in session:
|
||||
|
@ -73,8 +70,7 @@ def put_tag(namespace, repository, tag):
|
|||
abort(403)
|
||||
|
||||
|
||||
@v1_bp.route('/repositories/<path:repository>/tags/<tag>',
|
||||
methods=['DELETE'])
|
||||
@v1_bp.route('/repositories/<path:repository>/tags/<tag>', methods=['DELETE'])
|
||||
@process_auth
|
||||
@anon_protect
|
||||
@parse_repository_name
|
||||
|
@ -82,8 +78,8 @@ def delete_tag(namespace, repository, tag):
|
|||
permission = ModifyRepositoryPermission(namespace, repository)
|
||||
|
||||
if permission.can():
|
||||
model.delete_tag(namespace, repository, tag)
|
||||
model.garbage_collect_repository(namespace, repository)
|
||||
model.tag.delete_tag(namespace, repository, tag)
|
||||
model.repository.garbage_collect_repository(namespace, repository)
|
||||
|
||||
return make_response('Deleted', 200)
|
||||
|
|
@ -2,9 +2,8 @@ import logging
|
|||
|
||||
from flask import make_response, url_for, request
|
||||
|
||||
import data.model.blob
|
||||
|
||||
from app import storage
|
||||
from app import storage, app
|
||||
from data import model
|
||||
from digest import digest_tools
|
||||
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write, get_input_stream
|
||||
from auth.jwt_auth import process_jwt_auth
|
||||
|
@ -22,11 +21,11 @@ logger = logging.getLogger(__name__)
|
|||
@anon_protect
|
||||
def check_blob_existence(namespace, repo_name, digest):
|
||||
try:
|
||||
found = data.model.blob.get_blob_by_digest(digest)
|
||||
found = model.blob.get_repo_blob_by_digest(namespace, repo_name, digest)
|
||||
|
||||
# The response body must be empty for a successful HEAD request
|
||||
return make_response('')
|
||||
except data.model.blob.BlobDoesNotExist:
|
||||
except model.BlobDoesNotExist:
|
||||
abort(404)
|
||||
|
||||
|
||||
|
@ -66,7 +65,8 @@ def upload_chunk(namespace, repo_name, upload_uuid):
|
|||
if digest is not None:
|
||||
final_blob_location = digest_tools.content_path(digest)
|
||||
storage.complete_chunked_upload(upload_location, upload_uuid, final_blob_location, digest)
|
||||
data.model.blob.store_blob_record(digest, upload_location)
|
||||
model.blob.store_blob_record_and_temp_link(namespace, repo_name, digest, upload_location,
|
||||
app.config['PUSH_TEMP_TAG_EXPIRATION_SEC'])
|
||||
|
||||
response = make_response('', 201)
|
||||
response.headers['Docker-Content-Digest'] = digest
|
||||
|
|
|
@ -52,7 +52,7 @@ def generate_registry_jwt():
|
|||
|
||||
namespace, reponame = parse_namespace_repository(namespace_and_repo)
|
||||
if 'pull' in actions and 'push' in actions:
|
||||
repo = model.get_repository(namespace, reponame)
|
||||
repo = model.repository.get_repository(namespace, reponame)
|
||||
if repo:
|
||||
if not ModifyRepositoryPermission(namespace, reponame):
|
||||
abort(403)
|
||||
|
@ -60,7 +60,7 @@ def generate_registry_jwt():
|
|||
if not CreateRepositoryPermission(namespace):
|
||||
abort(403)
|
||||
logger.debug('Creating repository: %s/%s', namespace, reponame)
|
||||
model.create_repository(namespace, reponame, user)
|
||||
model.repository.create_repository(namespace, reponame, user)
|
||||
elif 'pull' in actions:
|
||||
if not ReadRepositoryPermission(namespace, reponame):
|
||||
abort(403)
|
||||
|
|
|
@ -7,8 +7,7 @@ from flask import redirect, Blueprint, abort, send_file, make_response
|
|||
from app import app, signer
|
||||
from auth.auth import process_auth
|
||||
from auth.permissions import ReadRepositoryPermission
|
||||
from data import model
|
||||
from data import database
|
||||
from data import model, database
|
||||
from endpoints.trackhelper import track_and_log
|
||||
from endpoints.decorators import anon_protect
|
||||
from storage import Storage
|
||||
|
@ -22,6 +21,7 @@ from formats.aci import ACIImage
|
|||
verbs = Blueprint('verbs', __name__)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _open_stream(formatter, namespace, repository, tag, synthetic_image_id, image_json,
|
||||
image_id_list):
|
||||
store = Storage(app)
|
||||
|
@ -29,7 +29,8 @@ def _open_stream(formatter, namespace, repository, tag, synthetic_image_id, imag
|
|||
# For performance reasons, we load the full image list here, cache it, then disconnect from
|
||||
# the database.
|
||||
with database.UseThenDisconnect(app.config):
|
||||
image_list = list(model.get_matching_repository_images(namespace, repository, image_id_list))
|
||||
image_list = list(model.image.get_matching_repository_images(namespace, repository,
|
||||
image_id_list))
|
||||
|
||||
image_list.sort(key=lambda image: image_id_list.index(image.docker_image_id))
|
||||
|
||||
|
@ -48,7 +49,7 @@ def _open_stream(formatter, namespace, repository, tag, synthetic_image_id, imag
|
|||
yield current_image_stream
|
||||
|
||||
stream = formatter.build_stream(namespace, repository, tag, synthetic_image_id, image_json,
|
||||
get_next_image, get_next_layer)
|
||||
get_next_image, get_next_layer)
|
||||
|
||||
return stream.read
|
||||
|
||||
|
@ -66,11 +67,11 @@ def _sign_sythentic_image(verb, linked_storage_uuid, queue_file):
|
|||
if not queue_file.raised_exception:
|
||||
with database.UseThenDisconnect(app.config):
|
||||
try:
|
||||
derived = model.get_storage_by_uuid(linked_storage_uuid)
|
||||
except model.InvalidImageException:
|
||||
derived = model.storage.get_storage_by_uuid(linked_storage_uuid)
|
||||
except model.storage.InvalidImageException:
|
||||
return
|
||||
|
||||
signature_entry = model.find_or_create_storage_signature(derived, signer.name)
|
||||
signature_entry = model.storage.find_or_create_storage_signature(derived, signer.name)
|
||||
signature_entry.signature = signature
|
||||
signature_entry.uploading = False
|
||||
signature_entry.save()
|
||||
|
@ -83,7 +84,7 @@ def _write_synthetic_image_to_storage(verb, linked_storage_uuid, linked_location
|
|||
logger.debug('Exception when building %s image %s: %s', verb, linked_storage_uuid, ex)
|
||||
|
||||
with database.UseThenDisconnect(app.config):
|
||||
model.delete_derived_storage_by_uuid(linked_storage_uuid)
|
||||
model.storage.delete_derived_storage_by_uuid(linked_storage_uuid)
|
||||
|
||||
queue_file.add_exception_handler(handle_exception)
|
||||
|
||||
|
@ -95,7 +96,7 @@ def _write_synthetic_image_to_storage(verb, linked_storage_uuid, linked_location
|
|||
# Setup the database (since this is a new process) and then disconnect immediately
|
||||
# once the operation completes.
|
||||
with database.UseThenDisconnect(app.config):
|
||||
done_uploading = model.get_storage_by_uuid(linked_storage_uuid)
|
||||
done_uploading = model.storage.get_storage_by_uuid(linked_storage_uuid)
|
||||
done_uploading.uploading = False
|
||||
done_uploading.save()
|
||||
|
||||
|
@ -103,17 +104,17 @@ def _write_synthetic_image_to_storage(verb, linked_storage_uuid, linked_location
|
|||
def _verify_repo_verb(store, namespace, repository, tag, verb, checker=None):
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
||||
if not permission.can() and not model.repository_is_public(namespace, repository):
|
||||
if not permission.can() and not model.repository.repository_is_public(namespace, repository):
|
||||
abort(403)
|
||||
|
||||
# Lookup the requested tag.
|
||||
try:
|
||||
tag_image = model.get_tag_image(namespace, repository, tag)
|
||||
tag_image = model.tag.get_tag_image(namespace, repository, tag)
|
||||
except model.DataModelException:
|
||||
abort(404)
|
||||
|
||||
# Lookup the tag's image and storage.
|
||||
repo_image = model.get_repo_image_extended(namespace, repository, tag_image.docker_image_id)
|
||||
repo_image = model.image.get_repo_image_extended(namespace, repository, tag_image.docker_image_id)
|
||||
if not repo_image:
|
||||
abort(404)
|
||||
|
||||
|
@ -139,7 +140,7 @@ def _repo_verb_signature(namespace, repository, tag, verb, checker=None, **kwarg
|
|||
(repo_image, tag_image, image_json) = result
|
||||
|
||||
# Lookup the derived image storage for the verb.
|
||||
derived = model.find_derived_storage(repo_image.storage, verb)
|
||||
derived = model.storage.find_derived_storage(repo_image.storage, verb)
|
||||
if derived is None or derived.uploading:
|
||||
return make_response('', 202)
|
||||
|
||||
|
@ -148,7 +149,7 @@ def _repo_verb_signature(namespace, repository, tag, verb, checker=None, **kwarg
|
|||
abort(404)
|
||||
|
||||
# Lookup the signature for the verb.
|
||||
signature_entry = model.lookup_storage_signature(derived, signer.name)
|
||||
signature_entry = model.storage.lookup_storage_signature(derived, signer.name)
|
||||
if signature_entry is None:
|
||||
abort(404)
|
||||
|
||||
|
@ -166,8 +167,8 @@ def _repo_verb(namespace, repository, tag, verb, formatter, sign=False, checker=
|
|||
track_and_log('repo_verb', repo_image.repository, tag=tag, verb=verb, **kwargs)
|
||||
|
||||
# Lookup/create the derived image storage for the verb.
|
||||
derived = model.find_or_create_derived_storage(repo_image.storage, verb,
|
||||
store.preferred_locations[0])
|
||||
derived = model.storage.find_or_create_derived_storage(repo_image.storage, verb,
|
||||
store.preferred_locations[0])
|
||||
|
||||
if not derived.uploading:
|
||||
logger.debug('Derived %s image %s exists in storage', verb, derived.uuid)
|
||||
|
@ -206,8 +207,8 @@ def _repo_verb(namespace, repository, tag, verb, formatter, sign=False, checker=
|
|||
# and send the results to the client and storage.
|
||||
args = (formatter, namespace, repository, tag, synthetic_image_id, image_json, full_image_list)
|
||||
queue_process = QueueProcess(_open_stream,
|
||||
8 * 1024, 10 * 1024 * 1024, # 8K/10M chunk/max
|
||||
args, finished=_cleanup)
|
||||
8 * 1024, 10 * 1024 * 1024, # 8K/10M chunk/max
|
||||
args, finished=_cleanup)
|
||||
|
||||
client_queue_file = QueueFile(queue_process.create_queue(), 'client')
|
||||
storage_queue_file = QueueFile(queue_process.create_queue(), 'storage')
|
||||
|
|
|
@ -9,7 +9,6 @@ from health.healthcheck import get_healthchecker
|
|||
|
||||
from data import model
|
||||
from data.database import db
|
||||
from data.model.oauth import DatabaseAuthorizationProvider
|
||||
from app import app, billing as stripe, build_logs, avatar, signer, log_archive
|
||||
from auth.auth import require_session_login, process_oauth
|
||||
from auth.permissions import (AdministerOrganizationPermission, ReadRepositoryPermission,
|
||||
|
@ -281,24 +280,24 @@ def robots():
|
|||
@route_show_if(features.BUILD_SUPPORT)
|
||||
@require_session_login
|
||||
def buildlogs(build_uuid):
|
||||
build = model.get_repository_build(build_uuid)
|
||||
if not build:
|
||||
found_build = model.build.get_repository_build(build_uuid)
|
||||
if not found_build:
|
||||
abort(403)
|
||||
|
||||
repo = build.repository
|
||||
repo = found_build.repository
|
||||
if not ModifyRepositoryPermission(repo.namespace_user.username, repo.name).can():
|
||||
abort(403)
|
||||
|
||||
# If the logs have been archived, just return a URL of the completed archive
|
||||
if build.logs_archived:
|
||||
return redirect(log_archive.get_file_url(build.uuid))
|
||||
if found_build.logs_archived:
|
||||
return redirect(log_archive.get_file_url(found_build.uuid))
|
||||
|
||||
_, logs = build_logs.get_log_entries(build.uuid, 0)
|
||||
_, logs = build_logs.get_log_entries(found_build.uuid, 0)
|
||||
response = jsonify({
|
||||
'logs': [log for log in logs]
|
||||
})
|
||||
|
||||
response.headers["Content-Disposition"] = "attachment;filename=" + build.uuid + ".json"
|
||||
response.headers["Content-Disposition"] = "attachment;filename=" + found_build.uuid + ".json"
|
||||
return response
|
||||
|
||||
|
||||
|
@ -314,7 +313,7 @@ def receipt():
|
|||
if invoice_id:
|
||||
invoice = stripe.Invoice.retrieve(invoice_id)
|
||||
if invoice:
|
||||
user_or_org = model.get_user_or_org_by_customer_id(invoice.customer)
|
||||
user_or_org = model.user.get_user_or_org_by_customer_id(invoice.customer)
|
||||
|
||||
if user_or_org:
|
||||
if user_or_org.organization:
|
||||
|
@ -341,8 +340,8 @@ def confirm_repo_email():
|
|||
record = None
|
||||
|
||||
try:
|
||||
record = model.confirm_email_authorization_for_repo(code)
|
||||
except model.DataModelException as ex:
|
||||
record = model.repository.confirm_email_authorization_for_repo(code)
|
||||
except DataModelException as ex:
|
||||
return render_page_template('confirmerror.html', error_message=ex.message)
|
||||
|
||||
message = """
|
||||
|
@ -363,8 +362,8 @@ def confirm_email():
|
|||
new_email = None
|
||||
|
||||
try:
|
||||
user, new_email, old_email = model.confirm_user_email(code)
|
||||
except model.DataModelException as ex:
|
||||
user, new_email, old_email = model.user.confirm_user_email(code)
|
||||
except DataModelException as ex:
|
||||
return render_page_template('confirmerror.html', error_message=ex.message)
|
||||
|
||||
if new_email:
|
||||
|
@ -379,7 +378,7 @@ def confirm_email():
|
|||
@web.route('/recovery', methods=['GET'])
|
||||
def confirm_recovery():
|
||||
code = request.values['code']
|
||||
user = model.validate_reset_code(code)
|
||||
user = model.user.validate_reset_code(code)
|
||||
|
||||
if user:
|
||||
common_login(user)
|
||||
|
@ -394,22 +393,22 @@ def confirm_recovery():
|
|||
@anon_protect
|
||||
def build_status_badge(namespace, repository):
|
||||
token = request.args.get('token', None)
|
||||
is_public = model.repository_is_public(namespace, repository)
|
||||
is_public = model.repository.repository_is_public(namespace, repository)
|
||||
if not is_public:
|
||||
repo = model.get_repository(namespace, repository)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
if not repo or token != repo.badge_token:
|
||||
abort(404)
|
||||
|
||||
# Lookup the tags for the repository.
|
||||
tags = model.list_repository_tags(namespace, repository)
|
||||
tags = model.tag.list_repository_tags(namespace, repository)
|
||||
is_empty = len(list(tags)) == 0
|
||||
build = model.get_recent_repository_build(namespace, repository)
|
||||
recent_build = model.build.get_recent_repository_build(namespace, repository)
|
||||
|
||||
if not is_empty and (not build or build.phase == 'complete'):
|
||||
if not is_empty and (not recent_build or recent_build.phase == 'complete'):
|
||||
status_name = 'ready'
|
||||
elif build and build.phase == 'error':
|
||||
elif recent_build and recent_build.phase == 'error':
|
||||
status_name = 'failed'
|
||||
elif build and build.phase != 'complete':
|
||||
elif recent_build and recent_build.phase != 'complete':
|
||||
status_name = 'building'
|
||||
else:
|
||||
status_name = 'none'
|
||||
|
@ -419,7 +418,7 @@ def build_status_badge(namespace, repository):
|
|||
return response
|
||||
|
||||
|
||||
class FlaskAuthorizationProvider(DatabaseAuthorizationProvider):
|
||||
class FlaskAuthorizationProvider(model.oauth.DatabaseAuthorizationProvider):
|
||||
def get_authorized_user(self):
|
||||
return current_user.db_user()
|
||||
|
||||
|
@ -579,14 +578,13 @@ def download_logs_archive():
|
|||
def attach_bitbucket_trigger(namespace, repository_name):
|
||||
permission = AdministerRepositoryPermission(namespace, repository_name)
|
||||
if permission.can():
|
||||
repo = model.get_repository(namespace, repository_name)
|
||||
repo = model.repository.get_repository(namespace, repository_name)
|
||||
if not repo:
|
||||
msg = 'Invalid repository: %s/%s' % (namespace, repository_name)
|
||||
abort(404, message=msg)
|
||||
|
||||
trigger = model.create_build_trigger(repo, BitbucketBuildTrigger.service_name(),
|
||||
None,
|
||||
current_user.db_user())
|
||||
trigger = model.build.create_build_trigger(repo, BitbucketBuildTrigger.service_name(), None,
|
||||
current_user.db_user())
|
||||
|
||||
try:
|
||||
oauth_info = BuildTriggerHandler.get_handler(trigger).get_oauth_url()
|
||||
|
@ -596,7 +594,7 @@ def attach_bitbucket_trigger(namespace, repository_name):
|
|||
}
|
||||
|
||||
access_token_secret = oauth_info['access_token_secret']
|
||||
model.update_build_trigger(trigger, config, auth_token=access_token_secret)
|
||||
model.build.update_build_trigger(trigger, config, auth_token=access_token_secret)
|
||||
|
||||
return redirect(oauth_info['url'])
|
||||
except TriggerProviderException:
|
||||
|
@ -612,13 +610,13 @@ def attach_bitbucket_trigger(namespace, repository_name):
|
|||
def attach_custom_build_trigger(namespace, repository_name):
|
||||
permission = AdministerRepositoryPermission(namespace, repository_name)
|
||||
if permission.can():
|
||||
repo = model.get_repository(namespace, repository_name)
|
||||
repo = model.repository.get_repository(namespace, repository_name)
|
||||
if not repo:
|
||||
msg = 'Invalid repository: %s/%s' % (namespace, repository_name)
|
||||
abort(404, message=msg)
|
||||
|
||||
trigger = model.create_build_trigger(repo, CustomBuildTrigger.service_name(),
|
||||
None, current_user.db_user())
|
||||
trigger = model.build.create_build_trigger(repo, CustomBuildTrigger.service_name(),
|
||||
None, current_user.db_user())
|
||||
|
||||
repo_path = '%s/%s' % (namespace, repository_name)
|
||||
full_url = '%s%s%s' % (url_for('web.repository', path=repo_path), '?tab=builds&newtrigger=',
|
||||
|
@ -634,16 +632,16 @@ def attach_custom_build_trigger(namespace, repository_name):
|
|||
@process_oauth
|
||||
@parse_repository_name_and_tag
|
||||
@anon_protect
|
||||
def redirect_to_repository(namespace, reponame, tag):
|
||||
def redirect_to_repository(namespace, reponame, tag_name):
|
||||
permission = ReadRepositoryPermission(namespace, reponame)
|
||||
is_public = model.repository_is_public(namespace, reponame)
|
||||
is_public = model.repository.repository_is_public(namespace, reponame)
|
||||
|
||||
if request.args.get('ac-discovery', 0) == 1:
|
||||
return index('')
|
||||
|
||||
if permission.can() or is_public:
|
||||
repository_name = '/'.join([namespace, reponame])
|
||||
return redirect(url_for('web.repository', path=repository_name, tag=tag))
|
||||
return redirect(url_for('web.repository', path=repository_name, tag=tag_name))
|
||||
|
||||
abort(404)
|
||||
|
||||
|
@ -653,7 +651,7 @@ def redirect_to_repository(namespace, reponame, tag):
|
|||
@process_oauth
|
||||
@anon_protect
|
||||
def redirect_to_namespace(namespace):
|
||||
user_or_org = model.get_user_or_org(namespace)
|
||||
user_or_org = model.user.get_user_or_org(namespace)
|
||||
if not user_or_org:
|
||||
abort(404)
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ def stripe_webhook():
|
|||
logger.debug('Stripe webhook call: %s', request_data)
|
||||
|
||||
customer_id = request_data.get('data', {}).get('object', {}).get('customer', None)
|
||||
user = model.get_user_or_org_by_customer_id(customer_id) if customer_id else None
|
||||
user = model.user.get_user_or_org_by_customer_id(customer_id) if customer_id else None
|
||||
|
||||
event_type = request_data['type'] if 'type' in request_data else None
|
||||
if event_type == 'charge.succeeded':
|
||||
|
@ -73,7 +73,7 @@ def build_trigger_webhook(trigger_uuid, **kwargs):
|
|||
logger.debug('Webhook received with uuid %s', trigger_uuid)
|
||||
|
||||
try:
|
||||
trigger = model.get_build_trigger(trigger_uuid)
|
||||
trigger = model.build.get_build_trigger(trigger_uuid)
|
||||
except model.InvalidBuildTriggerException:
|
||||
# It is ok to return 404 here, since letting an attacker know that a trigger UUID is valid
|
||||
# doesn't leak anything
|
||||
|
@ -101,8 +101,8 @@ def build_trigger_webhook(trigger_uuid, **kwargs):
|
|||
# The payload was malformed
|
||||
abort(400, message=ipe.message)
|
||||
|
||||
pull_robot_name = model.get_pull_robot_name(trigger)
|
||||
repo = model.get_repository(namespace, repository)
|
||||
pull_robot_name = model.build.get_pull_robot_name(trigger)
|
||||
repo = model.repository.get_repository(namespace, repository)
|
||||
start_build(repo, prepared, pull_robot_name=pull_robot_name)
|
||||
|
||||
return make_response('Okay')
|
||||
|
|
Reference in a new issue