diff --git a/endpoints/api/repository.py b/endpoints/api/repository.py index 851bd644d..6075811dd 100644 --- a/endpoints/api/repository.py +++ b/endpoints/api/repository.py @@ -18,7 +18,7 @@ from endpoints.api import (truthy_bool, format_date, nickname, log_action, valid request_error, require_scope, Unauthorized, NotFound, InvalidRequest, path_param, ExceedsLicenseException) from endpoints.api.billing import lookup_allowed_private_repos, get_namespace_plan -from endpoints.common import check_repository_usage +from endpoints.api.subscribe import check_repository_usage from auth.permissions import (ModifyRepositoryPermission, AdministerRepositoryPermission, CreateRepositoryPermission) diff --git a/endpoints/api/subscribe.py b/endpoints/api/subscribe.py index 026f10406..e66fe48c8 100644 --- a/endpoints/api/subscribe.py +++ b/endpoints/api/subscribe.py @@ -5,7 +5,6 @@ import stripe from app import billing from endpoints.api import request_error, log_action, NotFound -from endpoints.common import check_repository_usage from data import model from data.billing import PLANS @@ -15,6 +14,20 @@ import features logger = logging.getLogger(__name__) +def check_repository_usage(user_or_org, plan_found): + private_repos = model.user.get_private_repo_count(user_or_org.username) + if plan_found is None: + repos_allowed = 0 + else: + repos_allowed = plan_found['privateRepos'] + + if private_repos > repos_allowed: + model.notification.create_unique_notification('over_private_usage', user_or_org, + {'namespace': user_or_org.username}) + else: + model.notification.delete_notifications_by_kind(user_or_org, 'over_private_usage') + + def carderror_response(exc): return {'carderror': exc.message}, 402 diff --git a/endpoints/common.py b/endpoints/common.py index 894354006..371c66384 100644 --- a/endpoints/common.py +++ b/endpoints/common.py @@ -14,12 +14,10 @@ from flask.ext.principal import identity_changed from random import SystemRandom from cachetools import lru_cache -from data import model from app import app, oauth_apps, LoginWrappedDBUser from auth.permissions import QuayDeferredPermissionUser from auth import scopes -from endpoints.api.discovery import swagger_route_data from werkzeug.routing import BaseConverter from functools import wraps from config import frontend_visible_config @@ -79,15 +77,6 @@ def route_hide_if(value): return decorator -def get_route_data(): - global route_data - if route_data: - return route_data - - route_data = swagger_route_data(include_internal=True, compact=True) - return route_data - - def truthy_param(param): return param not in {False, 'false', 'False', '0', 'FALSE', '', 'null'} @@ -139,7 +128,7 @@ def _get_version_number(): except IOError: return '' -def render_page_template(name, **kwargs): +def render_page_template(name, route_data=None, **kwargs): debugging = app.config.get('DEBUGGING', False) if debugging: # If DEBUGGING is enabled, then we load the full set of individual JS and CSS files @@ -187,7 +176,7 @@ def render_page_template(name, **kwargs): version_number = ' - ' + _get_version_number() resp = make_response(render_template(name, - route_data=json.dumps(get_route_data()), + route_data=json.dumps(route_data), external_styles=external_styles, external_scripts=external_scripts, main_styles=add_cachebusters(main_styles), @@ -214,17 +203,3 @@ def render_page_template(name, **kwargs): resp.headers['X-FRAME-OPTIONS'] = 'DENY' return resp - -def check_repository_usage(user_or_org, plan_found): - private_repos = model.user.get_private_repo_count(user_or_org.username) - if plan_found is None: - repos_allowed = 0 - else: - repos_allowed = plan_found['privateRepos'] - - if private_repos > repos_allowed: - model.notification.create_unique_notification('over_private_usage', user_or_org, - {'namespace': user_or_org.username}) - else: - model.notification.delete_notifications_by_kind(user_or_org, 'over_private_usage') - diff --git a/endpoints/oauthlogin.py b/endpoints/oauthlogin.py index 665801a6d..3ca75574b 100644 --- a/endpoints/oauthlogin.py +++ b/endpoints/oauthlogin.py @@ -4,7 +4,8 @@ import requests from flask import request, redirect, url_for, Blueprint from flask.ext.login import current_user -from endpoints.common import render_page_template, common_login, route_show_if +from endpoints.common import common_login, route_show_if +from endpoints.web import render_page_template_with_routedata from app import app, analytics, get_app_url, github_login, google_login, dex_login from data import model from util.names import parse_repository_name @@ -22,10 +23,12 @@ oauthlogin = Blueprint('oauthlogin', __name__) def render_ologin_error(service_name, error_message='Could not load user data. The token may have expired.'): - return render_page_template('ologinerror.html', service_name=service_name, - error_message=error_message, - service_url=get_app_url(), - user_creation=features.USER_CREATION and features.DIRECT_LOGIN) + user_creation = features.USER_CREATION and features.DIRECT_LOGIN + return render_page_template_with_routedata('ologinerror.html', + service_name=service_name, + error_message=error_message, + service_url=get_app_url(), + user_creation=user_creation) def get_user(service, token): diff --git a/endpoints/web.py b/endpoints/web.py index ab6611237..d89d72f70 100644 --- a/endpoints/web.py +++ b/endpoints/web.py @@ -24,6 +24,7 @@ from buildtrigger.customhandler import CustomBuildTrigger from buildtrigger.triggerutil import TriggerProviderException from data import model from data.database import db +from endpoints.api.discovery import swagger_route_data from endpoints.common import common_login, render_page_template, route_show_if, param_required from endpoints.csrf import csrf_protect, generate_csrf_token, verify_csrf from endpoints.decorators import anon_protect, anon_allowed @@ -38,6 +39,20 @@ from util.useremails import send_email_changed +_route_data = None + +def _get_route_data(): + global _route_data + if _route_data: + return _route_data + + _route_data = swagger_route_data(include_internal=True, compact=True) + return _route_data + + +def render_page_template_with_routedata(name, *args, **kwargs): + return render_page_template(name, _get_route_data(), *args, **kwargs) + # Capture the unverified SSL errors. logger = logging.getLogger(__name__) logging.captureWarnings(True) @@ -51,17 +66,17 @@ JWT_ISSUER = app.config.get('JWT_AUTH_TOKEN_ISSUER') @web.route('/', methods=['GET'], defaults={'path': ''}) @no_cache def index(path, **kwargs): - return render_page_template('index.html', **kwargs) + return render_page_template_with_routedata('index.html', **kwargs) @web.route('/500', methods=['GET']) def internal_error_display(): - return render_page_template('500.html') + return render_page_template_with_routedata('500.html') @web.errorhandler(404) @web.route('/404', methods=['GET']) def not_found_error_display(e = None): - resp = render_page_template('404.html') + resp = render_page_template_with_routedata('404.html') resp.status_code = 404 return resp @@ -265,19 +280,19 @@ def dbrevision_health(): @web.route('/tos', methods=['GET']) @no_cache def tos(): - return render_page_template('tos.html') + return render_page_template_with_routedata('tos.html') @web.route('/disclaimer', methods=['GET']) @no_cache def disclaimer(): - return render_page_template('disclaimer.html') + return render_page_template_with_routedata('disclaimer.html') @web.route('/privacy', methods=['GET']) @no_cache def privacy(): - return render_page_template('privacy.html') + return render_page_template_with_routedata('privacy.html') @web.route('/robots.txt', methods=['GET']) @@ -352,7 +367,7 @@ def confirm_repo_email(): try: record = model.repository.confirm_email_authorization_for_repo(code) except model.DataModelException as ex: - return render_page_template('confirmerror.html', error_message=ex.message) + return render_page_template_with_routedata('confirmerror.html', error_message=ex.message) message = """ Your E-mail address has been authorized to receive notifications for repository @@ -361,7 +376,7 @@ def confirm_repo_email(): record.repository.namespace_user.username, record.repository.name, record.repository.namespace_user.username, record.repository.name) - return render_page_template('message.html', message=message) + return render_page_template_with_routedata('message.html', message=message) @web.route('/confirm', methods=['GET']) @@ -375,7 +390,7 @@ def confirm_email(): try: user, new_email, old_email = model.user.confirm_user_email(code) except model.DataModelException as ex: - return render_page_template('confirmerror.html', error_message=ex.message) + return render_page_template_with_routedata('confirmerror.html', error_message=ex.message) if new_email: send_email_changed(user.username, old_email, new_email) @@ -467,9 +482,9 @@ def oauth_local_handler(): return if not request.args.get('scope'): - return render_page_template("message.html", message="Authorization canceled") + return render_page_template_with_routedata("message.html", message="Authorization canceled") else: - return render_page_template("generatedtoken.html") + return render_page_template_with_routedata("generatedtoken.html") @web.route('/oauth/denyapp', methods=['POST']) @@ -533,12 +548,12 @@ def request_authorization_code(): # Show the authorization page. has_dangerous_scopes = any([check_scope['dangerous'] for check_scope in scope_info]) - return render_page_template('oauthorize.html', scopes=scope_info, - has_dangerous_scopes=has_dangerous_scopes, - application=oauth_app_view, - enumerate=enumerate, client_id=client_id, - redirect_uri=redirect_uri, scope=scope, - csrf_token_val=generate_csrf_token()) + return render_page_template_with_routedata('oauthorize.html', scopes=scope_info, + has_dangerous_scopes=has_dangerous_scopes, + application=oauth_app_view, + enumerate=enumerate, client_id=client_id, + redirect_uri=redirect_uri, scope=scope, + csrf_token_val=generate_csrf_token()) if response_type == 'token': return provider.get_token_response(response_type, client_id, redirect_uri, scope=scope) diff --git a/requirements-nover.txt b/requirements-nover.txt index eaf0ced3a..d6f8b2ac9 100644 --- a/requirements-nover.txt +++ b/requirements-nover.txt @@ -59,3 +59,4 @@ jsonpath-rw bintrees redlock semantic-version +bencode \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index d6323dc2b..b3bec6a11 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ APScheduler==3.0.3 autobahn==0.9.3-3 Babel==1.3 beautifulsoup4==4.4.0 +bencode==1.0 bintrees==2.0.3 blinker==1.3 boto==2.38.0 diff --git a/util/migrate/backfill_v1_metadata.py b/util/migrate/backfill_v1_metadata.py index e9de7e9a2..20680f077 100644 --- a/util/migrate/backfill_v1_metadata.py +++ b/util/migrate/backfill_v1_metadata.py @@ -56,7 +56,7 @@ class ImageStoragePlacement(BaseModel): def image_json_path(storage_uuid): - base_path = storage.image_path(storage_uuid) + base_path = storage._image_path(storage_uuid) return '{0}json'.format(base_path)