use joinedload to only hit the database once per request

also:

* only include active orgs
* write lots of tests
This commit is contained in:
Leo Hemsted
2018-03-13 13:07:02 +00:00
parent 91fa475645
commit 5871dee606
4 changed files with 150 additions and 8 deletions

View File

@@ -1,6 +1,9 @@
from random import (SystemRandom)
from datetime import (datetime, timedelta)
from sqlalchemy import func
from sqlalchemy.orm import joinedload
from app import db
from app.models import (User, VerifyCode)
@@ -113,3 +116,16 @@ def update_user_password(user, password):
user.password_changed_at = datetime.utcnow()
db.session.add(user)
db.session.commit()
def get_user_and_accounts(user_id):
return User.query.filter(
User.id == user_id
).options(
# eagerly load the user's services and organisations, and also the service's org and vice versa
# (so we can see if the user knows about it)
joinedload('services'),
joinedload('organisations'),
joinedload('organisations.services'),
joinedload('services.organisation'),
).one()

View File

@@ -116,11 +116,11 @@ class User(db.Model):
services = db.relationship(
'Service',
secondary='user_to_service',
backref=db.backref('user_to_service', lazy='dynamic'))
backref='user_to_service')
organisations = db.relationship(
'Organisation',
secondary='user_to_organisation',
backref=db.backref('users', lazy='dynamic'))
backref='users')
@property
def password(self):

View File

@@ -19,7 +19,8 @@ from app.dao.users_dao import (
create_secret_code,
save_user_attribute,
update_user_password,
count_user_verify_codes
count_user_verify_codes,
get_user_and_accounts
)
from app.dao.permissions_dao import permission_dao
from app.dao.services_dao import dao_fetch_service_by_id
@@ -397,8 +398,7 @@ def update_password(user_id):
@user_blueprint.route('/<uuid:user_id>/organisations-and-services', methods=['GET'])
def get_organisations_and_services_for_user(user_id):
user = get_user_by_id(user_id=user_id)
user = get_user_and_accounts(user_id)
data = {
'organisations': [
{
@@ -410,10 +410,10 @@ def get_organisations_and_services_for_user(user_id):
'name': service.name
}
for service in org.services
if service.active and user in service.users
if service.active and service in user.services
]
}
for org in user.organisations
for org in user.organisations if org.active
],
'services_without_organisations': [
{
@@ -426,7 +426,7 @@ def get_organisations_and_services_for_user(user_id):
# but not one that the user can see.
(
not service.organisation or
user not in service.organisation.users
service.organisation not in user.organisations
)
)
]