Accidental refactor, split out legacy.py into separate sumodules and update all call sites.

This commit is contained in:
Jake Moshenko 2015-07-15 17:25:41 -04:00
parent 2109d24483
commit 3efaa255e8
92 changed files with 4458 additions and 4269 deletions

View file

@ -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):

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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

View file

@ -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()

View file

@ -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)

View file

@ -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)

View file

@ -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 {}

View file

@ -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

View file

@ -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()

View file

@ -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))

View file

@ -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 = {

View file

@ -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()

View file

@ -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)

View file

@ -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,

View file

@ -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

View file

@ -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()

View file

@ -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)