Merge branch 'master' into touchdown
Conflicts: static/js/app.js static/partials/organizations.html test/data/test.db
This commit is contained in:
commit
c630d7e948
65 changed files with 1843 additions and 273 deletions
|
@ -66,6 +66,10 @@ class Unauthorized(ApiException):
|
|||
ApiException.__init__(self, 'insufficient_scope', 403, 'Unauthorized', payload)
|
||||
|
||||
|
||||
class ExceedsLicenseException(ApiException):
|
||||
def __init__(self, payload=None):
|
||||
ApiException.__init__(self, None, 402, 'Payment Required', payload)
|
||||
|
||||
|
||||
class NotFound(ApiException):
|
||||
def __init__(self, payload=None):
|
||||
|
@ -275,6 +279,10 @@ def request_error(exception=None, **kwargs):
|
|||
raise InvalidRequest(message, data)
|
||||
|
||||
|
||||
def license_error(exception=None):
|
||||
raise ExceedsLicenseException()
|
||||
|
||||
|
||||
def log_action(kind, user_or_orgname, metadata=None, repo=None):
|
||||
if not metadata:
|
||||
metadata = {}
|
||||
|
|
|
@ -36,7 +36,9 @@ def get_card(user):
|
|||
card_info = {
|
||||
'owner': default_card.name,
|
||||
'type': default_card.type,
|
||||
'last4': default_card.last4
|
||||
'last4': default_card.last4,
|
||||
'exp_month': default_card.exp_month,
|
||||
'exp_year': default_card.exp_year
|
||||
}
|
||||
|
||||
return {'card': card_info}
|
||||
|
|
|
@ -54,7 +54,7 @@ class SeatUsage(ApiResource):
|
|||
if SuperUserPermission().can():
|
||||
return {
|
||||
'count': model.get_active_user_count(),
|
||||
'allowed': app.config.get('LICENSE_SEAT_COUNT', 0)
|
||||
'allowed': app.config.get('LICENSE_USER_LIMIT', 0)
|
||||
}
|
||||
|
||||
abort(403)
|
||||
|
|
|
@ -5,10 +5,10 @@ from flask import request
|
|||
from flask.ext.login import logout_user
|
||||
from flask.ext.principal import identity_changed, AnonymousIdentity
|
||||
|
||||
from app import app, billing as stripe
|
||||
from app import app, billing as stripe, authentication
|
||||
from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error,
|
||||
log_action, internal_only, NotFound, require_user_admin,
|
||||
InvalidToken, require_scope, format_date, hide_if, show_if)
|
||||
InvalidToken, require_scope, format_date, hide_if, show_if, license_error)
|
||||
from endpoints.api.subscribe import subscribe
|
||||
from endpoints.common import common_login
|
||||
from data import model
|
||||
|
@ -18,8 +18,7 @@ from auth.permissions import (AdministerOrganizationPermission, CreateRepository
|
|||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from util.gravatar import compute_hash
|
||||
from util.email import (send_confirmation_email, send_recovery_email,
|
||||
send_change_email)
|
||||
from util.useremails import (send_confirmation_email, send_recovery_email, send_change_email)
|
||||
|
||||
import features
|
||||
|
||||
|
@ -193,6 +192,8 @@ class User(ApiResource):
|
|||
code = model.create_confirm_email_code(new_user)
|
||||
send_confirmation_email(new_user.username, new_user.email, code.code)
|
||||
return 'Created', 201
|
||||
except model.TooManyUsersException as ex:
|
||||
raise license_error(exception=ex)
|
||||
except model.DataModelException as ex:
|
||||
raise request_error(exception=ex)
|
||||
|
||||
|
@ -227,7 +228,12 @@ def conduct_signin(username_or_email, password):
|
|||
needs_email_verification = False
|
||||
invalid_credentials = False
|
||||
|
||||
verified = model.verify_user(username_or_email, password)
|
||||
verified = None
|
||||
try:
|
||||
verified = authentication.verify_user(username_or_email, password)
|
||||
except model.TooManyUsersException as ex:
|
||||
raise license_error(exception=ex)
|
||||
|
||||
if verified:
|
||||
if common_login(verified):
|
||||
return {'success': True}
|
||||
|
@ -245,6 +251,7 @@ def conduct_signin(username_or_email, password):
|
|||
|
||||
@resource('/v1/user/convert')
|
||||
@internal_only
|
||||
@show_if(app.config['AUTHENTICATION_TYPE'] == 'Database')
|
||||
class ConvertToOrganization(ApiResource):
|
||||
""" Operations for converting a user to an organization. """
|
||||
schemas = {
|
||||
|
@ -289,7 +296,7 @@ class ConvertToOrganization(ApiResource):
|
|||
|
||||
# Ensure that the sign in credentials work.
|
||||
admin_password = convert_data['adminPassword']
|
||||
if not model.verify_user(admin_username, admin_password):
|
||||
if not authentication.verify_user(admin_username, admin_password):
|
||||
raise request_error(reason='invaliduser',
|
||||
message='The admin user credentials are not valid')
|
||||
|
||||
|
|
|
@ -35,7 +35,11 @@ def exchange_github_code_for_token(code, for_login=True):
|
|||
get_access_token = client.post(app.config['GITHUB_TOKEN_URL'],
|
||||
params=payload, headers=headers)
|
||||
|
||||
token = get_access_token.json()['access_token']
|
||||
json_data = get_access_token.json()
|
||||
if not json_data:
|
||||
return ''
|
||||
|
||||
token = json_data.get('access_token', '')
|
||||
return token
|
||||
|
||||
|
||||
|
@ -83,7 +87,7 @@ def github_oauth_callback():
|
|||
# try to create the user
|
||||
try:
|
||||
to_login = model.create_federated_user(username, found_email, 'github',
|
||||
github_id)
|
||||
github_id, set_password_notification=True)
|
||||
|
||||
# Success, tell analytics
|
||||
analytics.track(to_login.username, 'register', {'service': 'github'})
|
||||
|
@ -115,6 +119,7 @@ def github_oauth_attach():
|
|||
|
||||
|
||||
@callback.route('/github/callback/trigger/<path:repository>', methods=['GET'])
|
||||
@route_show_if(features.GITHUB_BUILD)
|
||||
@require_session_login
|
||||
@parse_repository_name
|
||||
def attach_github_build_trigger(namespace, repository):
|
||||
|
|
|
@ -9,14 +9,14 @@ from flask.ext.principal import identity_changed
|
|||
from random import SystemRandom
|
||||
|
||||
from data import model
|
||||
from data.queue import dockerfile_build_queue
|
||||
from app import app, login_manager
|
||||
from app import app, login_manager, dockerfile_build_queue
|
||||
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 getFrontendVisibleConfig
|
||||
from external_libraries import get_external_javascript, get_external_css
|
||||
|
||||
import features
|
||||
|
||||
|
@ -147,7 +147,12 @@ def render_page_template(name, **kwargs):
|
|||
main_scripts = ['dist/quay-frontend.min.js']
|
||||
cache_buster = random_string()
|
||||
|
||||
external_styles = get_external_css(local=not app.config.get('USE_CDN', True))
|
||||
external_scripts = get_external_javascript(local=not app.config.get('USE_CDN', True))
|
||||
|
||||
resp = make_response(render_template(name, route_data=json.dumps(get_route_data()),
|
||||
external_styles=external_styles,
|
||||
external_scripts=external_scripts,
|
||||
main_styles=main_styles,
|
||||
library_styles=library_styles,
|
||||
main_scripts=main_scripts,
|
||||
|
@ -159,6 +164,7 @@ def render_page_template(name, **kwargs):
|
|||
is_debug=str(app.config.get('DEBUGGING', False)).lower(),
|
||||
show_chat=features.OLARK_CHAT,
|
||||
cache_buster=cache_buster,
|
||||
has_billing=features.BILLING,
|
||||
**kwargs))
|
||||
|
||||
resp.headers['X-FRAME-OPTIONS'] = 'DENY'
|
||||
|
|
|
@ -8,12 +8,11 @@ from collections import OrderedDict
|
|||
|
||||
from data import model
|
||||
from data.model import oauth
|
||||
from data.queue import webhook_queue
|
||||
from app import analytics, app
|
||||
from app import analytics, app, webhook_queue, authentication, userevents
|
||||
from auth.auth import process_auth
|
||||
from auth.auth_context import get_authenticated_user, get_validated_token, get_validated_oauth_token
|
||||
from util.names import parse_repository_name
|
||||
from util.email import send_confirmation_email
|
||||
from util.useremails import send_confirmation_email
|
||||
from auth.permissions import (ModifyRepositoryPermission, UserAdminPermission,
|
||||
ReadRepositoryPermission, CreateRepositoryPermission)
|
||||
|
||||
|
@ -95,18 +94,17 @@ def create_user():
|
|||
abort(400, 'Invalid robot account or password.',
|
||||
issue='robot-login-failure')
|
||||
|
||||
existing_user = model.get_user(username)
|
||||
if existing_user:
|
||||
verified = model.verify_user(username, password)
|
||||
if authentication.user_exists(username):
|
||||
verified = authentication.verify_user(username, password)
|
||||
if verified:
|
||||
# Mark that the user was logged in.
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event = userevents.get_event(username)
|
||||
event.publish_event_data('docker-cli', {'action': 'login'})
|
||||
|
||||
return success
|
||||
else:
|
||||
# Mark that the login failed.
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event = userevents.get_event(username)
|
||||
event.publish_event_data('docker-cli', {'action': 'loginfailure'})
|
||||
|
||||
abort(400, 'Invalid password.', issue='login-failure')
|
||||
|
@ -114,7 +112,12 @@ def create_user():
|
|||
else:
|
||||
# New user case
|
||||
profile.debug('Creating user')
|
||||
new_user = model.create_user(username, password, user_data['email'])
|
||||
new_user = None
|
||||
|
||||
try:
|
||||
new_user = model.create_user(username, password, user_data['email'])
|
||||
except model.TooManyUsersException as ex:
|
||||
abort(402, 'Seat limit has been reached for this license', issue='seat-limit')
|
||||
|
||||
profile.debug('Creating email code for user')
|
||||
code = model.create_confirm_email_code(new_user)
|
||||
|
@ -260,7 +263,7 @@ def create_repository(namespace, repository):
|
|||
'namespace': namespace
|
||||
}
|
||||
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event = userevents.get_event(username)
|
||||
event.publish_event_data('docker-cli', user_data)
|
||||
|
||||
elif get_validated_token():
|
||||
|
@ -308,7 +311,7 @@ def update_images(namespace, repository):
|
|||
'namespace': namespace
|
||||
}
|
||||
|
||||
event = app.config['USER_EVENTS'].get_event(username)
|
||||
event = userevents.get_event(username)
|
||||
event.publish_event_data('docker-cli', user_data)
|
||||
|
||||
profile.debug('GCing repository')
|
||||
|
|
|
@ -3,8 +3,8 @@ import json
|
|||
|
||||
from flask import request, Blueprint, abort, Response
|
||||
from flask.ext.login import current_user
|
||||
from data import userevent
|
||||
from auth.auth import require_session_login
|
||||
from app import userevents
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -41,7 +41,7 @@ def index():
|
|||
@realtime.route("/user/test")
|
||||
@require_session_login
|
||||
def user_test():
|
||||
evt = userevent.UserEvent('logs.quay.io', current_user.db_user().username)
|
||||
evt = userevents.get_event(current_user.db_user().username)
|
||||
evt.publish_event_data('test', {'foo': 2})
|
||||
return 'OK'
|
||||
|
||||
|
@ -58,5 +58,5 @@ def user_subscribe():
|
|||
if not events:
|
||||
abort(404)
|
||||
|
||||
listener = userevent.UserEventListener('logs.quay.io', current_user.db_user().username, events)
|
||||
listener = userevents.get_listener(current_user.db_user().username, events)
|
||||
return Response(wrapper(listener), mimetype="text/event-stream")
|
||||
|
|
|
@ -7,9 +7,7 @@ from functools import wraps
|
|||
from datetime import datetime
|
||||
from time import time
|
||||
|
||||
from data.queue import image_diff_queue
|
||||
|
||||
from app import storage as store
|
||||
from app import storage as store, image_diff_queue
|
||||
from auth.auth import process_auth, extract_namespace_repo_from_session
|
||||
from util import checksums, changes
|
||||
from util.http import abort
|
||||
|
|
|
@ -8,7 +8,7 @@ from data import model
|
|||
from auth.auth import process_auth
|
||||
from auth.permissions import ModifyRepositoryPermission
|
||||
from util.invoice import renderInvoiceToHtml
|
||||
from util.email import send_invoice_email, send_subscription_change, send_payment_failed
|
||||
from util.useremails import send_invoice_email, send_subscription_change, send_payment_failed
|
||||
from util.names import parse_repository_name
|
||||
from util.http import abort
|
||||
from endpoints.trigger import BuildTrigger, ValidationRequestException, SkipRequestException
|
||||
|
|
Reference in a new issue