Time Utilities
Location:app/utils/time.py
Functions for working with dates, times, and financial years.
get_current_financial_year
Returns the current financial year (April to March).int - The current financial year
Logic: Returns current year if month > 3 (April onwards), otherwise returns previous year
percentage_through_current_financial_year
Calculates how far through the current financial year as a percentage.float - Percentage (0.001-100) through the financial year
Use Case: Budget tracking, rate limiting calculations based on annual allowances
is_less_than_days_ago
Checks if a date is within the last N days.date_from_db(datetime): Date to checknumber_of_days(int): Number of days threshold
bool - True if date is less than N days ago
to_utc_string
Converts an aware datetime to UTC string format.aware_datetime(datetime): Timezone-aware datetime
str - UTC datetime string in format %Y-%m-%dT%H:%M:%S.%fZ
Note: Matches app.utils.DATETIME_FORMAT in the API codebase
str_no_tz
Converts aware datetime to string without timezone info (for backwards compatibility).aware_datetime(datetime): Timezone-aware datetime
str - String representation without timezone
isoformat_no_tz
Converts aware datetime to ISO format without timezone.aware_datetime(datetime): Timezone-aware datetime
str - ISO format string without timezone
User Utilities
Location:app/utils/user.py
Functions and decorators for user authentication and authorization.
Decorators
user_is_logged_in
Alias for Flask-Login’slogin_required decorator.
user_has_permissions
Requires user to have specific permissions.*permissions(str): Required permission names**permission_kwargs: Additional permission arguments
user_is_gov_user
Requires user to have a government email address.user_is_platform_admin
Requires user to be a platform administrator.Email Validation
is_gov_user
Checks if an email address belongs to a government user.email_address(str): Email address to check
bool - True if email is from government domain or approved organisation
Logic: Checks against:
- Government email domains from
email_domains.txt - Organisation domains from API
CSV Utilities
Location:app/utils/csv.py
Functions for CSV file processing and validation.
get_errors_for_csv
Validates CSV recipients and returns user-friendly error messages.recipients(RecipientCSV): Parsed CSV recipientstemplate_type(str): “email”, “sms”, or “letter”
list[str] - List of human-readable error messages
Error Types Detected:
- Invalid recipients (bad email addresses, phone numbers)
- Missing data in required columns
- Messages too long
- Empty messages
- QR codes with too many characters
generate_notifications_csv
Generates a CSV export of notifications with original upload data.service_id(str): Service IDjob_id(str, optional): Job ID for job-specific exporttemplate_type(str): Template typepage_size(int): Notifications per pagepage(int): Starting page (default: 1)
- Row number
- Original upload columns
- Template, Type, Job, Status, Time
- Recipient, Reference, Template, Type, Sent by, Sent by email, Job, Status, Time, API key name
Branding Utilities
Location:app/utils/branding.py
Functions for managing email and letter branding options.
get_email_choices
Returns available email branding choices for a service.service(Service): Service object
(id, name) tuples
Logic:
- Offers GOV.UK branding if service can use it and doesn’t currently
- Offers “GOV.UK and ” if service has organisation
- Offers NHS branding if service is NHS and doesn’t currently use it
- Offers brandings from service’s branding pool
- Offers organisation branding if no branding pool
get_letter_choices
Returns available letter branding choices for a service.service(Service): Service object
(id, name) tuples
Logic:
- Offers NHS branding if service is NHS and doesn’t currently use it
- Offers brandings from letter branding pool
- Offers organisation branding if no branding pool
letter_filename_for_db_from_logo_key
Extracts filename without extension from logo key for database storage.logo_key(str): Full logo file path
str - Filename without extension
Note: For letters, database stores filename without extension (unlike email branding which stores full path)
Pagination Utilities
Location:app/utils/pagination.py
Functions for handling paginated results.
get_page_from_request
Extracts page number from request arguments.int - Page number from request args, or 1 if not specified, or None if invalid
generate_previous_dict
Generates previous page link data.view(str): Flask view nameservice_id(str): Service IDpage(int): Current page numberurl_args(dict, optional): Additional URL parameters
dict - Previous page link data
generate_next_dict
Generates next page link data.view(str): Flask view nameservice_id(str): Service IDpage(int): Current page numberurl_args(dict, optional): Additional URL parameters
dict - Next page link data
generate_optional_previous_and_next_dicts
Generates both previous and next page links, returning None for unavailable pages.view(str): Flask view nameservice_id(str): Service IDpage(int): Current page numbernum_pages(int): Total number of pagesurl_args(dict, optional): Additional URL parameters
tuple[dict | None, dict | None] - (previous_page, next_page) or None if not available
Template Utilities
Location:app/utils/templates.py
Functions for template rendering and manipulation.
get_sample_template
Creates a minimal template object for a given type.template_type(str): “email”, “sms”, or “letter”
get_template
Creates a fully configured template object with service branding and settings.template(dict): Template data from APIservice(Service): Service objectshow_recipient(bool): Whether to show recipient in previewletter_preview_url(str, optional): URL for letter preview imagespage_count(int, optional): Page count for precompiled lettersredact_missing_personalisation(bool): Whether to redact missing placeholdersemail_reply_to(str, optional): Reply-to email addresssms_sender(str, optional): SMS sender nameinclude_letter_edit_ui_overlay(bool): Include letter editing UI
TemplateChange
Analyzes changes between template versions.has_different_placeholders(bool): Whether placeholders changedplaceholders_added(OrderedSet): New placeholdersplaceholders_removed(OrderedSet): Removed placeholders (excluding email files)email_files_removed(OrderedSet): Removed email file attachmentsis_breaking_change(bool): Whether change would break API integrations
- Adding placeholders when service has API keys
- Removing email file attachments