mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-19 01:44:45 -05:00
A lot of pages in the admin app are now generated entirely from Redis, without touching the API. The one remaining API call that a lot of pages make, when the user is platform admin or a member of an organisation, is to get the name of the current service’s organisation. This commit adds some code to start caching that as well, which should speed up page load times for when we’re clicking around the admin app (it’s typically 100ms just to get the organisation, and more than that when the API is under load). This means changing the service model to get the organisation from the API by ID, not by service ID. Otherwise it would be very hard to clear the cache if the name of the organisation ever changed. We can’t cache the whole organisation because it has a `count_of_live_services` field which can change at any time, without an update being made.
210 lines
6.4 KiB
Python
210 lines
6.4 KiB
Python
from flask import abort
|
||
from werkzeug.utils import cached_property
|
||
|
||
from app.models import JSONModel, ModelList
|
||
from app.notify_client.email_branding_client import email_branding_client
|
||
from app.notify_client.letter_branding_client import letter_branding_client
|
||
from app.notify_client.organisations_api_client import organisations_client
|
||
|
||
|
||
class Organisation(JSONModel):
|
||
|
||
TYPE_CENTRAL = 'central'
|
||
TYPE_LOCAL = 'local'
|
||
TYPE_NHS_CENTRAL = 'nhs_central'
|
||
TYPE_NHS_LOCAL = 'nhs_local'
|
||
TYPE_NHS_GP = 'nhs_gp'
|
||
TYPE_EMERGENCY_SERVICE = 'emergency_service'
|
||
TYPE_SCHOOL_OR_COLLEGE = 'school_or_college'
|
||
TYPE_OTHER = 'other'
|
||
|
||
TYPES = (
|
||
(TYPE_CENTRAL, 'Central government'),
|
||
(TYPE_LOCAL, 'Local government'),
|
||
(TYPE_NHS_CENTRAL, 'NHS – central government agency or public body'),
|
||
(TYPE_NHS_LOCAL, 'NHS Trust or Clinical Commissioning Group'),
|
||
(TYPE_NHS_GP, 'GP practice'),
|
||
(TYPE_EMERGENCY_SERVICE, 'Emergency service'),
|
||
(TYPE_SCHOOL_OR_COLLEGE, 'School or college'),
|
||
(TYPE_OTHER, 'Other'),
|
||
)
|
||
|
||
ALLOWED_PROPERTIES = {
|
||
'id',
|
||
'name',
|
||
'active',
|
||
'crown',
|
||
'organisation_type',
|
||
'letter_branding_id',
|
||
'email_branding_id',
|
||
'agreement_signed',
|
||
'agreement_signed_at',
|
||
'agreement_signed_by_id',
|
||
'agreement_signed_version',
|
||
'agreement_signed_on_behalf_of_name',
|
||
'agreement_signed_on_behalf_of_email_address',
|
||
'domains',
|
||
'request_to_go_live_notes',
|
||
'count_of_live_services',
|
||
}
|
||
|
||
@classmethod
|
||
def from_id(cls, org_id):
|
||
if not org_id:
|
||
return cls({})
|
||
return cls(organisations_client.get_organisation(org_id))
|
||
|
||
@classmethod
|
||
def from_domain(cls, domain):
|
||
return cls(organisations_client.get_organisation_by_domain(domain))
|
||
|
||
@classmethod
|
||
def from_service(cls, service_id):
|
||
return cls(organisations_client.get_service_organisation(service_id))
|
||
|
||
@classmethod
|
||
def create_from_form(cls, form):
|
||
return cls.create(
|
||
name=form.name.data,
|
||
crown={
|
||
'crown': True,
|
||
'non-crown': False,
|
||
'unknown': None,
|
||
}.get(form.crown_status.data),
|
||
organisation_type=form.organisation_type.data,
|
||
)
|
||
|
||
@classmethod
|
||
def create(cls, name, crown, organisation_type, agreement_signed=False):
|
||
return cls(organisations_client.create_organisation(
|
||
name=name,
|
||
crown=crown,
|
||
organisation_type=organisation_type,
|
||
agreement_signed=agreement_signed,
|
||
))
|
||
|
||
def __init__(self, _dict):
|
||
|
||
super().__init__(_dict)
|
||
|
||
if self._dict == {}:
|
||
self.name = None
|
||
self.crown = None
|
||
self.agreement_signed = None
|
||
self.domains = []
|
||
self.organisation_type = None
|
||
self.request_to_go_live_notes = None
|
||
self.email_branding_id = None
|
||
|
||
def as_agreement_statement_for_go_live_request(self, fallback_domain):
|
||
if self.agreement_signed:
|
||
agreement_statement = 'Yes, on behalf of {}.'.format(self.name)
|
||
elif self.name:
|
||
agreement_statement = '{} (organisation is {}, {}).'.format(
|
||
{
|
||
False: 'No',
|
||
None: 'Can’t tell',
|
||
}.get(self.agreement_signed),
|
||
self.name,
|
||
{
|
||
True: 'a crown body',
|
||
False: 'a non-crown body',
|
||
None: 'crown status unknown',
|
||
}.get(self.crown),
|
||
)
|
||
else:
|
||
agreement_statement = 'Can’t tell (domain is {}).'.format(fallback_domain)
|
||
|
||
if self.request_to_go_live_notes:
|
||
agreement_statement = agreement_statement + ' ' + self.request_to_go_live_notes
|
||
|
||
return agreement_statement
|
||
|
||
def as_info_for_branding_request(self, fallback_domain):
|
||
return self.name or 'Can’t tell (domain is {})'.format(fallback_domain)
|
||
|
||
@property
|
||
def organisation_type_label(self):
|
||
return dict(self.TYPES).get(self.organisation_type)
|
||
|
||
@property
|
||
def crown_status_or_404(self):
|
||
if self.crown is None:
|
||
abort(404)
|
||
return self.crown
|
||
|
||
@cached_property
|
||
def services(self):
|
||
return organisations_client.get_organisation_services(self.id)
|
||
|
||
@cached_property
|
||
def service_ids(self):
|
||
return [s['id'] for s in self.services]
|
||
|
||
@property
|
||
def live_services(self):
|
||
return [s for s in self.services if s['active'] and not s['restricted']]
|
||
|
||
@property
|
||
def trial_services(self):
|
||
return [s for s in self.services if not s['active'] or s['restricted']]
|
||
|
||
@cached_property
|
||
def invited_users(self):
|
||
from app.models.user import OrganisationInvitedUsers
|
||
return OrganisationInvitedUsers(self.id)
|
||
|
||
@cached_property
|
||
def active_users(self):
|
||
from app.models.user import OrganisationUsers
|
||
return OrganisationUsers(self.id)
|
||
|
||
@cached_property
|
||
def team_members(self):
|
||
return sorted(
|
||
self.invited_users + self.active_users,
|
||
key=lambda user: user.email_address.lower(),
|
||
)
|
||
|
||
@cached_property
|
||
def email_branding(self):
|
||
if self.email_branding_id:
|
||
return email_branding_client.get_email_branding(
|
||
self.email_branding_id
|
||
)['email_branding']
|
||
|
||
@property
|
||
def email_branding_name(self):
|
||
if self.email_branding_id:
|
||
return self.email_branding['name']
|
||
return 'GOV.UK'
|
||
|
||
@cached_property
|
||
def letter_branding(self):
|
||
if self.letter_branding_id:
|
||
return letter_branding_client.get_letter_branding(
|
||
self.letter_branding_id
|
||
)
|
||
|
||
def update(self, delete_services_cache=False, **kwargs):
|
||
response = organisations_client.update_organisation(
|
||
self.id,
|
||
cached_service_ids=self.service_ids if delete_services_cache else None,
|
||
**kwargs
|
||
)
|
||
self.__init__(response)
|
||
|
||
def associate_service(self, service_id):
|
||
organisations_client.update_service_organisation(
|
||
service_id,
|
||
self.id
|
||
)
|
||
|
||
def services_and_usage(self, financial_year):
|
||
return organisations_client.get_services_and_usage(self.id, financial_year)
|
||
|
||
|
||
class Organisations(ModelList):
|
||
client_method = organisations_client.get_organisations
|
||
model = Organisation
|