From f0e8661e343d6e9499e39bc336c111db3036bac9 Mon Sep 17 00:00:00 2001 From: Ken Tsang Date: Thu, 8 Feb 2018 12:19:21 +0000 Subject: [PATCH] Add organisations pages to show orgs and create/edit them --- app/main/__init__.py | 1 + app/main/forms.py | 5 + app/main/views/organisations.py | 63 +++++++++++ .../organisations/manage-organisation.html | 27 +++++ .../views/organisations/organisations.html | 28 +++++ tests/app/main/views/test_organisations.py | 104 ++++++++++++++++++ 6 files changed, 228 insertions(+) create mode 100644 app/main/views/organisations.py create mode 100644 app/templates/views/organisations/manage-organisation.html create mode 100644 app/templates/views/organisations/organisations.html create mode 100644 tests/app/main/views/test_organisations.py diff --git a/app/main/__init__.py b/app/main/__init__.py index ceea4e4b0..4ec54c1e2 100644 --- a/app/main/__init__.py +++ b/app/main/__init__.py @@ -30,6 +30,7 @@ from app.main.views import ( # noqa letter_jobs, email_branding, conversation, + organisations, notifications, inbound_number ) diff --git a/app/main/forms.py b/app/main/forms.py index 2004d1661..537b11ba7 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -665,6 +665,11 @@ class ServiceCreateEmailBranding(StripWhitespaceForm): file = FileField_wtf('Upload a PNG logo', validators=[FileAllowed(['png'], 'PNG Images only!')]) +class CreateOrUpdateOrganisation(StripWhitespaceForm): + + name = StringField('Name', validators=[DataRequired()]) + + class LetterBranding(StripWhitespaceForm): def __init__(self, choices=[], *args, **kwargs): diff --git a/app/main/views/organisations.py b/app/main/views/organisations.py new file mode 100644 index 000000000..013dbcd4a --- /dev/null +++ b/app/main/views/organisations.py @@ -0,0 +1,63 @@ +from flask import redirect, render_template, url_for +from flask_login import login_required + +from app import organisations_client +from app.main import main +from app.main.forms import CreateOrUpdateOrganisation +from app.utils import user_has_permissions + + +@main.route("/organisations", methods=['GET']) +@login_required +@user_has_permissions(admin_override=True) +def organisations(): + orgs = organisations_client.get_organisations() + + return render_template( + 'views/organisations/organisations.html', + organisations=orgs + ) + + +@main.route("/organisation//edit", methods=['GET', 'POST']) +@login_required +@user_has_permissions(admin_override=True) +def update_organisation(org_id): + org = organisations_client.get_organisation(org_id) + + form = CreateOrUpdateOrganisation() + + if form.validate_on_submit(): + organisations_client.update_organisation( + org_id=org_id, + name=form.name.data + ) + + return redirect(url_for('.organisations')) + + form.name.data = org['name'] + + return render_template( + 'views/organisations/manage-organisation.html', + form=form, + organisation=org + ) + + +@main.route("/organisations/create", methods=['GET', 'POST']) +@login_required +@user_has_permissions(admin_override=True) +def create_organisation(): + form = CreateOrUpdateOrganisation() + + if form.validate_on_submit(): + organisations_client.create_organisation( + name=form.name.data, + ) + + return redirect(url_for('.organisations')) + + return render_template( + 'views/organisations/manage-organisation.html', + form=form + ) diff --git a/app/templates/views/organisations/manage-organisation.html b/app/templates/views/organisations/manage-organisation.html new file mode 100644 index 000000000..a2b52a0d8 --- /dev/null +++ b/app/templates/views/organisations/manage-organisation.html @@ -0,0 +1,27 @@ +{% extends "views/platform-admin/_base_template.html" %} +{% from "components/page-footer.html" import page_footer %} +{% from "components/textbox.html" import textbox, colour_textbox %} + +{% block service_page_title %} + {{ '{} an organisations'.format('Update' if organisation else 'Create')}} +{% endblock %} + +{% block platform_admin_content %} + +

{{ '{} an organisation'.format('Update' if organisation else 'Create')}}

+
+
+ +
+
+
{{textbox(form.name)}}
+ {{ page_footer( + 'Save', + back_link=url_for('.organisations'), + back_link_text='Back to organisations', + ) }} +
+
+
+
+{% endblock %} diff --git a/app/templates/views/organisations/organisations.html b/app/templates/views/organisations/organisations.html new file mode 100644 index 000000000..4d4028d63 --- /dev/null +++ b/app/templates/views/organisations/organisations.html @@ -0,0 +1,28 @@ +{% extends "views/platform-admin/_base_template.html" %} +{% from "components/page-footer.html" import page_footer %} + +{% block service_page_title %} + Show organisations +{% endblock %} + +{% block platform_admin_content %} + +

+
Organisations
+

+
+
+ {% for org in organisations %} +
+ {{ org['name'] }} + {% if not org['active'] %} + - archived + {% endif %} +
+ {% endfor %} +
+
Create an organisation
+
+
+ +{% endblock %} diff --git a/tests/app/main/views/test_organisations.py b/tests/app/main/views/test_organisations.py new file mode 100644 index 000000000..746a5a035 --- /dev/null +++ b/tests/app/main/views/test_organisations.py @@ -0,0 +1,104 @@ +from bs4 import BeautifulSoup +from flask import url_for + +from tests.conftest import ( + normalize_spaces +) + + +def test_organisation_page_shows_all_organisations( + logged_in_platform_admin_client, + mocker +): + orgs = [ + {'id': '1', 'name': 'Test 1', 'active': True}, + {'id': '2', 'name': 'Test 2', 'active': True}, + {'id': '3', 'name': 'Test 3', 'active': False}, + ] + + mocker.patch( + 'app.organisations_client.get_organisations', return_value=orgs + ) + response = logged_in_platform_admin_client.get( + url_for('.organisations') + ) + + assert response.status_code == 200 + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + + assert normalize_spaces( + page.select_one('h1').text + ) == "Organisations" + + for index, org in enumerate(orgs): + assert (page.select('a.browse-list-link')[index]).text == org['name'] + if not org['active']: + assert (page.select_one('.table-field-status-default,heading-medium')).text == '- archived' + assert normalize_spaces((page.select('a.browse-list-link')[-1]).text) == 'Create an organisation' + + +def test_edit_organisation_shows_the_correct_organisation( + logged_in_platform_admin_client, + fake_uuid, + mocker +): + org = {'id': fake_uuid, 'name': 'Test 1', 'active': True} + mocker.patch( + 'app.organisations_client.get_organisation', return_value=org + ) + + response = logged_in_platform_admin_client.get( + url_for('.update_organisation', org_id=fake_uuid) + ) + + assert response.status_code == 200 + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + + assert page.select_one('#name').attrs.get('value') == org['name'] + + +def test_create_new_organisation( + logged_in_platform_admin_client, + mocker, + fake_uuid +): + mock_create_organisation = mocker.patch( + 'app.organisations_client.create_organisation' + ) + + org = {'name': 'new name'} + + logged_in_platform_admin_client.post( + url_for('.create_organisation'), + content_type='multipart/form-data', + data=org + ) + + mock_create_organisation.assert_called_once_with(name=org['name']) + + +def test_update_organisation( + logged_in_platform_admin_client, + mocker, + fake_uuid, +): + org = {'name': 'new name'} + + mocker.patch( + 'app.organisations_client.get_organisation', return_value=org + ) + mock_update_organisation = mocker.patch( + 'app.organisations_client.update_organisation' + ) + + logged_in_platform_admin_client.post( + url_for('.update_organisation', org_id=fake_uuid), + content_type='multipart/form-data', + data=org + ) + + assert mock_update_organisation.called + mock_update_organisation.assert_called_once_with( + org_id=fake_uuid, + name=org['name'] + )