mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-16 20:49:00 -04:00
Merge pull request #3044 from alphagov/count-orgs-and-services-on-choose
Add count of organisations and live services for platform admin user
This commit is contained in:
@@ -3,6 +3,7 @@ import os
|
||||
import urllib
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from functools import partial
|
||||
from numbers import Number
|
||||
from time import monotonic
|
||||
|
||||
import ago
|
||||
@@ -345,6 +346,14 @@ def format_delta(date):
|
||||
)
|
||||
|
||||
|
||||
def format_thousands(value):
|
||||
if isinstance(value, Number):
|
||||
return '{:,.0f}'.format(value)
|
||||
if value is None:
|
||||
return ''
|
||||
return value
|
||||
|
||||
|
||||
def valid_phone_number(phone_number):
|
||||
try:
|
||||
validate_phone_number(phone_number)
|
||||
@@ -688,6 +697,7 @@ def add_template_filters(application):
|
||||
formatted_list,
|
||||
nl2br,
|
||||
format_phone_number_human_readable,
|
||||
format_thousands,
|
||||
id_safe,
|
||||
]:
|
||||
application.add_template_filter(fn)
|
||||
|
||||
@@ -34,6 +34,7 @@ from wtforms.fields.html5 import EmailField, SearchField, TelField
|
||||
from wtforms.validators import URL, DataRequired, Length, Optional, Regexp
|
||||
from wtforms.widgets import CheckboxInput, ListWidget
|
||||
|
||||
from app import format_thousands
|
||||
from app.main.validators import (
|
||||
Blacklist,
|
||||
CsvFileValidator,
|
||||
@@ -209,9 +210,9 @@ class ForgivingIntegerField(StringField):
|
||||
error = None
|
||||
try:
|
||||
if int(self.data) > self.POSTGRES_MAX_INT:
|
||||
error = 'Number of {} must be {:,.0f} or less'.format(
|
||||
error = 'Number of {} must be {} or less'.format(
|
||||
self.things,
|
||||
self.POSTGRES_MAX_INT,
|
||||
format_thousands(self.POSTGRES_MAX_INT),
|
||||
)
|
||||
except ValueError:
|
||||
error = 'Enter the number of {} {}'.format(
|
||||
@@ -234,7 +235,7 @@ class ForgivingIntegerField(StringField):
|
||||
|
||||
try:
|
||||
value = int(self.data)
|
||||
value = '{:,.0f}'.format(value)
|
||||
value = format_thousands(value)
|
||||
except (ValueError, TypeError):
|
||||
value = self.data if self.data is not None else ''
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from flask import redirect, render_template, session, url_for
|
||||
from flask_login import current_user
|
||||
|
||||
from app import status_api_client
|
||||
from app.main import main
|
||||
from app.models.organisation import Organisations
|
||||
from app.utils import PermanentRedirect, user_is_logged_in
|
||||
|
||||
|
||||
@@ -18,9 +20,17 @@ def services_or_dashboard():
|
||||
@main.route("/accounts")
|
||||
@user_is_logged_in
|
||||
def choose_account():
|
||||
org_count, live_service_count = None, None
|
||||
if current_user.platform_admin:
|
||||
org_count, live_service_count = (
|
||||
len(Organisations()),
|
||||
status_api_client.get_count_of_live_services_and_organisations()['services'],
|
||||
)
|
||||
return render_template(
|
||||
'views/choose-account.html',
|
||||
can_add_service=current_user.is_gov_user,
|
||||
org_count=org_count,
|
||||
live_service_count=live_service_count,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ from notifications_utils.template import Template, WithSubjectTemplate
|
||||
from app import (
|
||||
current_service,
|
||||
format_datetime_short,
|
||||
format_thousands,
|
||||
job_api_client,
|
||||
notification_api_client,
|
||||
service_api_client,
|
||||
@@ -186,8 +187,8 @@ def cancel_letter_job(service_id, job_id):
|
||||
except HTTPError as e:
|
||||
flash(e.message, 'dangerous')
|
||||
return redirect(url_for('main.view_job', service_id=service_id, job_id=job_id))
|
||||
flash("Cancelled {:,.0f} letters from {}".format(
|
||||
number_of_letters, job['original_file_name']
|
||||
flash("Cancelled {} letters from {}".format(
|
||||
format_thousands(number_of_letters), job['original_file_name']
|
||||
), 'default_with_tick')
|
||||
return redirect(url_for('main.service_dashboard', service_id=service_id))
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ from app import (
|
||||
billing_api_client,
|
||||
current_service,
|
||||
email_branding_client,
|
||||
format_thousands,
|
||||
inbound_number_client,
|
||||
letter_branding_client,
|
||||
notification_api_client,
|
||||
@@ -212,9 +213,9 @@ def submit_request_to_go_live(service_id):
|
||||
service_dashboard=url_for('main.service_dashboard', service_id=current_service.id, _external=True),
|
||||
organisation_type=str(current_service.organisation_type).title(),
|
||||
agreement=current_service.organisation.as_human_readable(current_user.email_domain),
|
||||
volume_email_formatted=format_if_number(current_service.volume_email),
|
||||
volume_sms_formatted=format_if_number(current_service.volume_sms),
|
||||
volume_letter_formatted=format_if_number(current_service.volume_letter),
|
||||
volume_email_formatted=format_thousands(current_service.volume_email),
|
||||
volume_sms_formatted=format_thousands(current_service.volume_sms),
|
||||
volume_letter_formatted=format_thousands(current_service.volume_letter),
|
||||
research_consent='Yes' if current_service.consent_to_research else 'No',
|
||||
existing_live='Yes' if current_user.live_services else 'No',
|
||||
email_address=current_user.email_address,
|
||||
@@ -262,7 +263,7 @@ def service_switch_count_as_live(service_id):
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
current_service.update(count_as_live=form.enabled.data)
|
||||
current_service.update_count_as_live(form.enabled.data)
|
||||
return redirect(url_for('.service_settings', service_id=service_id))
|
||||
|
||||
return render_template(
|
||||
@@ -1121,7 +1122,3 @@ def check_contact_details_type(contact_details):
|
||||
return 'email_address'
|
||||
else:
|
||||
return 'phone_number'
|
||||
|
||||
|
||||
def format_if_number(value):
|
||||
return '{:,.0f}'.format(value) if isinstance(value, int) else ''
|
||||
|
||||
@@ -65,6 +65,9 @@ class Service(JSONModel):
|
||||
def update(self, **kwargs):
|
||||
return service_api_client.update_service(self.id, **kwargs)
|
||||
|
||||
def update_count_as_live(self, count_as_live):
|
||||
return service_api_client.update_count_as_live(self.id, count_as_live=count_as_live)
|
||||
|
||||
def update_status(self, live):
|
||||
return service_api_client.update_status(self.id, live=live)
|
||||
|
||||
|
||||
@@ -114,6 +114,13 @@ class ServiceAPIClient(NotifyAdminAPIClient):
|
||||
go_live_at=str(datetime.utcnow()) if live else None
|
||||
)
|
||||
|
||||
@cache.delete('live-service-and-organisation-counts')
|
||||
def update_count_as_live(self, service_id, count_as_live):
|
||||
return self.update_service(
|
||||
service_id,
|
||||
count_as_live=count_as_live,
|
||||
)
|
||||
|
||||
# This method is not cached because it calls through to one which is
|
||||
def update_service_with_properties(self, service_id, properties):
|
||||
return self.update_service(service_id, **properties)
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
<ul class="column-three-quarters">
|
||||
<li class="browse-list-item">
|
||||
<a href="{{ url_for('.organisations') }}" class="browse-list-link">All organisations</a>
|
||||
<p class="browse-list-hint">
|
||||
{{ org_count|format_thousands }} organisations, {{ live_service_count|format_thousands }} live services
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -120,12 +120,12 @@
|
||||
<div class="grid-row bottom-gutter">
|
||||
<div class="column-half">
|
||||
<h3 class="visually-hidden">Services</h3>
|
||||
<div class="product-page-big-number">{{ counts.services }}</div>
|
||||
<div class="product-page-big-number">{{ counts.services|format_thousands }}</div>
|
||||
services
|
||||
</div>
|
||||
<div class="column-half">
|
||||
<h3 class="visually-hidden">Organisations</h3>
|
||||
<div class="product-page-big-number">{{ counts.organisations }}</div>
|
||||
<div class="product-page-big-number">{{ counts.organisations|format_thousands }}</div>
|
||||
organisations
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user