Merge pull request #3008 from alphagov/new-choose-service

Split choose service page into live services and trial mode services
This commit is contained in:
Chris Hill-Scott
2019-06-13 17:01:19 +01:00
committed by GitHub
20 changed files with 388 additions and 155 deletions

View File

@@ -49,6 +49,11 @@
margin-top: $gutter / 3;
}
.top-gutter-2-3 {
@extend %top-gutter;
margin-top: $gutter * 2 / 3;
}
%bottom-gutter,
.bottom-gutter {
@extend %contain-floats;

View File

@@ -37,6 +37,7 @@
&-hint {
@include core-19;
margin-top: 5px;
margin: 5px 0 10px 0;
color: $secondary-text-colour;
}
}

View File

@@ -1,7 +1,6 @@
from flask import redirect, render_template, session, url_for
from flask_login import current_user, login_required
from app import user_api_client
from app.main import main
from app.utils import PermanentRedirect
@@ -19,12 +18,8 @@ def services_or_dashboard():
@main.route("/accounts")
@login_required
def choose_account():
orgs_and_services = user_api_client.get_organisations_and_services_for_user(current_user)
return render_template(
'views/choose-account.html',
organisations=orgs_and_services['organisations'],
services_without_organisations=orgs_and_services['services_without_organisations'],
can_add_service=current_user.is_gov_user,
)
@@ -36,17 +31,17 @@ def show_accounts_or_dashboard():
return redirect(url_for('.index'))
service_id = session.get('service_id')
if service_id and (service_id in current_user.services or current_user.platform_admin):
if service_id and (current_user.belongs_to_service(service_id) or current_user.platform_admin):
return redirect(url_for('.service_dashboard', service_id=service_id))
organisation_id = session.get('organisation_id')
if organisation_id and (organisation_id in current_user.organisations or current_user.platform_admin):
if organisation_id and (current_user.belongs_to_organisation(organisation_id) or current_user.platform_admin):
return redirect(url_for('.organisation_dashboard', org_id=organisation_id))
if len(current_user.services) == 1 and not current_user.organisations:
return redirect(url_for('.service_dashboard', service_id=current_user.services[0]))
if len(current_user.service_ids) == 1 and not current_user.organisation_ids:
return redirect(url_for('.service_dashboard', service_id=current_user.service_ids[0]))
if len(current_user.organisations) == 1 and not current_user.services:
return redirect(url_for('.organisation_dashboard', org_id=current_user.organisations[0]))
if len(current_user.organisation_ids) == 1 and not current_user.trial_mode_services:
return redirect(url_for('.organisation_dashboard', org_id=current_user.organisation_ids[0]))
return redirect(url_for('.choose_account'))

View File

@@ -31,12 +31,9 @@ def find_users_by_email():
@login_required
@user_is_platform_admin
def user_information(user_id):
user = User.from_id(user_id)
services = user_api_client.get_services_for_user(user)
return render_template(
'views/find-users/user-information.html',
user=user,
services=services,
user=User.from_id(user_id),
)

View File

@@ -222,7 +222,7 @@ def submit_request_to_go_live(service_id):
volume_sms_formatted=format_if_number(current_service.volume_sms),
volume_letter_formatted=format_if_number(current_service.volume_letter),
research_consent='Yes' if current_service.consent_to_research else 'No',
existing_live='Yes' if user_api_client.user_has_live_services(current_user) else 'No',
existing_live='Yes' if current_user.live_services else 'No',
email_address=current_user.email_address,
),
ticket_type=zendesk_client.TYPE_QUESTION,

View File

@@ -14,7 +14,6 @@ from app import (
service_api_client,
template_folder_api_client,
template_statistics_client,
user_api_client,
)
from app.main import main
from app.main.forms import (
@@ -127,7 +126,7 @@ def choose_template(service_id, template_type='all', template_folder_id=None):
template_type=template_type,
allow_adding_letter_template=current_service.has_permission('letter'),
allow_adding_copy_of_template=(
current_service.all_templates or len(current_user.services) > 1
current_service.all_templates or len(current_user.service_ids) > 1
),
)
option_hints = {template_folder_id: 'current folder'}
@@ -368,10 +367,7 @@ def choose_template_to_copy(
else:
return render_template(
'views/templates/copy.html',
services_templates_and_folders=TemplateLists([
Service(service) for service in
user_api_client.get_services_for_user(current_user)
], user=current_user),
services_templates_and_folders=TemplateLists(current_user),
search_form=SearchByNameForm(),
)
@@ -402,7 +398,7 @@ def copy_template(service_id, template_id):
form=form,
template=template,
heading_action='Add',
services=user_api_client.get_service_ids_for_user(current_user),
services=current_user.service_ids,
)

View File

@@ -56,7 +56,6 @@ class Service(JSONModel):
def __init__(self, _dict):
super().__init__(_dict)
if 'permissions' not in self._dict:
self.permissions = {'email', 'sms', 'letter'}
@@ -94,6 +93,10 @@ class Service(JSONModel):
def trial_mode(self):
return self._dict['restricted']
@property
def live(self):
return not self.trial_mode
def has_permission(self, permission):
return permission in self.permissions

View File

@@ -65,9 +65,9 @@ class TemplateList():
class TemplateLists():
def __init__(self, services, user=None):
def __init__(self, user):
self.services = sorted(
services,
user.services,
key=lambda service: service.name.lower(),
)
self.user = user

View File

@@ -1,4 +1,5 @@
from collections.abc import Sequence
from itertools import chain
from flask import abort, current_app, request, session
from flask_login import AnonymousUserMixin, UserMixin, login_user
@@ -38,11 +39,9 @@ class User(JSONModel, UserMixin):
'failed_login_count',
'logged_in_at',
'mobile_number',
'organisations',
'password_changed_at',
'permissions',
'platform_admin',
'services',
'state',
}
@@ -193,9 +192,9 @@ class User(JSONModel, UserMixin):
return True
if org_id:
return org_id in self.organisations
return org_id in self.organisation_ids
if not permissions:
return service_id in self.services
return service_id in self.service_ids
if service_id:
return any(x in self._permissions.get(service_id, []) for x in permissions)
@@ -223,12 +222,15 @@ class User(JSONModel, UserMixin):
]
def belongs_to_service(self, service_id):
return str(service_id) in self.services
return str(service_id) in self.service_ids
def belongs_to_service_or_403(self, service_id):
if not self.belongs_to_service(service_id):
abort(403)
def belongs_to_organisation(self, organisation_id):
return str(organisation_id) in self.organisation_ids
@property
def locked(self):
return self.failed_login_count >= self.max_failed_login_count
@@ -237,6 +239,71 @@ class User(JSONModel, UserMixin):
def email_domain(self):
return self.email_address.split('@')[-1]
@cached_property
def orgs_and_services(self):
return user_api_client.get_organisations_and_services_for_user(self.id)
@property
def services(self):
return sorted(
self.services_with_organisation + self.services_without_organisations,
key=lambda service: service.name.lower(),
)
@property
def services_with_organisation(self):
from app.models.service import Service
return [
Service(service) for service in
next(chain(
org['services'] for org in self.orgs_and_services['organisations']
), [])
]
@property
def services_without_organisations(self):
from app.models.service import Service
return [
Service(service) for service in
self.orgs_and_services['services_without_organisations']
]
@property
def service_ids(self):
return self._dict['services']
@property
def trial_mode_services(self):
return [
service for service in self.services if service.trial_mode
]
@property
def live_services(self):
return [
service for service in self.services if service.live
]
@property
def live_services_not_belonging_to_users_organisations(self):
from app.models.service import Service
return [
Service(service)
for service in self.orgs_and_services['services_without_organisations']
if not service['restricted']
]
@property
def organisations(self):
return [
Organisation.from_id(organisation['id'])
for organisation in self.orgs_and_services['organisations']
]
@property
def organisation_ids(self):
return self._dict['organisations']
@cached_property
def default_organisation(self):
return Organisation(
@@ -251,6 +318,14 @@ class User(JSONModel, UserMixin):
return 'nhs'
return None
@property
def has_access_to_live_and_trial_mode_services(self):
return (
self.organisations or self.live_services
) and (
self.trial_mode_services
)
@property
def has_nhs_email_address(self):
return self.email_address.lower().endswith((
@@ -267,7 +342,7 @@ class User(JSONModel, UserMixin):
"state": self.state,
"failed_login_count": self.failed_login_count,
"permissions": [x for x in self._permissions],
"organisations": self.organisations,
"organisations": self.organisation_ids,
"current_session_id": self.current_session_id
}
if hasattr(self, '_password'):

View File

@@ -89,7 +89,6 @@ class HeaderNavigation(Navigation):
'letter_branding',
'live_services',
'live_services_csv',
'organisations',
'performance_platform_xlsx',
'platform_admin',
'platform_admin_letter_validation_preview',
@@ -214,6 +213,7 @@ class HeaderNavigation(Navigation):
'organisation_settings',
'organisation_preview_email_branding',
'organisation_preview_letter_branding',
'organisations',
'privacy',
'public_agreement',
'public_download_agreement',

View File

@@ -1,5 +1,3 @@
from itertools import chain
from notifications_python_client.errors import HTTPError
from app.models.roles_and_permissions import (
@@ -184,29 +182,9 @@ class UserApiClient(NotifyAdminAPIClient):
data = {'email': new_email}
self.post(endpoint, data)
def get_organisations_and_services_for_user(self, user):
endpoint = '/user/{}/organisations-and-services'.format(user.id)
def get_organisations_and_services_for_user(self, user_id):
endpoint = '/user/{}/organisations-and-services'.format(user_id)
return self.get(endpoint)
def get_services_for_user(self, user):
orgs_and_services_for_user = self.get_organisations_and_services_for_user(user)
all_services = orgs_and_services_for_user['services_without_organisations'] + next(chain(
org['services'] for org in orgs_and_services_for_user['organisations']
), [])
return sorted(all_services, key=lambda service: service['name'])
def user_has_live_services(self, user):
return any(
not service['restricted'] for service in self.get_services_for_user(user)
)
def get_service_ids_for_user(self, user):
return {
service['id'] for service in self.get_services_for_user(user)
}
def user_belongs_to_service(self, user, service_id):
return str(service_id) in self.get_service_ids_for_user(user)
user_api_client = UserApiClient()

View File

@@ -1,43 +1,119 @@
{% extends "withoutnav_template.html" %}
{% macro service_list(
heading,
show_heading,
organisations=[],
services=[]
) %}
{% if show_heading %}
<div class="grid-row">
<div class="column-one-quarter">
<h2>
{{ heading }}
</h2>
</div>
<div class="column-three-quarters">
<ul>
{% else %}
<ul>
{% endif %}
{% for org in organisations %}
<li class="browse-list-item">
<a href="{{ url_for('.organisation_dashboard', org_id=org.id) }}" class="browse-list-link">{{ org.name }}</a>
<p class="browse-list-hint">
{{ org.live_services|length }}
live service{% if org.live_services|length != 1 %}s{% endif %}
</p>
</li>
{% endfor %}
{% for service in services %}
<li class="browse-list-item">
<a href="{{ url_for('.service_dashboard', service_id=service.id) }}" class="browse-list-link">{{ service.name }}</a>
</li>
{% endfor %}
{% if show_heading %}
</ul>
</div>
</div>
{% else %}
</ul>
{% endif %}
{% if show_add_service_button %}
<div class="js-stick-at-bottom-when-scrolling">
<a href="{{ url_for('.add_service') }}" class="button-secondary">Add a new service</a>
</div>
{% endif %}
<div class="keyline-block"></div>
{% endmacro %}
{% block per_page_title %}
Choose service
{% endblock %}
{% block maincolumn_content %}
<h1 class="heading-large">
<h1 class="heading-large {% if current_user.has_access_to_live_and_trial_mode_services %}visually-hidden{% endif %}">
Choose service
</h1>
<nav class="browse-list">
<ul>
{% for org in organisations %}
<li class="browse-list-item">
<a href="{{ url_for('.organisation_dashboard', org_id=org.id) }}" class="browse-list-link">{{ org.name }}</a>
{% if org.services %}
<ul class="browse-sub-list">
{% for item in org.services %}
<li class="browse-list-sub-item">
<a href="{{ url_for('.service_dashboard', service_id=item.id) }}" class="browse-list-link">{{ item.name }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
<div class ="keyline-block"></div>
{% endfor %}
{% if services_without_organisations %}
{% for item in services_without_organisations %}
<nav class="browse-list {% if current_user.has_access_to_live_and_trial_mode_services %}top-gutter-2-3{% endif %}">
{% if current_user.platform_admin %}
<div class="grid-row">
<div class="column-one-quarter">
<h2>
Platform admin
</h2>
</div>
<ul class="column-three-quarters">
<li class="browse-list-item">
<a href="{{ url_for('.service_dashboard', service_id=item.id) }}" class="browse-list-link">{{ item.name }}</a>
<a href="{{ url_for('.organisations') }}" class="browse-list-link">All organisations</a>
</li>
{% endfor %}
<div class ="keyline-block"></div>
{% endif %}
</ul>
</ul>
</div>
<div class="keyline-block"></div>
{% endif %}
{% if current_user.organisations %}
{{ service_list(
heading='Live services',
show_heading=current_user.trial_mode_services,
organisations=current_user.organisations,
services=current_user.live_services_not_belonging_to_users_organisations
) }}
{% else %}
{{ service_list(
heading='Live services',
show_heading=(current_user.trial_mode_services and current_user.live_services),
services=current_user.live_services
) }}
{% endif %}
{% if current_user.trial_mode_services %}
{{ service_list(
heading='Trial mode services',
show_heading=(current_user.organisations or current_user.live_services),
services=current_user.trial_mode_services
) }}
{% endif %}
</nav>
{% if can_add_service %}
<div class="js-stick-at-bottom-when-scrolling">
{% if current_user.has_access_to_live_and_trial_mode_services %}
<div class="grid-row">
<div class="column-one-quarter">
&nbsp;
</div>
<div class="column-three-quarters">
{% endif %}
<a href="{{ url_for('.add_service') }}" class="button-secondary">Add a new service</a>
{% if current_user.has_access_to_live_and_trial_mode_services %}
</div>
</div>
{% endif %}
</div>
{% endif %}

View File

@@ -12,20 +12,42 @@
{{ user.name }}
</h1>
<p>{{ user.email_address }}</p>
<p>{{ user.mobile_number }}</p>
<h2 class="heading-medium">Services</h2>
<p class="{{ '' if user.mobile_number else 'hint' }}">{{ user.mobile_number or 'No mobile number'}}</p>
<h2 class="heading-medium">Live services</h2>
<nav class="browse-list">
<ul>
{% for service in services %}
<li class="browse-list-item">
<a class="browse-list-hint" href={{url_for('.service_dashboard', service_id=service.id)}}>{{ service.name }}</a>
</li>
{% endfor %}
</ul>
{% if user.live_services %}
<ul>
{% for service in user.live_services %}
<li class="browse-list-item">
<a class="browse-list-hint" href={{url_for('.service_dashboard', service_id=service.id)}}>{{ service.name }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p class="hint">
No live services
</p>
{% endif %}
</nav>
<h2 class="heading-medium">Trial mode services</h2>
<nav class="browse-list">
{% if user.trial_mode_services %}
<ul>
{% for service in user.trial_mode_services %}
<li class="browse-list-item">
<a class="browse-list-hint" href={{url_for('.service_dashboard', service_id=service.id)}}>{{ service.name }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p class="hint">
No services in trial mode
</p>
{% endif %}
</nav>
<h2 class="heading-medium">Last login</h2>
{% if not user.logged_in_at %}
<p>This person has never logged in</p>
<p class="hint">This person has never logged in</p>
{% else %}
<p>Last logged in
<time class="timeago" datetime="{{ user.logged_in_at }}">

View File

@@ -1,35 +1,59 @@
{% extends "views/platform-admin/_base_template.html" %}
{% extends "withoutnav_template.html" %}
{% from "components/live-search.html" import live_search %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/page-header.html" import page_header %}
{% block per_page_title %}
Organisations
All organisations
{% endblock %}
{% block org_page_title %}
Organisations
{% endblock %}
{% block fullwidth_content %}
{% block platform_admin_content %}
<div id="content">
<div class="navigation-service">
<div class="navigation-service-name">
&nbsp;
</div>
<a href="{{ url_for('main.choose_account') }}" class="navigation-service-switch">Switch service</a>
</div>
<h1 class="heading-large">
Organisations
</h1>
{{ live_search(target_selector='.browse-list-item', show=True, form=search_form, label='Search by name') }}
<nav class="browse-list">
<ul>
{% for org in organisations %}
<li class="browse-list-item">
<a href="{{ url_for('main.organisation_dashboard', org_id=org['id']) }}" class="browse-list-link">{{ org['name'] }}</a>
{% if not org['active'] %}
<span class="table-field-status-default heading-medium">- archived</span>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
<div class="js-stick-at-bottom-when-scrolling">
<a href="{{ url_for('main.add_organisation') }}" class="button-secondary">New organisation</a>
<main role="main">
<div class="grid-row top-gutter-2-3">
<div class="column-one-quarter">
<h1>
All organisations
</h1>
</div>
<div class="column-three-quarters">
{{ live_search(target_selector='.browse-list-item', show=True, form=search_form, label='Search by name') }}
<nav class="browse-list">
<ul>
{% for org in organisations %}
<li class="browse-list-item">
<a href="{{ url_for('main.organisation_dashboard', org_id=org['id']) }}" class="browse-list-link">{{ org['name'] }}</a>
{% if not org['active'] %}
<span class="table-field-status-default heading-medium">- archived</span>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
</div>
</div>
<div class="js-stick-at-bottom-when-scrolling">
<div class="grid-row">
<div class="column-one-quarter">
&nbsp;
</div>
<div class="column-three-quarters">
<a href="{{ url_for('main.add_organisation') }}" class="button-secondary">New organisation</a>
</div>
</div>
</div>
</main>
</div>
{% endblock %}

View File

@@ -15,7 +15,6 @@
('Summary', url_for('main.platform_admin')),
('Live services', url_for('main.live_services')),
('Trial mode services', url_for('main.trial_services')),
('Organisations', url_for('main.organisations')),
('Providers', url_for('main.view_providers')),
('Reports', url_for('main.platform_admin_reports')),
('Email branding', url_for('main.email_branding')),

View File

@@ -15,16 +15,16 @@ SAMPLE_DATA = {
'name': 'org_1',
'id': 'o1',
'services': [
{'name': 'org_service_1', 'id': 'os1'},
{'name': 'org_service_2', 'id': 'os2'},
{'name': 'org_service_3', 'id': 'os3'},
{'name': 'org_service_1', 'id': 'os1', 'restricted': False},
{'name': 'org_service_2', 'id': 'os2', 'restricted': False},
{'name': 'org_service_3', 'id': 'os3', 'restricted': True},
]
},
{
'name': 'org_2',
'id': 'o2',
'services': [
{'name': 'org_service_4', 'id': 'os4'},
{'name': 'org_service_4', 'id': 'os4', 'restricted': False},
]
},
{
@@ -34,9 +34,9 @@ SAMPLE_DATA = {
}
],
'services_without_organisations': [
{'name': 'service_1', 'id': 's1'},
{'name': 'service_2', 'id': 's2'},
{'name': 'service_3', 'id': 's3'},
{'name': 'service_1', 'id': 's1', 'restricted': False},
{'name': 'service_2', 'id': 's2', 'restricted': False},
{'name': 'service_3', 'id': 's3', 'restricted': True},
]
}
@@ -51,45 +51,58 @@ def mock_get_orgs_and_services(mocker):
def test_choose_account_should_show_choose_accounts_page(
client_request,
mock_get_orgs_and_services
mock_get_orgs_and_services,
mock_get_organisation,
mock_get_organisation_services,
):
resp = client_request.get('main.choose_account')
page = resp.find('div', {'id': 'content'}).main
assert normalize_spaces(page.h1.text) == 'Choose service'
outer_list_items = page.nav.ul.find_all('li', recursive=False)
assert len(outer_list_items) == 6
outer_list_items = page.select('nav ul')[0].select('li')
assert len(outer_list_items) == 5
# first org
assert outer_list_items[0].a.text == 'org_1'
assert outer_list_items[0].a.text == 'Org 1'
assert outer_list_items[0].a['href'] == url_for('.organisation_dashboard', org_id='o1')
outer_list_orgs = outer_list_items[0].ul
assert ' '.join(outer_list_orgs.stripped_strings) == 'org_service_1 org_service_2 org_service_3'
assert normalize_spaces(outer_list_items[0].select_one('.browse-list-hint').text) == (
'1 live service'
)
# second org
assert outer_list_items[1].a.text == 'org_2'
assert outer_list_items[1].a.text == 'Org 2'
assert outer_list_items[1].a['href'] == url_for('.organisation_dashboard', org_id='o2')
outer_list_orgs = outer_list_items[1].ul
assert ' '.join(outer_list_orgs.stripped_strings) == 'org_service_4'
assert normalize_spaces(outer_list_items[1].select_one('.browse-list-hint').text) == (
'2 live services'
)
# third org
assert outer_list_items[2].a.text == 'org_3'
assert outer_list_items[2].a.text == 'Org 3'
assert outer_list_items[2].a['href'] == url_for('.organisation_dashboard', org_id='o3')
assert not outer_list_items[2].ul # org 3 has no services
assert normalize_spaces(outer_list_items[2].select_one('.browse-list-hint').text) == (
'0 live services'
)
# orphaned services
# orphaned live services
assert outer_list_items[3].a.text == 'service_1'
assert outer_list_items[3].a['href'] == url_for('.service_dashboard', service_id='s1')
assert outer_list_items[4].a.text == 'service_2'
assert outer_list_items[4].a['href'] == url_for('.service_dashboard', service_id='s2')
assert outer_list_items[5].a.text == 'service_3'
assert outer_list_items[5].a['href'] == url_for('.service_dashboard', service_id='s3')
# orphaned trial services
trial_services_list_items = page.select('nav ul')[1].select('li')
assert len(trial_services_list_items) == 2
assert trial_services_list_items[0].a.text == 'org_service_3'
assert trial_services_list_items[0].a['href'] == url_for('.service_dashboard', service_id='os3')
assert trial_services_list_items[1].a.text == 'service_3'
assert trial_services_list_items[1].a['href'] == url_for('.service_dashboard', service_id='s3')
def test_choose_account_should_show_choose_accounts_page_if_no_services(
client_request,
mock_get_orgs_and_services
mock_get_orgs_and_services,
mock_get_organisation,
mock_get_organisation_services,
):
mock_get_orgs_and_services.return_value = {
'organisations': [],
@@ -106,9 +119,27 @@ def test_choose_account_should_show_choose_accounts_page_if_no_services(
assert add_service_link['href'] == url_for('main.add_service')
def test_choose_account_should_should_organisations_link_for_platform_admin(
client_request,
platform_admin_user,
mock_get_orgs_and_services,
mock_get_organisation,
mock_get_organisation_services,
):
client_request.login(platform_admin_user)
page = client_request.get('main.choose_account')
first_link = page.select_one('.browse-list-item a')
assert first_link.text == 'All organisations'
assert first_link['href'] == url_for('main.organisations')
def test_choose_account_should_show_back_to_service_link(
client_request,
mock_get_orgs_and_services
mock_get_orgs_and_services,
mock_get_organisation,
mock_get_organisation_services,
):
resp = client_request.get('main.choose_account')
@@ -122,7 +153,9 @@ def test_choose_account_should_show_back_to_service_link(
def test_choose_account_should_not_show_back_to_service_link_if_no_service_in_session(
client,
client_request,
mock_get_orgs_and_services
mock_get_orgs_and_services,
mock_get_organisation,
mock_get_organisation_services,
):
with client.session_transaction() as session:
session['service_id'] = None
@@ -152,6 +185,8 @@ def test_choose_account_should_not_show_back_to_service_link_if_service_archived
client_request,
service_one,
mock_get_orgs_and_services,
mock_get_organisation,
mock_get_organisation_services,
active,
):
service_one['active'] = active

View File

@@ -16,7 +16,12 @@ def user_with_orgs_and_services(num_orgs, num_services, platform_admin=False):
@pytest.mark.parametrize('num_orgs,num_services,endpoint,endpoint_kwargs', [
(0, 0, '.choose_account', {}),
(0, 2, '.choose_account', {}),
(1, 1, '.choose_account', {}),
# assumption is that live service is part of users organisation
# real users shouldnt have orphaned live services, or access to
# services belonging to other organisations
(1, 1, '.organisation_dashboard', {'org_id': 'org1'}),
(2, 0, '.choose_account', {}),
(0, 1, '.service_dashboard', {'service_id': 'service1'}),
(1, 0, '.organisation_dashboard', {'org_id': 'org1'}),
@@ -24,6 +29,7 @@ def user_with_orgs_and_services(num_orgs, num_services, platform_admin=False):
def test_show_accounts_or_dashboard_redirects_to_choose_account_or_service_dashboard(
client,
mocker,
mock_get_non_empty_organisations_and_services_for_user,
num_orgs,
num_services,
endpoint,
@@ -72,6 +78,7 @@ def test_show_accounts_or_dashboard_redirects_if_org_in_session(client, mocker):
def test_show_accounts_or_dashboard_doesnt_redirect_to_service_dashboard_if_user_not_part_of_service_in_session(
client,
mocker,
mock_get_non_empty_organisations_and_services_for_user,
mock_get_service
):
client.login(user_with_orgs_and_services(num_orgs=1, num_services=1), mocker=mocker)
@@ -82,12 +89,13 @@ def test_show_accounts_or_dashboard_doesnt_redirect_to_service_dashboard_if_user
response = client.get(url_for('.show_accounts_or_dashboard'))
assert response.status_code == 302
assert response.location == url_for('main.choose_account', _external=True)
assert response.location == url_for('main.organisation_dashboard', org_id='org1', _external=True)
def test_show_accounts_or_dashboard_doesnt_redirect_to_org_dashboard_if_user_not_part_of_org_in_session(
client,
mocker
mocker,
mock_get_non_empty_organisations_and_services_for_user,
):
client.login(user_with_orgs_and_services(num_orgs=1, num_services=1), mocker=mocker)
with client.session_transaction() as session:
@@ -97,7 +105,7 @@ def test_show_accounts_or_dashboard_doesnt_redirect_to_org_dashboard_if_user_not
response = client.get(url_for('.show_accounts_or_dashboard'))
assert response.status_code == 302
assert response.location == url_for('main.choose_account', _external=True)
assert response.location == url_for('main.organisation_dashboard', org_id='org1', _external=True)
def test_show_accounts_or_dashboard_redirects_if_not_logged_in(

View File

@@ -37,7 +37,7 @@ def test_organisation_page_shows_all_organisations(
assert normalize_spaces(
page.select_one('h1').text
) == "Organisations"
) == "All organisations"
for index, org in enumerate(orgs):
assert page.select('a.browse-list-link')[index].text == org['name']

View File

@@ -101,8 +101,8 @@ def test_user_information_page_shows_information_about_user(
mocker.patch(
'app.user_api_client.get_organisations_and_services_for_user',
return_value={'organisations': [], 'services_without_organisations': [
{"id": 1, "name": "Fresh Orchard Juice"},
{"id": 2, "name": "Nature Therapy"},
{"id": 1, "name": "Fresh Orchard Juice", "restricted": True},
{"id": 2, "name": "Nature Therapy", "restricted": False},
]},
autospec=True
)
@@ -116,10 +116,12 @@ def test_user_information_page_shows_information_about_user(
assert document.xpath("//p/text()[normalize-space()='test@gov.uk']")
assert document.xpath("//p/text()[normalize-space()='+447700900986']")
assert document.xpath("//h2/text()[normalize-space()='Services']")
assert document.xpath("//a/text()[normalize-space()='Fresh Orchard Juice']")
assert document.xpath("//h2/text()[normalize-space()='Live services']")
assert document.xpath("//a/text()[normalize-space()='Nature Therapy']")
assert document.xpath("//h2/text()[normalize-space()='Trial mode services']")
assert document.xpath("//a/text()[normalize-space()='Fresh Orchard Juice']")
assert document.xpath("//h2/text()[normalize-space()='Last login']")
assert not document.xpath("//p/text()[normalize-space()='0 failed login attempts']")
@@ -137,8 +139,8 @@ def test_user_information_page_displays_if_there_are_failed_login_attempts(
mocker.patch(
'app.user_api_client.get_organisations_and_services_for_user',
return_value={'organisations': [], 'services_without_organisations': [
{"id": 1, "name": "Fresh Orchard Juice"},
{"id": 2, "name": "Nature Therapy"},
{"id": 1, "name": "Fresh Orchard Juice", "restricted": True},
{"id": 2, "name": "Nature Therapy", "restricted": True},
]},
autospec=True
)

View File

@@ -3136,7 +3136,11 @@ def mock_get_organisation(
def _get_organisation(org_id):
return organisation_json(
org_id,
'Org 1',
{
'o1': 'Org 1',
'o2': 'Org 2',
'o3': 'Org 3',
}.get(org_id, 'Org 1'),
email_branding_id=email_branding_id,
letter_branding_id=letter_branding_id,
)
@@ -3199,6 +3203,18 @@ def mock_update_service_organisation(mocker):
@pytest.fixture(scope='function')
def mock_get_organisation_services(mocker, api_user_active):
def _get_organisation_services(organisation_id):
if organisation_id == 'o1':
return [
service_json('12345', 'service one', restricted=False),
service_json('67890', 'service two'),
service_json('abcde', 'service three'),
]
if organisation_id == 'o2':
return [
service_json('12345', 'service one', restricted=False),
service_json('67890', 'service two', restricted=False),
service_json('abcde', 'service three'),
]
return [
service_json('12345', 'service one'),
service_json('67890', 'service two'),
@@ -3339,6 +3355,7 @@ def mock_get_non_empty_organisations_and_services_for_user(mocker, organisation_
return [{
'name': '{} {}'.format(name, i),
'id': SERVICE_TWO_ID,
'restricted': False,
} for i in range(1, 3)]
def _get_orgs_and_services(user_id):