notify-api-332 rename organisation

This commit is contained in:
Kenneth Kehl
2023-07-10 11:06:29 -07:00
parent 8be3864d7a
commit 4940d5e93b
42 changed files with 1301 additions and 1274 deletions

View File

@@ -145,8 +145,8 @@ def register_blueprint(application):
receive_notifications_blueprint,
)
from app.notifications.rest import notifications as notifications_blueprint
from app.organisation.invite_rest import organisation_invite_blueprint
from app.organisation.rest import organisation_blueprint
from app.organization.invite_rest import organization_invite_blueprint
from app.organization.rest import organization_blueprint
from app.performance_dashboard.rest import performance_dashboard_blueprint
from app.platform_stats.rest import platform_stats_blueprint
from app.provider_details.rest import (
@@ -202,8 +202,8 @@ def register_blueprint(application):
service_invite_blueprint.before_request(requires_admin_auth)
application.register_blueprint(service_invite_blueprint)
organisation_invite_blueprint.before_request(requires_admin_auth)
application.register_blueprint(organisation_invite_blueprint)
organization_invite_blueprint.before_request(requires_admin_auth)
application.register_blueprint(organization_invite_blueprint)
inbound_number_blueprint.before_request(requires_admin_auth)
application.register_blueprint(inbound_number_blueprint)
@@ -229,8 +229,8 @@ def register_blueprint(application):
service_callback_blueprint.before_request(requires_admin_auth)
application.register_blueprint(service_callback_blueprint)
organisation_blueprint.before_request(requires_admin_auth)
application.register_blueprint(organisation_blueprint, url_prefix='/organisations')
organization_blueprint.before_request(requires_admin_auth)
application.register_blueprint(organization_blueprint, url_prefix='/organizations')
complaint_blueprint.before_request(requires_admin_auth)
application.register_blueprint(complaint_blueprint)

View File

@@ -63,7 +63,7 @@ def get_free_sms_fragment_limit(service_id):
if annual_billing is None:
service = Service.query.get(service_id)
# An entry does not exist in annual_billing table for that service and year.
# Set the annual billing to the default free allowance based on the organisation type of the service.
# Set the annual billing to the default free allowance based on the organization type of the service.
annual_billing = set_default_free_allowance_for_service(
service=service,

View File

@@ -31,10 +31,10 @@ from app.dao.fact_billing_dao import (
update_fact_billing,
)
from app.dao.jobs_dao import dao_get_job_by_id
from app.dao.organisation_dao import (
dao_add_service_to_organisation,
dao_get_organisation_by_email_address,
dao_get_organisation_by_id,
from app.dao.organization_dao import (
dao_add_service_to_organization,
dao_get_organization_by_email_address,
dao_get_organization_by_id,
)
from app.dao.services_dao import (
dao_fetch_all_services_by_user,
@@ -57,7 +57,7 @@ from app.models import (
Domain,
EmailBranding,
Notification,
Organisation,
Organization,
Service,
Template,
TemplateHistory,
@@ -273,18 +273,18 @@ def update_jobs_archived_flag(start_date, end_date):
current_app.logger.info('Total archived jobs = {}'.format(total_updated))
@notify_command(name='populate-organisations-from-file')
@notify_command(name='populate-organizations-from-file')
@click.option('-f', '--file_name', required=True,
help="Pipe delimited file containing organisation name, sector, agreement_signed, domains")
def populate_organisations_from_file(file_name):
# [0] organisation name:: name of the organisation insert if organisation is missing.
help="Pipe delimited file containing organization name, sector, agreement_signed, domains")
def populate_organizations_from_file(file_name):
# [0] organization name:: name of the organization insert if organization is missing.
# [1] sector:: Federal | State only
# [2] agreement_signed:: TRUE | FALSE
# [3] domains:: comma separated list of domains related to the organisation
# [3] domains:: comma separated list of domains related to the organization
# [4] email branding name: name of the default email branding for the org
# The expectation is that the organisation, organisation_to_service
# and user_to_organisation will be cleared before running this command.
# The expectation is that the organization, organization_to_service
# and user_to_organization will be cleared before running this command.
# Ignoring duplicates allows us to run the command again with the same file or same file with new rows.
with open(file_name, 'r') as f:
def boolean_or_none(field):
@@ -306,10 +306,10 @@ def populate_organisations_from_file(file_name):
'name': columns[0],
'active': True,
'agreement_signed': boolean_or_none(columns[3]),
'organisation_type': columns[1].lower(),
'organization_type': columns[1].lower(),
'email_branding_id': email_branding.id if email_branding else None
}
org = Organisation(**data)
org = Organization(**data)
try:
db.session.add(org)
db.session.commit()
@@ -319,7 +319,7 @@ def populate_organisations_from_file(file_name):
domains = columns[4].split(',')
for d in domains:
if len(d.strip()) > 0:
domain = Domain(domain=d.strip(), organisation_id=org.id)
domain = Domain(domain=d.strip(), organization_id=org.id)
try:
db.session.add(domain)
db.session.commit()
@@ -328,14 +328,14 @@ def populate_organisations_from_file(file_name):
db.session.rollback()
@notify_command(name='populate-organisation-agreement-details-from-file')
@notify_command(name='populate-organization-agreement-details-from-file')
@click.option('-f', '--file_name', required=True,
help="CSV file containing id, agreement_signed_version, "
"agreement_signed_on_behalf_of_name, agreement_signed_at")
def populate_organisation_agreement_details_from_file(file_name):
def populate_organization_agreement_details_from_file(file_name):
"""
The input file should be a comma separated CSV file with a header row and 4 columns
id: the organisation ID
id: the organization ID
agreement_signed_version
agreement_signed_on_behalf_of_name
agreement_signed_at: The date the agreement was signed in the format of 'dd/mm/yyyy'
@@ -347,7 +347,7 @@ def populate_organisation_agreement_details_from_file(file_name):
next(csv_reader)
for row in csv_reader:
org = dao_get_organisation_by_id(row[0])
org = dao_get_organization_by_id(row[0])
current_app.logger.info(f"Updating {org.name}")
@@ -362,20 +362,20 @@ def populate_organisation_agreement_details_from_file(file_name):
db.session.commit()
@notify_command(name='associate-services-to-organisations')
def associate_services_to_organisations():
@notify_command(name='associate-services-to-organizations')
def associate_services_to_organizations():
services = Service.get_history_model().query.filter_by(
version=1
).all()
for s in services:
created_by_user = User.query.filter_by(id=s.created_by_id).first()
organisation = dao_get_organisation_by_email_address(created_by_user.email_address)
organization = dao_get_organization_by_email_address(created_by_user.email_address)
service = dao_fetch_service_by_id(service_id=s.id)
if organisation:
dao_add_service_to_organisation(service=service, organisation_id=organisation.id)
if organization:
dao_add_service_to_organization(service=service, organization_id=organization.id)
print("finished associating services to organisations")
print("finished associating services to organizations")
@notify_command(name='populate-service-volume-intentions')

View File

@@ -144,7 +144,7 @@ class Config(object):
ALREADY_REGISTERED_EMAIL_TEMPLATE_ID = '0880fbb1-a0c6-46f0-9a8e-36c986381ceb'
CHANGE_EMAIL_CONFIRMATION_TEMPLATE_ID = 'eb4d9930-87ab-4aef-9bce-786762687884'
SERVICE_NOW_LIVE_TEMPLATE_ID = '618185c6-3636-49cd-b7d2-6f6f5eb3bdde'
ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID = '203566f0-d835-47c5-aa06-932439c86573'
ORGANIZATION_INVITATION_EMAIL_TEMPLATE_ID = '203566f0-d835-47c5-aa06-932439c86573'
TEAM_MEMBER_EDIT_EMAIL_TEMPLATE_ID = 'c73f1d71-4049-46d5-a647-d013bdeca3f0'
TEAM_MEMBER_EDIT_MOBILE_TEMPLATE_ID = '8a31520f-4751-4789-8ea1-fe54496725eb'
REPLY_TO_EMAIL_ADDRESS_VERIFICATION_TEMPLATE_ID = 'a42f1d17-9404-46d5-a647-d013bdfca3e1'

View File

@@ -164,8 +164,8 @@
"id": "203566f0-d835-47c5-aa06-932439c86573",
"name": "Notify organization invitation email",
"type": "email",
"subject": "((user_name)) has invited you to collaborate on ((organisation_name)) on U.S. Notify",
"content": ["((user_name)) has invited you to collaborate on ((organisation_name)) on U.S. Notify.","","","U.S. Notify makes it easy to keep people updated by helping you send text messages and emails.","","","Open this link to create an account on U.S. Notify:","","((url))","","","This invitation will stop working at midnight tomorrow. This is to keep ((organisation_name)) secure."]
"subject": "((user_name)) has invited you to collaborate on ((organization_name)) on U.S. Notify",
"content": ["((user_name)) has invited you to collaborate on ((organization_name)) on U.S. Notify.","","","U.S. Notify makes it easy to keep people updated by helping you send text messages and emails.","","","Open this link to create an account on U.S. Notify:","","((url))","","","This invitation will stop working at midnight tomorrow. This is to keep ((organization_name)) secure."]
},
{
"id": "c73f1d71-4049-46d5-a647-d013bdeca3f0",

View File

@@ -78,10 +78,10 @@ def set_default_free_allowance_for_service(service, year_start=None):
year_start = 2020
if year_start > 2022:
year_start = 2022
if service.organisation_type:
free_allowance = default_free_sms_fragment_limits[service.organisation_type][year_start]
if service.organization_type:
free_allowance = default_free_sms_fragment_limits[service.organization_type][year_start]
else:
current_app.logger.info(f"no organisation type for service {service.id}. Using other default of "
current_app.logger.info(f"no organization type for service {service.id}. Using other default of "
f"{default_free_sms_fragment_limits['other'][year_start]}")
free_allowance = default_free_sms_fragment_limits['other'][year_start]

View File

@@ -10,7 +10,7 @@ from app.dao.date_util import (
get_calendar_year_dates,
get_calendar_year_for_datetime,
)
from app.dao.organisation_dao import dao_get_organisation_live_services
from app.dao.organization_dao import dao_get_organization_live_services
from app.models import (
EMAIL_TYPE,
KEY_TYPE_NORMAL,
@@ -22,7 +22,7 @@ from app.models import (
FactBilling,
NotificationAllTimeView,
NotificationHistory,
Organisation,
Organization,
Rate,
Service,
)
@@ -77,8 +77,8 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
sms_cost = chargeable_sms * FactBilling.rate
query = db.session.query(
Organisation.name.label('organisation_name'),
Organisation.id.label('organisation_id'),
Organization.name.label('organization_name'),
Organization.id.label('organization_id'),
Service.name.label("service_name"),
Service.id.label("service_id"),
allowance_left_at_start_date_query.c.free_sms_fragment_limit,
@@ -92,7 +92,7 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
).outerjoin(
allowance_left_at_start_date_query, Service.id == allowance_left_at_start_date_query.c.service_id
).outerjoin(
Service.organisation
Service.organization
).join(
FactBilling, FactBilling.service_id == Service.id,
).filter(
@@ -100,15 +100,15 @@ def fetch_sms_billing_for_all_services(start_date, end_date):
FactBilling.local_date <= end_date,
FactBilling.notification_type == SMS_TYPE,
).group_by(
Organisation.name,
Organisation.id,
Organization.name,
Organization.id,
Service.id,
Service.name,
allowance_left_at_start_date_query.c.free_sms_fragment_limit,
allowance_left_at_start_date_query.c.sms_remainder,
FactBilling.rate,
).order_by(
Organisation.name,
Organization.name,
Service.name
)
@@ -497,7 +497,7 @@ def create_billing_record(data, rate, process_day):
return billing_record
def fetch_email_usage_for_organisation(organisation_id, start_date, end_date):
def fetch_email_usage_for_organization(organization_id, start_date, end_date):
query = db.session.query(
Service.name.label("service_name"),
Service.id.label("service_id"),
@@ -510,7 +510,7 @@ def fetch_email_usage_for_organisation(organisation_id, start_date, end_date):
FactBilling.local_date >= start_date,
FactBilling.local_date <= end_date,
FactBilling.notification_type == EMAIL_TYPE,
Service.organisation_id == organisation_id,
Service.organization_id == organization_id,
Service.restricted.is_(False)
).group_by(
Service.id,
@@ -521,9 +521,9 @@ def fetch_email_usage_for_organisation(organisation_id, start_date, end_date):
return query.all()
def fetch_sms_billing_for_organisation(organisation_id, financial_year):
def fetch_sms_billing_for_organization(organization_id, financial_year):
# ASSUMPTION: AnnualBilling has been populated for year.
ft_billing_subquery = query_organisation_sms_usage_for_year(organisation_id, financial_year).subquery()
ft_billing_subquery = query_organization_sms_usage_for_year(organization_id, financial_year).subquery()
sms_billable_units = func.sum(func.coalesce(ft_billing_subquery.c.chargeable_units, 0))
@@ -551,7 +551,7 @@ def fetch_sms_billing_for_organisation(organisation_id, financial_year):
).outerjoin(
ft_billing_subquery, Service.id == ft_billing_subquery.c.service_id
).filter(
Service.organisation_id == organisation_id,
Service.organization_id == organization_id,
Service.restricted.is_(False)
).group_by(
Service.id,
@@ -564,7 +564,7 @@ def fetch_sms_billing_for_organisation(organisation_id, financial_year):
return query.all()
def query_organisation_sms_usage_for_year(organisation_id, year):
def query_organization_sms_usage_for_year(organization_id, year):
"""
See docstring for query_service_sms_usage_for_year()
"""
@@ -616,15 +616,15 @@ def query_organisation_sms_usage_for_year(organisation_id, year):
FactBilling.notification_type == SMS_TYPE,
)
).filter(
Service.organisation_id == organisation_id,
Service.organization_id == organization_id,
AnnualBilling.financial_year_start == year,
)
def fetch_usage_year_for_organisation(organisation_id, year):
def fetch_usage_year_for_organization(organization_id, year):
year_start, year_end = get_calendar_year_dates(year)
today = datetime.utcnow().date()
services = dao_get_organisation_live_services(organisation_id)
services = dao_get_organization_live_services(organization_id)
# if year end date is less than today, we are calculating for data in the past and have no need for deltas.
if year_end >= today:
@@ -646,8 +646,8 @@ def fetch_usage_year_for_organisation(organisation_id, year):
'emails_sent': 0,
'active': service.active
}
sms_usages = fetch_sms_billing_for_organisation(organisation_id, year)
email_usages = fetch_email_usage_for_organisation(organisation_id, year_start, year_end)
sms_usages = fetch_sms_billing_for_organization(organization_id, year)
email_usages = fetch_email_usage_for_organization(organization_id, year_start, year_end)
for usage in sms_usages:
service_with_usage[str(usage.service_id)] = {
'service_id': usage.service_id,
@@ -669,15 +669,15 @@ def fetch_usage_year_for_organisation(organisation_id, year):
def fetch_billing_details_for_all_services():
billing_details = db.session.query(
Service.id.label('service_id'),
func.coalesce(Service.purchase_order_number, Organisation.purchase_order_number).label('purchase_order_number'),
func.coalesce(Service.billing_contact_names, Organisation.billing_contact_names).label('billing_contact_names'),
func.coalesce(Service.purchase_order_number, Organization.purchase_order_number).label('purchase_order_number'),
func.coalesce(Service.billing_contact_names, Organization.billing_contact_names).label('billing_contact_names'),
func.coalesce(
Service.billing_contact_email_addresses,
Organisation.billing_contact_email_addresses
Organization.billing_contact_email_addresses
).label('billing_contact_email_addresses'),
func.coalesce(Service.billing_reference, Organisation.billing_reference).label('billing_reference'),
func.coalesce(Service.billing_reference, Organization.billing_reference).label('billing_reference'),
).outerjoin(
Service.organisation
Service.organization
).all()
return billing_details
@@ -797,8 +797,8 @@ def fetch_volumes_by_service(start_date, end_date):
results = db.session.query(
Service.name.label("service_name"),
Service.id.label("service_id"),
Service.organisation_id.label("organisation_id"),
Organisation.name.label("organisation_name"),
Service.organization_id.label("organization_id"),
Organization.name.label("organization_name"),
annual_billing.c.free_sms_fragment_limit.label("free_allowance"),
func.coalesce(func.sum(volume_stats.c.sms_totals), 0).label("sms_notifications"),
func.coalesce(func.sum(volume_stats.c.sms_fragments_times_multiplier), 0
@@ -807,7 +807,7 @@ def fetch_volumes_by_service(start_date, end_date):
).select_from(
Service
).outerjoin(
Organisation, Service.organisation_id == Organisation.id
Organization, Service.organization_id == Organization.id
).join(
annual_billing, Service.id == annual_billing.c.service_id
).outerjoin( # include services without volume
@@ -819,11 +819,11 @@ def fetch_volumes_by_service(start_date, end_date):
).group_by(
Service.id,
Service.name,
Service.organisation_id,
Organisation.name,
Service.organization_id,
Organization.name,
annual_billing.c.free_sms_fragment_limit
).order_by(
Organisation.name,
Organization.name,
Service.name,
).all()

View File

@@ -1,7 +1,7 @@
from datetime import datetime, timedelta
from app import db
from app.models import InvitedOrganisationUser
from app.models import InvitedOrganizationUser
def save_invited_org_user(invited_org_user):
@@ -9,21 +9,21 @@ def save_invited_org_user(invited_org_user):
db.session.commit()
def get_invited_org_user(organisation_id, invited_org_user_id):
return InvitedOrganisationUser.query.filter_by(organisation_id=organisation_id, id=invited_org_user_id).one()
def get_invited_org_user(organization_id, invited_org_user_id):
return InvitedOrganizationUser.query.filter_by(organization_id=organization_id, id=invited_org_user_id).one()
def get_invited_org_user_by_id(invited_org_user_id):
return InvitedOrganisationUser.query.filter_by(id=invited_org_user_id).one()
return InvitedOrganizationUser.query.filter_by(id=invited_org_user_id).one()
def get_invited_org_users_for_organisation(organisation_id):
return InvitedOrganisationUser.query.filter_by(organisation_id=organisation_id).all()
def get_invited_org_users_for_organization(organization_id):
return InvitedOrganizationUser.query.filter_by(organization_id=organization_id).all()
def delete_org_invitations_created_more_than_two_days_ago():
deleted = db.session.query(InvitedOrganisationUser).filter(
InvitedOrganisationUser.created_at <= datetime.utcnow() - timedelta(days=2)
deleted = db.session.query(InvitedOrganizationUser).filter(
InvitedOrganizationUser.created_at <= datetime.utcnow() - timedelta(days=2)
).delete()
db.session.commit()
return deleted

View File

@@ -1,137 +0,0 @@
from sqlalchemy.sql.expression import func
from app import db
from app.dao.dao_utils import VersionOptions, autocommit, version_class
from app.models import Domain, Organisation, Service, User
def dao_get_organisations():
return Organisation.query.order_by(
Organisation.active.desc(), Organisation.name.asc()
).all()
def dao_count_organisations_with_live_services():
return db.session.query(Organisation.id).join(Organisation.services).filter(
Service.active.is_(True),
Service.restricted.is_(False),
Service.count_as_live.is_(True),
).distinct().count()
def dao_get_organisation_services(organisation_id):
return Organisation.query.filter_by(
id=organisation_id
).one().services
def dao_get_organisation_live_services(organisation_id):
return Service.query.filter_by(
organisation_id=organisation_id,
restricted=False
).all()
def dao_get_organisation_by_id(organisation_id):
return Organisation.query.filter_by(id=organisation_id).one()
def dao_get_organisation_by_email_address(email_address):
email_address = email_address.lower().replace('.gsi.gov.uk', '.gov.uk')
for domain in Domain.query.order_by(func.char_length(Domain.domain).desc()).all():
if (
email_address.endswith("@{}".format(domain.domain)) or
email_address.endswith(".{}".format(domain.domain))
):
return Organisation.query.filter_by(id=domain.organisation_id).one()
return None
def dao_get_organisation_by_service_id(service_id):
return Organisation.query.join(Organisation.services).filter_by(id=service_id).first()
@autocommit
def dao_create_organisation(organisation):
db.session.add(organisation)
@autocommit
def dao_update_organisation(organisation_id, **kwargs):
domains = kwargs.pop('domains', None)
num_updated = Organisation.query.filter_by(id=organisation_id).update(
kwargs
)
if isinstance(domains, list):
Domain.query.filter_by(organisation_id=organisation_id).delete()
db.session.bulk_save_objects([
Domain(domain=domain.lower(), organisation_id=organisation_id)
for domain in domains
])
organisation = Organisation.query.get(organisation_id)
if 'organisation_type' in kwargs:
_update_organisation_services(organisation, 'organisation_type', only_where_none=False)
if 'email_branding_id' in kwargs:
_update_organisation_services(organisation, 'email_branding')
return num_updated
@version_class(
VersionOptions(Service, must_write_history=False),
)
def _update_organisation_services(organisation, attribute, only_where_none=True):
for service in organisation.services:
if getattr(service, attribute) is None or not only_where_none:
setattr(service, attribute, getattr(organisation, attribute))
db.session.add(service)
@autocommit
@version_class(Service)
def dao_add_service_to_organisation(service, organisation_id):
organisation = Organisation.query.filter_by(
id=organisation_id
).one()
service.organisation_id = organisation_id
service.organisation_type = organisation.organisation_type
db.session.add(service)
def dao_get_users_for_organisation(organisation_id):
return db.session.query(
User
).join(
User.organisations
).filter(
Organisation.id == organisation_id,
User.state == 'active'
).order_by(User.created_at).all()
@autocommit
def dao_add_user_to_organisation(organisation_id, user_id):
organisation = dao_get_organisation_by_id(organisation_id)
user = User.query.filter_by(id=user_id).one()
user.organisations.append(organisation)
db.session.add(organisation)
return user
@autocommit
def dao_remove_user_from_organisation(organisation, user):
organisation.users.remove(user)

137
app/dao/organization_dao.py Normal file
View File

@@ -0,0 +1,137 @@
from sqlalchemy.sql.expression import func
from app import db
from app.dao.dao_utils import VersionOptions, autocommit, version_class
from app.models import Domain, Organization, Service, User
def dao_get_organizations():
return Organization.query.order_by(
Organization.active.desc(), Organization.name.asc()
).all()
def dao_count_organizations_with_live_services():
return db.session.query(Organization.id).join(Organization.services).filter(
Service.active.is_(True),
Service.restricted.is_(False),
Service.count_as_live.is_(True),
).distinct().count()
def dao_get_organization_services(organization_id):
return Organization.query.filter_by(
id=organization_id
).one().services
def dao_get_organization_live_services(organization_id):
return Service.query.filter_by(
organization_id=organization_id,
restricted=False
).all()
def dao_get_organization_by_id(organization_id):
return Organization.query.filter_by(id=organization_id).one()
def dao_get_organization_by_email_address(email_address):
email_address = email_address.lower().replace('.gsi.gov.uk', '.gov.uk')
for domain in Domain.query.order_by(func.char_length(Domain.domain).desc()).all():
if (
email_address.endswith("@{}".format(domain.domain)) or
email_address.endswith(".{}".format(domain.domain))
):
return Organization.query.filter_by(id=domain.organization_id).one()
return None
def dao_get_organization_by_service_id(service_id):
return Organization.query.join(Organization.services).filter_by(id=service_id).first()
@autocommit
def dao_create_organization(organization):
db.session.add(organization)
@autocommit
def dao_update_organization(organization_id, **kwargs):
domains = kwargs.pop('domains', None)
num_updated = Organization.query.filter_by(id=organization_id).update(
kwargs
)
if isinstance(domains, list):
Domain.query.filter_by(organization_id=organization_id).delete()
db.session.bulk_save_objects([
Domain(domain=domain.lower(), organization_id=organization_id)
for domain in domains
])
organization = Organization.query.get(organization_id)
if 'organization_type' in kwargs:
_update_organization_services(organization, 'organization_type', only_where_none=False)
if 'email_branding_id' in kwargs:
_update_organization_services(organization, 'email_branding')
return num_updated
@version_class(
VersionOptions(Service, must_write_history=False),
)
def _update_organization_services(organization, attribute, only_where_none=True):
for service in organization.services:
if getattr(service, attribute) is None or not only_where_none:
setattr(service, attribute, getattr(organization, attribute))
db.session.add(service)
@autocommit
@version_class(Service)
def dao_add_service_to_organization(service, organization_id):
organization = Organization.query.filter_by(
id=organization_id
).one()
service.organization_id = organization_id
service.organization_type = organization.organization_type
db.session.add(service)
def dao_get_users_for_organization(organization_id):
return db.session.query(
User
).join(
User.organizations
).filter(
Organization.id == organization_id,
User.state == 'active'
).order_by(User.created_at).all()
@autocommit
def dao_add_user_to_organization(organization_id, user_id):
organization = dao_get_organization_by_id(organization_id)
user = User.query.filter_by(id=user_id).one()
user.organizations.append(organization)
db.session.add(organization)
return user
@autocommit
def dao_remove_user_from_organization(organization, user):
organization.users.remove(user)

View File

@@ -9,7 +9,7 @@ from sqlalchemy.sql.expression import and_, asc, case, func
from app import db
from app.dao.dao_utils import VersionOptions, autocommit, version_class
from app.dao.date_util import get_current_calendar_year
from app.dao.organisation_dao import dao_get_organisation_by_email_address
from app.dao.organization_dao import dao_get_organization_by_email_address
from app.dao.service_sms_sender_dao import insert_service_sms_sender
from app.dao.service_user_dao import dao_get_service_user
from app.dao.template_folder_dao import dao_get_valid_template_folders_by_id
@@ -27,7 +27,7 @@ from app.models import (
Job,
Notification,
NotificationHistory,
Organisation,
Organization,
Permission,
Service,
ServiceEmailReplyTo,
@@ -96,8 +96,8 @@ def dao_fetch_live_services_data():
data = db.session.query(
Service.id.label('service_id'),
Service.name.label("service_name"),
Organisation.name.label("organisation_name"),
Organisation.organisation_type.label('organisation_type'),
Organization.name.label("organization_name"),
Organization.organization_type.label('organization_type'),
Service.consent_to_research.label('consent_to_research'),
User.name.label('contact_name'),
User.email_address.label('contact_email'),
@@ -121,7 +121,7 @@ def dao_fetch_live_services_data():
AnnualBilling.financial_year_start == most_recent_annual_billing.c.year
)
).outerjoin(
Service.organisation
Service.organization
).outerjoin(
this_year_ft_billing, Service.id == this_year_ft_billing.c.service_id
).outerjoin(
@@ -132,8 +132,8 @@ def dao_fetch_live_services_data():
Service.restricted.is_(False),
).group_by(
Service.id,
Organisation.name,
Organisation.organisation_type,
Organization.name,
Organization.organization_type,
Service.name,
Service.consent_to_research,
Service.count_as_live,
@@ -278,7 +278,7 @@ def dao_create_service(
if service_permissions is None:
service_permissions = DEFAULT_SERVICE_PERMISSIONS
organisation = dao_get_organisation_by_email_address(user.email_address)
organization = dao_get_organization_by_email_address(user.email_address)
from app.dao.permissions_dao import permission_dao
service.users.append(user)
@@ -294,12 +294,12 @@ def dao_create_service(
# do we just add the default - or will we get a value from FE?
insert_service_sms_sender(service, current_app.config['FROM_NUMBER'])
if organisation:
service.organisation_id = organisation.id
service.organisation_type = organisation.organisation_type
if organization:
service.organization_id = organization.id
service.organization_type = organization.organization_type
if organisation.email_branding:
service.email_branding = organisation.email_branding
if organization.email_branding:
service.email_branding = organization.email_branding
service.count_as_live = not user.platform_admin
@@ -376,7 +376,7 @@ def delete_service_and_all_associated_db_objects(service):
db.session.commit()
users = [x for x in service.users]
for user in users:
user.organisations = []
user.organizations = []
service.users.remove(user)
_delete_commit(Service.get_history_model().query.filter_by(id=service.id))
db.session.delete(service)
@@ -553,20 +553,20 @@ def dao_find_services_with_high_failure_rates(start_date, end_date, threshold=10
return query.all()
def get_live_services_with_organisation():
def get_live_services_with_organization():
query = db.session.query(
Service.id.label("service_id"),
Service.name.label("service_name"),
Organisation.id.label("organisation_id"),
Organisation.name.label("organisation_name")
Organization.id.label("organization_id"),
Organization.name.label("organization_name")
).outerjoin(
Service.organisation
Service.organization
).filter(
Service.count_as_live.is_(True),
Service.active.is_(True),
Service.restricted.is_(False)
).order_by(
Organisation.name,
Organization.name,
Service.name
)

View File

@@ -136,12 +136,12 @@ 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
# eagerly load the user's services and organizations, 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'),
joinedload('organizations'),
joinedload('organizations.services'),
joinedload('services.organization'),
).one()
@@ -157,7 +157,7 @@ def dao_archive_user(user):
for service_user in service_users:
db.session.delete(service_user)
user.organisations = []
user.organizations = []
user.auth_type = EMAIL_AUTH_TYPE
user.email_address = get_archived_db_column_value(user.email_address)

View File

@@ -121,9 +121,9 @@ class User(db.Model):
'Service',
secondary='user_to_service',
backref='users')
organisations = db.relationship(
'Organisation',
secondary='user_to_organisation',
organizations = db.relationship(
'Organization',
secondary='user_to_organization',
backref='users')
@validates("mobile_number")
@@ -185,7 +185,7 @@ class User(db.Model):
'email_access_validated_at': self.email_access_validated_at.strftime(DATETIME_FORMAT),
'logged_in_at': get_dt_string_or_none(self.logged_in_at),
'mobile_number': self.mobile_number,
'organisations': [x.id for x in self.organisations if x.active],
'organizations': [x.id for x in self.organizations if x.active],
'password_changed_at': self.password_changed_at.strftime(DATETIME_FORMAT_NO_TIMEZONE),
'permissions': self.get_permissions(),
'platform_admin': self.platform_admin,
@@ -213,12 +213,12 @@ class ServiceUser(db.Model):
)
user_to_organisation = db.Table(
'user_to_organisation',
user_to_organization = db.Table(
'user_to_organization',
db.Model.metadata,
db.Column('user_id', UUID(as_uuid=True), db.ForeignKey('users.id')),
db.Column('organisation_id', UUID(as_uuid=True), db.ForeignKey('organisation.id')),
UniqueConstraint('user_id', 'organisation_id', name='uix_user_to_organisation')
db.Column('organization_id', UUID(as_uuid=True), db.ForeignKey('organization.id')),
UniqueConstraint('user_id', 'organization_id', name='uix_user_to_organization')
)
@@ -310,23 +310,23 @@ class ServicePermissionTypes(db.Model):
class Domain(db.Model):
__tablename__ = "domain"
domain = db.Column(db.String(255), primary_key=True)
organisation_id = db.Column('organisation_id', UUID(as_uuid=True), db.ForeignKey('organisation.id'), nullable=False)
organization_id = db.Column('organization_id', UUID(as_uuid=True), db.ForeignKey('organization.id'), nullable=False)
ORGANISATION_TYPES = [
ORGANIZATION_TYPES = [
"federal", "state", "other"
]
class OrganisationTypes(db.Model):
__tablename__ = 'organisation_types'
class OrganizationTypes(db.Model):
__tablename__ = 'organization_types'
name = db.Column(db.String(255), primary_key=True)
annual_free_sms_fragment_limit = db.Column(db.BigInteger, nullable=False)
class Organisation(db.Model):
__tablename__ = "organisation"
class Organization(db.Model):
__tablename__ = "organization"
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=False)
name = db.Column(db.String(255), nullable=False, unique=True, index=True)
active = db.Column(db.Boolean, nullable=False, default=True)
@@ -343,9 +343,9 @@ class Organisation(db.Model):
agreement_signed_on_behalf_of_name = db.Column(db.String(255), nullable=True)
agreement_signed_on_behalf_of_email_address = db.Column(db.String(255), nullable=True)
agreement_signed_version = db.Column(db.Float, nullable=True)
organisation_type = db.Column(
organization_type = db.Column(
db.String(255),
db.ForeignKey('organisation_types.name'),
db.ForeignKey('organization_types.name'),
unique=False,
nullable=True,
)
@@ -386,7 +386,7 @@ class Organisation(db.Model):
"id": str(self.id),
"name": self.name,
"active": self.active,
"organisation_type": self.organisation_type,
"organization_type": self.organization_type,
"email_branding_id": self.email_branding_id,
"agreement_signed": self.agreement_signed,
"agreement_signed_at": self.agreement_signed_at,
@@ -411,7 +411,7 @@ class Organisation(db.Model):
'active': self.active,
'count_of_live_services': len(self.live_services),
'domains': self.domain_list,
'organisation_type': self.organisation_type,
'organization_type': self.organization_type,
}
@@ -440,9 +440,9 @@ class Service(db.Model, Versioned):
created_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), index=True, nullable=False)
created_by = db.relationship('User', foreign_keys=[created_by_id])
prefix_sms = db.Column(db.Boolean, nullable=False, default=True)
organisation_type = db.Column(
organization_type = db.Column(
db.String(255),
db.ForeignKey('organisation_types.name'),
db.ForeignKey('organization_types.name'),
unique=False,
nullable=True,
)
@@ -456,8 +456,8 @@ class Service(db.Model, Versioned):
go_live_user = db.relationship('User', foreign_keys=[go_live_user_id])
go_live_at = db.Column(db.DateTime, nullable=True)
organisation_id = db.Column(UUID(as_uuid=True), db.ForeignKey('organisation.id'), index=True, nullable=True)
organisation = db.relationship('Organisation', backref='services')
organization_id = db.Column(UUID(as_uuid=True), db.ForeignKey('organization.id'), index=True, nullable=True)
organization = db.relationship('Organization', backref='services')
notes = db.Column(db.Text, nullable=True)
purchase_order_number = db.Column(db.String(255), nullable=True)
@@ -1661,15 +1661,15 @@ class InvitedUser(db.Model):
return self.permissions.split(',')
class InvitedOrganisationUser(db.Model):
__tablename__ = 'invited_organisation_users'
class InvitedOrganizationUser(db.Model):
__tablename__ = 'invited_organization_users'
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
email_address = db.Column(db.String(255), nullable=False)
invited_by_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=False)
invited_by = db.relationship('User')
organisation_id = db.Column(UUID(as_uuid=True), db.ForeignKey('organisation.id'), nullable=False)
organisation = db.relationship('Organisation')
organization_id = db.Column(UUID(as_uuid=True), db.ForeignKey('organization.id'), nullable=False)
organization = db.relationship('Organization')
created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
status = db.Column(
@@ -1684,7 +1684,7 @@ class InvitedOrganisationUser(db.Model):
'id': str(self.id),
'email_address': self.email_address,
'invited_by': str(self.invited_by_id),
'organisation': str(self.organisation_id),
'organization': str(self.organization_id),
'created_at': self.created_at.strftime(DATETIME_FORMAT),
'status': self.status
}

View File

@@ -8,40 +8,40 @@ from app.dao.invited_org_user_dao import (
)
from app.dao.invited_org_user_dao import (
get_invited_org_user_by_id,
get_invited_org_users_for_organisation,
get_invited_org_users_for_organization,
save_invited_org_user,
)
from app.dao.templates_dao import dao_get_template_by_id
from app.errors import InvalidRequest, register_errors
from app.models import EMAIL_TYPE, KEY_TYPE_NORMAL, InvitedOrganisationUser
from app.models import EMAIL_TYPE, KEY_TYPE_NORMAL, InvitedOrganizationUser
from app.notifications.process_notifications import (
persist_notification,
send_notification_to_queue,
)
from app.organisation.organisation_schema import (
from app.organization.organization_schema import (
post_create_invited_org_user_status_schema,
post_update_invited_org_user_status_schema,
)
from app.schema_validation import validate
organisation_invite_blueprint = Blueprint('organisation_invite', __name__)
organization_invite_blueprint = Blueprint('organization_invite', __name__)
register_errors(organisation_invite_blueprint)
register_errors(organization_invite_blueprint)
@organisation_invite_blueprint.route('/organisation/<uuid:organisation_id>/invite', methods=['POST'])
def invite_user_to_org(organisation_id):
@organization_invite_blueprint.route('/organization/<uuid:organization_id>/invite', methods=['POST'])
def invite_user_to_org(organization_id):
data = request.get_json()
validate(data, post_create_invited_org_user_status_schema)
invited_org_user = InvitedOrganisationUser(
invited_org_user = InvitedOrganizationUser(
email_address=data['email_address'],
invited_by_id=data['invited_by'],
organisation_id=organisation_id
organization_id=organization_id
)
save_invited_org_user(invited_org_user)
template = dao_get_template_by_id(current_app.config['ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID'])
template = dao_get_template_by_id(current_app.config['ORGANIZATION_INVITATION_EMAIL_TEMPLATE_ID'])
saved_notification = persist_notification(
template_id=template.id,
@@ -54,7 +54,7 @@ def invite_user_to_org(organisation_id):
if invited_org_user.invited_by.platform_admin
else invited_org_user.invited_by.name
),
'organisation_name': invited_org_user.organisation.name,
'organization_name': invited_org_user.organization.name,
'url': invited_org_user_url(
invited_org_user.id,
data.get('invite_link_host'),
@@ -71,27 +71,27 @@ def invite_user_to_org(organisation_id):
return jsonify(data=invited_org_user.serialize()), 201
@organisation_invite_blueprint.route('/organisation/<uuid:organisation_id>/invite', methods=['GET'])
def get_invited_org_users_by_organisation(organisation_id):
invited_org_users = get_invited_org_users_for_organisation(organisation_id)
@organization_invite_blueprint.route('/organization/<uuid:organization_id>/invite', methods=['GET'])
def get_invited_org_users_by_organization(organization_id):
invited_org_users = get_invited_org_users_for_organization(organization_id)
return jsonify(data=[x.serialize() for x in invited_org_users]), 200
@organisation_invite_blueprint.route(
'/organisation/<uuid:organisation_id>/invite/<invited_org_user_id>',
@organization_invite_blueprint.route(
'/organization/<uuid:organization_id>/invite/<invited_org_user_id>',
methods=['GET']
)
def get_invited_org_user_by_organisation(organisation_id, invited_org_user_id):
invited_org_user = dao_get_invited_org_user(organisation_id, invited_org_user_id)
def get_invited_org_user_by_organization(organization_id, invited_org_user_id):
invited_org_user = dao_get_invited_org_user(organization_id, invited_org_user_id)
return jsonify(data=invited_org_user.serialize()), 200
@organisation_invite_blueprint.route(
'/organisation/<uuid:organisation_id>/invite/<invited_org_user_id>',
@organization_invite_blueprint.route(
'/organization/<uuid:organization_id>/invite/<invited_org_user_id>',
methods=['POST']
)
def update_org_invite_status(organisation_id, invited_org_user_id):
fetched = dao_get_invited_org_user(organisation_id=organisation_id, invited_org_user_id=invited_org_user_id)
def update_org_invite_status(organization_id, invited_org_user_id):
fetched = dao_get_invited_org_user(organization_id=organization_id, invited_org_user_id=invited_org_user_id)
data = request.get_json()
validate(data, post_update_invited_org_user_status_schema)
@@ -112,17 +112,17 @@ def invited_org_user_url(invited_org_user_id, invite_link_host=None):
if invite_link_host is None:
invite_link_host = current_app.config['ADMIN_BASE_URL']
return '{0}/organisation-invitation/{1}'.format(invite_link_host, token)
return '{0}/organization-invitation/{1}'.format(invite_link_host, token)
@organisation_invite_blueprint.route('/invite/organisation/<uuid:invited_org_user_id>', methods=['GET'])
@organization_invite_blueprint.route('/invite/organization/<uuid:invited_org_user_id>', methods=['GET'])
def get_invited_org_user(invited_org_user_id):
invited_user = get_invited_org_user_by_id(invited_org_user_id)
return jsonify(data=invited_user.serialize()), 200
@organisation_invite_blueprint.route('/invite/organisation/<token>', methods=['GET'])
@organisation_invite_blueprint.route('/invite/organisation/check/<token>', methods=['GET'])
@organization_invite_blueprint.route('/invite/organization/<token>', methods=['GET'])
@organization_invite_blueprint.route('/invite/organization/check/<token>', methods=['GET'])
def validate_invitation_token(token):
max_age_seconds = 60 * 60 * 24 * current_app.config['INVITATION_EXPIRATION_DAYS']

View File

@@ -1,33 +1,33 @@
from app.models import INVITED_USER_STATUS_TYPES, ORGANISATION_TYPES
from app.models import INVITED_USER_STATUS_TYPES, ORGANIZATION_TYPES
from app.schema_validation.definitions import uuid
post_create_organisation_schema = {
post_create_organization_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "POST organisation schema",
"description": "POST organization schema",
"type": "object",
"properties": {
"name": {"type": "string"},
"active": {"type": ["boolean", "null"]},
"organisation_type": {"enum": ORGANISATION_TYPES},
"organization_type": {"enum": ORGANIZATION_TYPES},
},
"required": ["name", "organisation_type"]
"required": ["name", "organization_type"]
}
post_update_organisation_schema = {
post_update_organization_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "POST organisation schema",
"description": "POST organization schema",
"type": "object",
"properties": {
"name": {"type": ["string", "null"]},
"active": {"type": ["boolean", "null"]},
"organisation_type": {"enum": ORGANISATION_TYPES},
"organization_type": {"enum": ORGANIZATION_TYPES},
},
"required": []
}
post_link_service_to_organisation_schema = {
post_link_service_to_organization_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "POST link service to organisation schema",
"description": "POST link service to organization schema",
"type": "object",
"properties": {
"service_id": uuid
@@ -38,7 +38,7 @@ post_link_service_to_organisation_schema = {
post_create_invited_org_user_status_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "POST create organisation invite schema",
"description": "POST create organization invite schema",
"type": "object",
"properties": {
"email_address": {"type": "string", "format": "email_address"},
@@ -51,7 +51,7 @@ post_create_invited_org_user_status_schema = {
post_update_invited_org_user_status_schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "POST update organisation invite schema",
"description": "POST update organization invite schema",
"type": "object",
"properties": {
"status": {"enum": INVITED_USER_STATUS_TYPES}

View File

@@ -5,47 +5,47 @@ from sqlalchemy.exc import IntegrityError
from app.config import QueueNames
from app.dao.annual_billing_dao import set_default_free_allowance_for_service
from app.dao.dao_utils import transaction
from app.dao.fact_billing_dao import fetch_usage_year_for_organisation
from app.dao.organisation_dao import (
dao_add_service_to_organisation,
dao_add_user_to_organisation,
dao_create_organisation,
dao_get_organisation_by_email_address,
dao_get_organisation_by_id,
dao_get_organisation_services,
dao_get_organisations,
dao_get_users_for_organisation,
dao_remove_user_from_organisation,
dao_update_organisation,
from app.dao.fact_billing_dao import fetch_usage_year_for_organization
from app.dao.organization_dao import (
dao_add_service_to_organization,
dao_add_user_to_organization,
dao_create_organization,
dao_get_organization_by_email_address,
dao_get_organization_by_id,
dao_get_organization_services,
dao_get_organizations,
dao_get_users_for_organization,
dao_remove_user_from_organization,
dao_update_organization,
)
from app.dao.services_dao import dao_fetch_service_by_id
from app.dao.templates_dao import dao_get_template_by_id
from app.dao.users_dao import get_user_by_id
from app.errors import InvalidRequest, register_errors
from app.models import KEY_TYPE_NORMAL, Organisation
from app.models import KEY_TYPE_NORMAL, Organization
from app.notifications.process_notifications import (
persist_notification,
send_notification_to_queue,
)
from app.organisation.organisation_schema import (
post_create_organisation_schema,
post_link_service_to_organisation_schema,
post_update_organisation_schema,
from app.organization.organization_schema import (
post_create_organization_schema,
post_link_service_to_organization_schema,
post_update_organization_schema,
)
from app.schema_validation import validate
organisation_blueprint = Blueprint('organisation', __name__)
register_errors(organisation_blueprint)
organization_blueprint = Blueprint('organization', __name__)
register_errors(organization_blueprint)
@organisation_blueprint.errorhandler(IntegrityError)
@organization_blueprint.errorhandler(IntegrityError)
def handle_integrity_error(exc):
"""
Handle integrity errors caused by the unique constraint on ix_organisation_name
Handle integrity errors caused by the unique constraint on ix_organization_name
"""
if 'ix_organisation_name' in str(exc):
if 'ix_organization_name' in str(exc):
return jsonify(result="error",
message="Organisation name already exists"), 400
message="Organization name already exists"), 400
if 'duplicate key value violates unique constraint "domain_pkey"' in str(exc):
return jsonify(result='error',
message='Domain already exists'), 400
@@ -54,124 +54,122 @@ def handle_integrity_error(exc):
return jsonify(result='error', message="Internal server error"), 500
@organisation_blueprint.route('', methods=['GET'])
def get_organisations():
organisations = [
org.serialize_for_list() for org in dao_get_organisations()
@organization_blueprint.route('', methods=['GET'])
def get_organizations():
organizations = [
org.serialize_for_list() for org in dao_get_organizations()
]
return jsonify(organisations)
return jsonify(organizations)
@organisation_blueprint.route('/<uuid:organisation_id>', methods=['GET'])
def get_organisation_by_id(organisation_id):
organisation = dao_get_organisation_by_id(organisation_id)
return jsonify(organisation.serialize())
@organization_blueprint.route('/<uuid:organization_id>', methods=['GET'])
def get_organization_by_id(organization_id):
organization = dao_get_organization_by_id(organization_id)
return jsonify(organization.serialize())
@organisation_blueprint.route('/by-domain', methods=['GET'])
def get_organisation_by_domain():
@organization_blueprint.route('/by-domain', methods=['GET'])
def get_organization_by_domain():
domain = request.args.get('domain')
if not domain or '@' in domain:
abort(400)
organisation = dao_get_organisation_by_email_address(
organization = dao_get_organization_by_email_address(
'example@{}'.format(request.args.get('domain'))
)
if not organisation:
if not organization:
abort(404)
return jsonify(organisation.serialize())
return jsonify(organization.serialize())
@organisation_blueprint.route('', methods=['POST'])
def create_organisation():
@organization_blueprint.route('', methods=['POST'])
def create_organization():
data = request.get_json()
validate(data, post_create_organisation_schema)
organisation = Organisation(**data)
dao_create_organisation(organisation)
return jsonify(organisation.serialize()), 201
validate(data, post_create_organization_schema)
organization = Organization(**data)
dao_create_organization(organization)
return jsonify(organization.serialize()), 201
@organisation_blueprint.route('/<uuid:organisation_id>', methods=['POST'])
def update_organisation(organisation_id):
@organization_blueprint.route('/<uuid:organization_id>', methods=['POST'])
def update_organization(organization_id):
data = request.get_json()
validate(data, post_update_organisation_schema)
validate(data, post_update_organization_schema)
result = dao_update_organisation(organisation_id, **data)
result = dao_update_organization(organization_id, **data)
if data.get('agreement_signed') is True:
# if a platform admin has manually adjusted the organisation, don't tell people
# if a platform admin has manually adjusted the organization, don't tell people
if data.get('agreement_signed_by_id'):
send_notifications_on_mou_signed(organisation_id)
send_notifications_on_mou_signed(organization_id)
if result:
return '', 204
else:
raise InvalidRequest("Organisation not found", 404)
raise InvalidRequest("Organization not found", 404)
@organisation_blueprint.route('/<uuid:organisation_id>/service', methods=['POST'])
def link_service_to_organisation(organisation_id):
@organization_blueprint.route('/<uuid:organization_id>/service', methods=['POST'])
def link_service_to_organization(organization_id):
data = request.get_json()
validate(data, post_link_service_to_organisation_schema)
validate(data, post_link_service_to_organization_schema)
service = dao_fetch_service_by_id(data['service_id'])
service.organisation = None
service.organization = None
with transaction():
dao_add_service_to_organisation(service, organisation_id)
dao_add_service_to_organization(service, organization_id)
set_default_free_allowance_for_service(service, year_start=None)
return '', 204
@organisation_blueprint.route('/<uuid:organisation_id>/services', methods=['GET'])
def get_organisation_services(organisation_id):
services = dao_get_organisation_services(organisation_id)
@organization_blueprint.route('/<uuid:organization_id>/services', methods=['GET'])
def get_organization_services(organization_id):
services = dao_get_organization_services(organization_id)
sorted_services = sorted(services, key=lambda s: (-s.active, s.name))
return jsonify([s.serialize_for_org_dashboard() for s in sorted_services])
@organisation_blueprint.route('/<uuid:organisation_id>/services-with-usage', methods=['GET'])
def get_organisation_services_usage(organisation_id):
@organization_blueprint.route('/<uuid:organization_id>/services-with-usage', methods=['GET'])
def get_organization_services_usage(organization_id):
try:
year = int(request.args.get('year', 'none'))
except ValueError:
return jsonify(result='error', message='No valid year provided'), 400
services = fetch_usage_year_for_organisation(organisation_id, year)
services = fetch_usage_year_for_organization(organization_id, year)
list_services = services.values()
sorted_services = sorted(list_services, key=lambda s: (-s['active'], s['service_name'].lower()))
return jsonify(services=sorted_services)
@organisation_blueprint.route('/<uuid:organisation_id>/users/<uuid:user_id>', methods=['POST'])
def add_user_to_organisation(organisation_id, user_id):
new_org_user = dao_add_user_to_organisation(organisation_id, user_id)
@organization_blueprint.route('/<uuid:organization_id>/users/<uuid:user_id>', methods=['POST'])
def add_user_to_organization(organization_id, user_id):
new_org_user = dao_add_user_to_organization(organization_id, user_id)
return jsonify(data=new_org_user.serialize())
@organisation_blueprint.route('/<uuid:organisation_id>/users/<uuid:user_id>', methods=['DELETE'])
def remove_user_from_organisation(organisation_id, user_id):
organisation = dao_get_organisation_by_id(organisation_id)
@organization_blueprint.route('/<uuid:organization_id>/users/<uuid:user_id>', methods=['DELETE'])
def remove_user_from_organization(organization_id, user_id):
organization = dao_get_organization_by_id(organization_id)
user = get_user_by_id(user_id=user_id)
if user not in organisation.users:
if user not in organization.users:
error = 'User not found'
raise InvalidRequest(error, status_code=404)
dao_remove_user_from_organisation(organisation, user)
dao_remove_user_from_organization(organization, user)
return {}, 204
@organisation_blueprint.route('/<uuid:organisation_id>/users', methods=['GET'])
def get_organisation_users(organisation_id):
org_users = dao_get_users_for_organisation(organisation_id)
@organization_blueprint.route('/<uuid:organization_id>/users', methods=['GET'])
def get_organization_users(organization_id):
org_users = dao_get_users_for_organization(organization_id)
return jsonify(data=[x.serialize() for x in org_users])
@@ -188,8 +186,8 @@ def check_request_args(request):
return org_id, name
def send_notifications_on_mou_signed(organisation_id):
organisation = dao_get_organisation_by_id(organisation_id)
def send_notifications_on_mou_signed(organization_id):
organization = dao_get_organization_by_id(organization_id)
notify_service = dao_fetch_service_by_id(current_app.config['NOTIFY_SERVICE_ID'])
def _send_notification(template_id, recipient, personalisation):
@@ -212,16 +210,16 @@ def send_notifications_on_mou_signed(organisation_id):
'mou_link': '{}/agreement/agreement.pdf'.format(
current_app.config['ADMIN_BASE_URL']
),
'org_name': organisation.name,
'org_dashboard_link': '{}/organisations/{}'.format(
'org_name': organization.name,
'org_dashboard_link': '{}/organizations/{}'.format(
current_app.config['ADMIN_BASE_URL'],
organisation.id
organization.id
),
'signed_by_name': organisation.agreement_signed_by.name,
'on_behalf_of_name': organisation.agreement_signed_on_behalf_of_name
'signed_by_name': organization.agreement_signed_by.name,
'on_behalf_of_name': organization.agreement_signed_on_behalf_of_name
}
if not organisation.agreement_signed_on_behalf_of_email_address:
if not organization.agreement_signed_on_behalf_of_email_address:
signer_template_id = 'MOU_SIGNER_RECEIPT_TEMPLATE_ID'
else:
signer_template_id = 'MOU_SIGNED_ON_BEHALF_SIGNER_RECEIPT_TEMPLATE_ID'
@@ -229,13 +227,13 @@ def send_notifications_on_mou_signed(organisation_id):
# let the person who has been signed on behalf of know.
_send_notification(
current_app.config['MOU_SIGNED_ON_BEHALF_ON_BEHALF_RECEIPT_TEMPLATE_ID'],
organisation.agreement_signed_on_behalf_of_email_address,
organization.agreement_signed_on_behalf_of_email_address,
personalisation
)
# let the person who signed know - the template is different depending on if they signed on behalf of someone
_send_notification(
current_app.config[signer_template_id],
organisation.agreement_signed_by.email_address,
organization.agreement_signed_by.email_address,
personalisation
)

View File

@@ -8,7 +8,7 @@ from app.dao.fact_notification_status_dao import (
from app.dao.fact_processing_time_dao import (
get_processing_time_percentage_for_date_range,
)
from app.dao.services_dao import get_live_services_with_organisation
from app.dao.services_dao import get_live_services_with_organization
from app.errors import register_errors
from app.performance_dashboard.performance_dashboard_schema import (
performance_dashboard_request,
@@ -37,7 +37,7 @@ def get_performance_dashboard():
total_notifications, emails, sms = transform_results_into_totals(total_for_all_time)
totals_for_date_range = get_total_notifications_for_date_range(start_date=start_date, end_date=end_date)
processing_time_results = get_processing_time_percentage_for_date_range(start_date=start_date, end_date=end_date)
services = get_live_services_with_organisation()
services = get_live_services_with_organization()
stats = {
"total_notifications": total_notifications,
"email_notifications": emails,
@@ -82,6 +82,6 @@ def transform_services_to_json(services_results):
j = []
for x in services_results:
j.append({"service_id": x.service_id, "service_name": x.service_name,
"organisation_id": x.organisation_id, "organisation_name": x.organisation_name}
"organization_id": x.organization_id, "organization_name": x.organization_name}
)
return j

View File

@@ -77,8 +77,8 @@ def get_data_for_billing_report():
for s in sms_costs:
if float(s.sms_cost) > 0:
entry = {
"organisation_id": str(s.organisation_id) if s.organisation_id else "",
"organisation_name": s.organisation_name or "",
"organization_id": str(s.organization_id) if s.organization_id else "",
"organization_name": s.organization_name or "",
"service_id": str(s.service_id),
"service_name": s.service_name,
"sms_cost": float(s.sms_cost),
@@ -99,8 +99,8 @@ def get_data_for_billing_report():
# sorting first by name == '' means that blank orgs will be sorted last.
result = sorted(combined.values(), key=lambda x: (
x['organisation_name'] == '',
x['organisation_name'],
x['organization_name'] == '',
x['organization_name'],
x['service_name']
))
return jsonify(result)
@@ -158,8 +158,8 @@ def volumes_by_service_report():
report.append({
"service_name": row.service_name,
"service_id": str(row.service_id),
"organisation_name": row.organisation_name if row.organisation_name else '',
"organisation_id": str(row.organisation_id) if row.organisation_id else '',
"organization_name": row.organization_name if row.organization_name else '',
"organization_id": str(row.organization_id) if row.organization_id else '',
"free_allowance": int(row.free_allowance),
"sms_notifications": int(row.sms_notifications),
"sms_chargeable_units": int(row.sms_chargeable_units),

View File

@@ -228,10 +228,10 @@ class ProviderDetailsHistorySchema(BaseSchema):
class ServiceSchema(BaseSchema, UUIDsAsStringsMixin):
created_by = field_for(models.Service, 'created_by', required=True)
organisation_type = field_for(models.Service, 'organisation_type')
organization_type = field_for(models.Service, 'organization_type')
permissions = fields.Method("serialize_service_permissions", "deserialize_service_permissions")
email_branding = field_for(models.Service, 'email_branding')
organisation = field_for(models.Service, 'organisation')
organization = field_for(models.Service, 'organization')
go_live_at = field_for(models.Service, 'go_live_at', format=DATETIME_FORMAT_NO_TIMEZONE)
def serialize_service_permissions(self, service):
@@ -297,7 +297,7 @@ class ServiceSchema(BaseSchema, UUIDsAsStringsMixin):
class DetailedServiceSchema(BaseSchema):
statistics = fields.Dict()
organisation_type = field_for(models.Service, 'organisation_type')
organization_type = field_for(models.Service, 'organization_type')
go_live_at = FlexibleDateTime()
created_at = FlexibleDateTime()
updated_at = FlexibleDateTime()

View File

@@ -25,7 +25,7 @@ from app.dao.fact_notification_status_dao import (
fetch_stats_for_all_services_by_date_range,
)
from app.dao.inbound_numbers_dao import dao_allocate_number_for_service
from app.dao.organisation_dao import dao_get_organisation_by_service_id
from app.dao.organization_dao import dao_get_organization_by_service_id
from app.dao.service_data_retention_dao import (
fetch_service_data_retention,
fetch_service_data_retention_by_id,
@@ -109,7 +109,7 @@ register_errors(service_blueprint)
@service_blueprint.errorhandler(IntegrityError)
def handle_integrity_error(exc):
"""
Handle integrity errors caused by the unique constraint on ix_organisation_name
Handle integrity errors caused by the unique constraint on ix_organization_name
"""
if any(
'duplicate key value violates unique constraint "{}"'.format(constraint) in str(exc)
@@ -794,10 +794,10 @@ def get_service_sms_senders_for_service(service_id):
return jsonify([sms_sender.serialize() for sms_sender in sms_senders]), 200
@service_blueprint.route('/<uuid:service_id>/organisation', methods=['GET'])
def get_organisation_for_service(service_id):
organisation = dao_get_organisation_by_service_id(service_id=service_id)
return jsonify(organisation.serialize() if organisation else {}), 200
@service_blueprint.route('/<uuid:service_id>/organization', methods=['GET'])
def get_organization_for_service(service_id):
organization = dao_get_organization_by_service_id(service_id=service_id)
return jsonify(organization.serialize() if organization else {}), 200
@service_blueprint.route('/<uuid:service_id>/data-retention', methods=['GET'])

View File

@@ -1,7 +1,7 @@
from flask import Blueprint, jsonify, request
from app import db, version
from app.dao.organisation_dao import dao_count_organisations_with_live_services
from app.dao.organization_dao import dao_count_organizations_with_live_services
from app.dao.services_dao import dao_count_live_services
status = Blueprint('status', __name__)
@@ -20,10 +20,10 @@ def show_status():
db_version=get_db_version()), 200
@status.route('/_status/live-service-and-organisation-counts')
def live_service_and_organisation_counts():
@status.route('/_status/live-service-and-organization-counts')
def live_service_and_organization_counts():
return jsonify(
organisations=dao_count_organisations_with_live_services(),
organizations=dao_count_organizations_with_live_services(),
services=dao_count_live_services(),
), 200

View File

@@ -560,8 +560,8 @@ def update_password(user_id):
return jsonify(data=user.serialize()), 200
@user_blueprint.route('/<uuid:user_id>/organisations-and-services', methods=['GET'])
def get_organisations_and_services_for_user(user_id):
@user_blueprint.route('/<uuid:user_id>/organizations-and-services', methods=['GET'])
def get_organizations_and_services_for_user(user_id):
user = get_user_and_accounts(user_id)
data = get_orgs_and_services(user)
return jsonify(data)
@@ -599,20 +599,20 @@ def _create_2fa_url(user, secret_code, next_redirect, email_auth_link_host):
def get_orgs_and_services(user):
return {
'organisations': [
'organizations': [
{
'name': org.name,
'id': org.id,
'count_of_live_services': len(org.live_services),
}
for org in user.organisations if org.active
for org in user.organizations if org.active
],
'services': [
{
'id': service.id,
'name': service.name,
'restricted': service.restricted,
'organisation': service.organisation.id if service.organisation else None,
'organization': service.organization.id if service.organization else None,
}
for service in user.services if service.active
]