Remove unnecessary calls to the database for user and permission metadata.

This commit is contained in:
yackob03 2013-10-15 14:48:49 -04:00
parent 13298be5d3
commit 959016a6eb
5 changed files with 58 additions and 39 deletions

View file

@ -7,6 +7,7 @@ from base64 import b64decode
from data import model from data import model
from app import app from app import app
from permissions import QuayDeferredPermissionUser
from util.names import parse_namespace_repository from util.names import parse_namespace_repository
@ -40,8 +41,9 @@ def process_basic_auth(auth):
ctx = _request_ctx_stack.top ctx = _request_ctx_stack.top
ctx.authenticated_user = authenticated ctx.authenticated_user = authenticated
identity_changed.send(app, identity=Identity(authenticated.username, new_identity = QuayDeferredPermissionUser(authenticated.username,
'username')) 'username')
identity_changed.send(app, identity=new_identity)
return return
# We weren't able to authenticate via basic auth. # We weren't able to authenticate via basic auth.

View file

@ -1,13 +1,12 @@
import logging import logging
from flask.ext.principal import identity_loaded, UserNeed, Permission from flask.ext.principal import (identity_loaded, UserNeed, Permission,
from flask.ext.login import current_user Identity, identity_changed)
from collections import namedtuple from collections import namedtuple
from functools import partial from functools import partial
from data import model from data import model
from app import app from app import app
from auth import get_authenticated_user, get_validated_token
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -17,6 +16,29 @@ _ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role'])
_RepositoryNeed = partial(_ResourceNeed, 'repository') _RepositoryNeed = partial(_ResourceNeed, 'repository')
class QuayDeferredPermissionUser(Identity):
def __init__(self, id, auth_type=None):
super(QuayDeferredPermissionUser, self).__init__(id, auth_type)
self._permissions_loaded = False
def can(self, permission):
if not self._permissions_loaded:
logger.debug('Loading user permissions after deferring.')
user_object = model.get_user(self.id)
for user in model.get_all_user_permissions(user_object):
grant = _RepositoryNeed(user.repositorypermission.repository.namespace,
user.repositorypermission.repository.name,
user.repositorypermission.role.name)
logger.debug('User added permission: {0}'.format(grant))
self.provides.add(grant)
self._permissions_loaded = True
return super(QuayDeferredPermissionUser, self).can(permission)
class ModifyRepositoryPermission(Permission): class ModifyRepositoryPermission(Permission):
def __init__(self, namespace, name): def __init__(self, namespace, name):
admin_need = _RepositoryNeed(namespace, name, 'admin') admin_need = _RepositoryNeed(namespace, name, 'admin')
@ -50,18 +72,12 @@ def on_identity_loaded(sender, identity):
logger.debug('Identity loaded: %s' % identity) logger.debug('Identity loaded: %s' % identity)
# We have verified an identity, load in all of the permissions # We have verified an identity, load in all of the permissions
if identity.auth_type == 'username': if isinstance(identity, QuayDeferredPermissionUser):
logger.debug('Computing permissions for user: %s' % identity.id) logger.debug('Deferring permissions for user: %s' % identity.id)
user_object = model.get_user(identity.id) elif identity.auth_type == 'username':
switch_to_deferred = QuayDeferredPermissionUser(identity.id, 'username')
identity.provides.add(UserNeed(user_object.username)) identity_changed.send(app, identity=switch_to_deferred)
for user in model.get_all_user_permissions(user_object):
grant = _RepositoryNeed(user.repositorypermission.repository.namespace,
user.repositorypermission.repository.name,
user.repositorypermission.role.name)
logger.debug('User added permission: {0}'.format(grant))
identity.provides.add(grant)
elif identity.auth_type == 'token': elif identity.auth_type == 'token':
logger.debug('Computing permissions for token: %s' % identity.id) logger.debug('Computing permissions for token: %s' % identity.id)

View file

@ -14,18 +14,12 @@ db = app.config['DB_DRIVER'](app.config['DB_NAME'],
**app.config['DB_CONNECTION_ARGS']) **app.config['DB_CONNECTION_ARGS'])
def connect_db():
logger.debug('Connectin to database.')
db.connect()
def close_db(exc): def close_db(exc):
if not db.is_closed(): if not db.is_closed():
logger.debug('Disconnecting from database.') logger.debug('Disconnecting from database.')
db.close() db.close()
app.before_request(connect_db)
app.teardown_request(close_db) app.teardown_request(close_db)

View file

@ -46,7 +46,7 @@ def get_logged_in_user():
if current_user.is_anonymous(): if current_user.is_anonymous():
return jsonify({'anonymous': True}) return jsonify({'anonymous': True})
user = current_user.db_user user = current_user.db_user()
return jsonify({ return jsonify({
'verified': user.verified, 'verified': user.verified,
'anonymous': False, 'anonymous': False,
@ -59,7 +59,7 @@ def get_logged_in_user():
@app.route('/api/user/', methods=['PUT']) @app.route('/api/user/', methods=['PUT'])
@api_login_required @api_login_required
def change_user_details(): def change_user_details():
user = current_user.db_user user = current_user.db_user()
user_data = request.get_json(); user_data = request.get_json();
@ -184,7 +184,7 @@ def match_repos_api():
username = None username = None
if current_user.is_authenticated(): if current_user.is_authenticated():
username = current_user.db_user.username username = current_user.db_user().username
matching = model.get_matching_repositories(prefix, username) matching = model.get_matching_repositories(prefix, username)
response = { response = {
@ -219,7 +219,7 @@ def list_repos_api():
username = None username = None
if current_user.is_authenticated() and include_private: if current_user.is_authenticated() and include_private:
username = current_user.db_user.username username = current_user.db_user().username
repo_query = model.get_visible_repositories(username, limit=limit, repo_query = model.get_visible_repositories(username, limit=limit,
include_public=include_public, include_public=include_public,
@ -474,7 +474,7 @@ def subscribe():
request_data = request.get_json() request_data = request.get_json()
plan = request_data['plan'] plan = request_data['plan']
user = current_user.db_user user = current_user.db_user()
private_repos = model.get_private_repo_count(user.username) private_repos = model.get_private_repo_count(user.username)
if not user.stripe_id: if not user.stripe_id:
@ -518,7 +518,7 @@ def subscribe():
@app.route('/api/user/plan', methods=['GET']) @app.route('/api/user/plan', methods=['GET'])
@api_login_required @api_login_required
def get_subscription(): def get_subscription():
user = current_user.db_user user = current_user.db_user()
private_repos = model.get_private_repo_count(user.username) private_repos = model.get_private_repo_count(user.username)
if user.stripe_id: if user.stripe_id:

View file

@ -8,30 +8,37 @@ from flask.ext.principal import identity_changed, Identity, AnonymousIdentity
from data import model from data import model
from app import app, login_manager, mixpanel from app import app, login_manager, mixpanel
from auth.permissions import QuayDeferredPermissionUser
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class _LoginWrappedDBUser(UserMixin): class _LoginWrappedDBUser(UserMixin):
def __init__(self, db_user): def __init__(self, db_username):
self.db_user = db_user
self._db_username = db_username
self._db_user = None
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): def is_active(self):
return self.db_user.verified return self.db_user().verified
def get_id(self): def get_id(self):
return unicode(self.db_user.username) return unicode(self._db_username)
@login_manager.user_loader @login_manager.user_loader
def load_user(username): def load_user(username):
logger.debug('Loading user: %s' % username) logger.debug('Loading user: %s' % username)
db_user = model.get_user(username) return _LoginWrappedDBUser(username)
if db_user:
return _LoginWrappedDBUser(db_user)
else:
return None
@app.route('/', methods=['GET'], defaults={'path': ''}) @app.route('/', methods=['GET'], defaults={'path': ''})
@ -78,8 +85,8 @@ def privacy():
def common_login(db_user): def common_login(db_user):
if login_user(_LoginWrappedDBUser(db_user)): if login_user(_LoginWrappedDBUser(db_user)):
logger.debug('Successfully signed in as: %s' % db_user.username) logger.debug('Successfully signed in as: %s' % db_user.username)
identity_changed.send(app, new_identity = QuayDeferredPermissionUser(db_user.username, 'username')
identity=Identity(db_user.username, 'username')) identity_changed.send(app, identity=new_identity)
return True return True
else: else:
logger.debug('User could not be logged in, inactive?.') logger.debug('User could not be logged in, inactive?.')