This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/endpoints/common.py
Joseph Schorr c374e8146a - Add code for placing the features information on the frontend
- Add a Features service for examining feature flags on the frontend
- Add a directive (quay-requires) that matches feature flags and, if any one does not match, removes the element from the DOM
- Add a directive (quay-show) that injects the features into the scope so that expressions of the form "Features.BILLING || something" work out of the box to show/hide the element
- Add a directive (quay-classes) that allows for setting of CSS classes on an element based on feature expression(s) such as {"!BILLING": "active"} (e.g. the BILLING flag is set to false, add the class "active".
2014-04-04 23:26:10 -04:00

181 lines
5.1 KiB
Python

import logging
import urlparse
import json
import string
from flask import make_response, render_template, request, abort
from flask.ext.login import login_user, UserMixin
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 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
import features
logger = logging.getLogger(__name__)
route_data = None
class RepoPathConverter(BaseConverter):
regex = '[\.a-zA-Z0-9_\-]+/[\.a-zA-Z0-9_\-]+'
weight = 200
app.url_map.converters['repopath'] = RepoPathConverter
def route_show_if(value):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not value:
abort(404)
return f(*args, **kwargs)
return decorated_function
return decorator
def route_hide_if(value):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if value:
abort(404)
return f(*args, **kwargs)
return decorated_function
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'}
@login_manager.user_loader
def load_user(username):
logger.debug('User loader loading deferred user: %s' % username)
return _LoginWrappedDBUser(username)
class _LoginWrappedDBUser(UserMixin):
def __init__(self, db_username, db_user=None):
self._db_username = db_username
self._db_user = db_user
def db_user(self):
if not self._db_user:
self._db_user = model.get_user(self._db_username)
return self._db_user
def is_authenticated(self):
return self.db_user() is not None
def is_active(self):
return self.db_user().verified
def get_id(self):
return unicode(self._db_username)
def common_login(db_user):
if login_user(_LoginWrappedDBUser(db_user.username, db_user)):
logger.debug('Successfully signed in as: %s' % db_user.username)
new_identity = QuayDeferredPermissionUser(db_user.username, 'username', {scopes.DIRECT_LOGIN})
identity_changed.send(app, identity=new_identity)
return True
else:
logger.debug('User could not be logged in, inactive?.')
return False
@app.errorhandler(model.DataModelException)
def handle_dme(ex):
logger.exception(ex)
return make_response(json.dumps({'message': ex.message}), 400)
def random_string():
return 'REMOVEME'
random = SystemRandom()
return ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(8)])
def render_page_template(name, **kwargs):
resp = make_response(render_template(name, route_data=json.dumps(get_route_data()),
feature_set=json.dumps(features.get_features()),
cache_buster=random_string(),
**kwargs))
resp.headers['X-FRAME-OPTIONS'] = 'DENY'
return resp
def check_repository_usage(user_or_org, plan_found):
private_repos = model.get_private_repo_count(user_or_org.username)
repos_allowed = plan_found['privateRepos']
if private_repos > repos_allowed:
model.create_notification('over_private_usage', user_or_org, {'namespace': user_or_org.username})
else:
model.delete_notifications_by_kind(user_or_org, 'over_private_usage')
def start_build(repository, dockerfile_id, tags, build_name, subdir, manual,
trigger=None, pull_robot_name=None):
host = urlparse.urlparse(request.url).netloc
repo_path = '%s/%s/%s' % (host, repository.namespace, repository.name)
token = model.create_access_token(repository, 'write')
logger.debug('Creating build %s with repo %s tags %s and dockerfile_id %s',
build_name, repo_path, tags, dockerfile_id)
job_config = {
'docker_tags': tags,
'repository': repo_path,
'build_subdir': subdir
}
build_request = model.create_repository_build(repository, token, job_config,
dockerfile_id, build_name,
trigger, pull_robot_name = pull_robot_name)
dockerfile_build_queue.put(json.dumps({
'build_uuid': build_request.uuid,
'namespace': repository.namespace,
'repository': repository.name,
'pull_credentials': model.get_pull_credentials(pull_robot_name) if pull_robot_name else None
}), retries_remaining=1)
metadata = {
'repo': repository.name,
'namespace': repository.namespace,
'fileid': dockerfile_id,
'manual': manual,
}
if trigger:
metadata['trigger_id'] = trigger.uuid
metadata['config'] = json.loads(trigger.config)
metadata['service'] = trigger.service.name
model.log_action('build_dockerfile', repository.namespace,
ip=request.remote_addr, metadata=metadata,
repository=repository)
return build_request