From f79a73b0ca766d1db3e388eb13685b038d32f4d8 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 09:35:15 +0100 Subject: [PATCH 01/25] Add methods to HostingEnvironment. --- consultation_analyser/hosting_environment.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/consultation_analyser/hosting_environment.py b/consultation_analyser/hosting_environment.py index e395067c..59286062 100644 --- a/consultation_analyser/hosting_environment.py +++ b/consultation_analyser/hosting_environment.py @@ -17,3 +17,9 @@ def is_deployed() -> bool: environment = env.str("ENVIRONMENT", "").upper() deployed_envs = ["DEV", "DEVELOPMENT", "PREPROD", "PROD", "PRODUCTION"] return environment in deployed_envs + + @staticmethod + def is_development_environment() -> bool: + environment = env.str("ENVIRONMENT", "").upper() + development_environments = ["LOCAL", "TEST", "DEV", "DEVELOPMENT"] + return environment in development_environments From cc9de2f6548e93b4301dc10b8d331b6ab3b97cce Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 09:39:12 +0100 Subject: [PATCH 02/25] Test only genereate dummy data in dev. --- tests/unit/test_generate_dummy_data.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_generate_dummy_data.py b/tests/unit/test_generate_dummy_data.py index 6afad052..c3cc0038 100644 --- a/tests/unit/test_generate_dummy_data.py +++ b/tests/unit/test_generate_dummy_data.py @@ -19,7 +19,8 @@ def test_a_consultation_is_generated(settings): @pytest.mark.django_db -@patch("consultation_analyser.hosting_environment.HostingEnvironment.is_local", return_value=False) -def test_the_tool_will_only_run_in_dev(settings): - with pytest.raises(Exception, match=r"should only be run in development"): - DummyConsultation() +@pytest.mark.parametrize("environment", ["preprod", "prod", "production"]) +def test_the_tool_will_only_run_in_dev(environment): + with patch.dict(os.environ, {"ENVIRONMENT": environment}): + with pytest.raises(Exception, match=r"should only be run in development"): + DummyConsultation() From f1d6999c9a7cc5b23d399ed23499b55ae5fe0f5d Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 10:56:22 +0100 Subject: [PATCH 03/25] Add options for blank themes with dummy data generation. --- .../consultations/dummy_data.py | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/consultation_analyser/consultations/dummy_data.py b/consultation_analyser/consultations/dummy_data.py index 454f1f89..85ddd199 100644 --- a/consultation_analyser/consultations/dummy_data.py +++ b/consultation_analyser/consultations/dummy_data.py @@ -13,8 +13,8 @@ class DummyConsultation: - def __init__(self, responses=10, **options): - if not HostingEnvironment.is_local(): + def __init__(self, responses=10, include_themes=True, **options): + if not HostingEnvironment.is_development_environment(): raise RuntimeError("Dummy data generation should only be run in development") consultation = ConsultationFactory(**options) @@ -31,12 +31,15 @@ def __init__(self, responses=10, **options): ] for r in range(responses): response = ConsultationResponseFactory(consultation=consultation) - _answers = [AnswerFactory(question=q, consultation_response=response) for q in questions] + if include_themes: + _answers = [AnswerFactory(question=q, consultation_response=response) for q in questions] - # Set themes per question, multiple answers with the same theme - for q in questions: - themes = [ThemeFactory() for _ in range(2, 6)] - for a in _answers: - random_theme = random.choice(themes) - a.theme = random_theme - a.save() + # Set themes per question, multiple answers with the same theme + for q in questions: + themes = [ThemeFactory() for _ in range(2, 6)] + for a in _answers: + random_theme = random.choice(themes) + a.theme = random_theme + a.save() + else: + _answers = [AnswerFactory(question=q, consultation_response=response, theme=None) for q in questions] From 72225aafb1711e6b7e3bad3423f1574cedb9d074 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 11:47:55 +0100 Subject: [PATCH 04/25] Add timestamp as default name for dummy data. --- consultation_analyser/consultations/dummy_data.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/consultation_analyser/consultations/dummy_data.py b/consultation_analyser/consultations/dummy_data.py index 85ddd199..8113ea71 100644 --- a/consultation_analyser/consultations/dummy_data.py +++ b/consultation_analyser/consultations/dummy_data.py @@ -1,3 +1,4 @@ +import datetime import random from consultation_analyser.factories import ( @@ -17,6 +18,14 @@ def __init__(self, responses=10, include_themes=True, **options): if not HostingEnvironment.is_development_environment(): raise RuntimeError("Dummy data generation should only be run in development") + # Timestamp to avoid duplicates - set these as default options + timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + if "name" not in options: + # name = f"Dummy consultation generated at {timestamp}" + options["name"] = f"Dummy consultation generated at {timestamp}" + if "slug" not in options: + options["slug"] = f"consultation-slug-{timestamp}" + consultation = ConsultationFactory(**options) section = SectionFactory(name="Base section", consultation=consultation) questions = [ From 9212cda64f956243a668e643e2f875eff491f8bc Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 11:49:08 +0100 Subject: [PATCH 05/25] Fix tests. --- tests/unit/test_generate_dummy_data.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_generate_dummy_data.py b/tests/unit/test_generate_dummy_data.py index c3cc0038..a143a991 100644 --- a/tests/unit/test_generate_dummy_data.py +++ b/tests/unit/test_generate_dummy_data.py @@ -1,3 +1,4 @@ +import os from unittest.mock import patch import pytest From c0604ea8a3dec6a7a9f4612851931916e7cc50cf Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 13:15:20 +0100 Subject: [PATCH 06/25] Rough outline of view to generate dummy data. --- .../jinja2/create_dummy_data.html | 36 +++++++++++++++++++ consultation_analyser/consultations/urls.py | 2 +- .../consultations/views/staff.py | 33 +++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 consultation_analyser/consultations/jinja2/create_dummy_data.html create mode 100644 consultation_analyser/consultations/views/staff.py diff --git a/consultation_analyser/consultations/jinja2/create_dummy_data.html b/consultation_analyser/consultations/jinja2/create_dummy_data.html new file mode 100644 index 00000000..11b7f536 --- /dev/null +++ b/consultation_analyser/consultations/jinja2/create_dummy_data.html @@ -0,0 +1,36 @@ +{% extends "base.html" %} +{%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} + + +{% block content %} +

Create dummy data for testing

+ + +

Local, test, dev environments only. Generate dummy questions and responses only, no themes.

+ +
{{ csrf_input }} + {{ govukButton({ + 'text': "Generate dummy consultation", + 'name': "generate_dummy_consultation" + }) }} + + +

Existing consultations

+ {% for c in consultations %} +

{{ c.name }}

+ {{ govukButton({ + 'text': "Generate themes", + 'name': "consultation_id", + 'value': c.id + }) }} + + {% endfor %} + +

{{ message }}

+ +
+ + {% endblock %} + + + diff --git a/consultation_analyser/consultations/urls.py b/consultation_analyser/consultations/urls.py index e5be7e17..5d98c9d3 100644 --- a/consultation_analyser/consultations/urls.py +++ b/consultation_analyser/consultations/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from .views import consultations, pages, questions, responses, schema +from .views import consultations, pages, questions, responses, schema, staff urlpatterns = [ path("", pages.home), diff --git a/consultation_analyser/consultations/views/staff.py b/consultation_analyser/consultations/views/staff.py new file mode 100644 index 00000000..9b61e53e --- /dev/null +++ b/consultation_analyser/consultations/views/staff.py @@ -0,0 +1,33 @@ +import uuid + +from django.http import HttpRequest, HttpResponse +from django.shortcuts import redirect, render + +from .. import dummy_data, ml_pipeline, models + + +def create_dummy_data(request: HttpRequest) -> HttpResponse: + # TODO - sort out messages properly + message = "" + if request.POST: + print(request.POST) + if "generate_dummy_consultation" in request.POST: + try: + dummy_data.DummyConsultation(include_themes=False) + message = "New consultation generated" + except RuntimeError as error: + message = error.args[0] + else: + consultation_id = request.POST.get("consultation_id") + themes_already_exist = models.Theme.objects.filter( + answer__question__section__consultation__id=consultation_id + ).exists() + if not themes_already_exist: + ml_pipeline.save_themes_for_consultation(consultation_id=consultation_id) + message = "Themes created for consultation" + else: + message = "Themes already exist for consultation" + + consultations = models.Consultation.objects.all() + context = {"consultations": consultations, "message": message} + return render(request, "create_dummy_data.html", context=context) From 3a788d0448c9aaf5c7023decabb456242f546097 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 22:24:21 +0100 Subject: [PATCH 07/25] Pass through messages for the testing dummy data page. --- .../jinja2/create_dummy_data.html | 18 ++++++++++++++++-- .../consultations/views/staff.py | 16 ++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/consultation_analyser/consultations/jinja2/create_dummy_data.html b/consultation_analyser/consultations/jinja2/create_dummy_data.html index 11b7f536..0ef0d073 100644 --- a/consultation_analyser/consultations/jinja2/create_dummy_data.html +++ b/consultation_analyser/consultations/jinja2/create_dummy_data.html @@ -1,8 +1,24 @@ {% extends "base.html" %} {%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} +{%- from 'govuk_frontend_jinja/components/notification-banner/macro.html' import govukNotificationBanner -%} +{%- from 'govuk_frontend_jinja/components/warning-text/macro.html' import govukWarningText -%} {% block content %} + + {% for message in messages %} + {% if message.tags == "info" %} + {{ govukNotificationBanner({ + 'html': message + }) }} + {% elif message.tags == "warning" %} + {{ govukWarningText({ + 'text': message, + 'iconFallbackText': "Warning" + }) }} + {% endif %} + {% endfor %} +

Create dummy data for testing

@@ -26,8 +42,6 @@

Existing consultations

{% endfor %} -

{{ message }}

- {% endblock %} diff --git a/consultation_analyser/consultations/views/staff.py b/consultation_analyser/consultations/views/staff.py index 9b61e53e..0da17319 100644 --- a/consultation_analyser/consultations/views/staff.py +++ b/consultation_analyser/consultations/views/staff.py @@ -1,5 +1,7 @@ import uuid +from django.contrib import messages +from django.contrib.messages import get_messages from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect, render @@ -7,16 +9,13 @@ def create_dummy_data(request: HttpRequest) -> HttpResponse: - # TODO - sort out messages properly - message = "" if request.POST: - print(request.POST) if "generate_dummy_consultation" in request.POST: try: dummy_data.DummyConsultation(include_themes=False) - message = "New consultation generated" + messages.add_message(request, messages.INFO, "New consultation generated") except RuntimeError as error: - message = error.args[0] + messages.add_message(request, messages.WARN, error.args[0]) else: consultation_id = request.POST.get("consultation_id") themes_already_exist = models.Theme.objects.filter( @@ -24,10 +23,11 @@ def create_dummy_data(request: HttpRequest) -> HttpResponse: ).exists() if not themes_already_exist: ml_pipeline.save_themes_for_consultation(consultation_id=consultation_id) - message = "Themes created for consultation" + messages.add_message(request, messages.INFO, "Themes created for consultation") else: - message = "Themes already exist for consultation" + messages.add_message(request, messages.INFO, "Themes already exist for this consultation") consultations = models.Consultation.objects.all() - context = {"consultations": consultations, "message": message} + # Have to pass messages to template as we are using jinja not DTL + context = {"consultations": consultations, "messages": get_messages(request)} return render(request, "create_dummy_data.html", context=context) From 68f8fb3fafbd6429be3815fc1d5410f27c562cf1 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 22:39:18 +0100 Subject: [PATCH 08/25] Change to a view per consultation. --- consultation_analyser/consultations/urls.py | 2 +- .../consultations/views/consultations.py | 6 +++--- tests/integration/test_consultation_page.py | 5 +++++ tests/request/test_access_consultation_pages.py | 12 ++++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/consultation_analyser/consultations/urls.py b/consultation_analyser/consultations/urls.py index 5d98c9d3..f003eaf0 100644 --- a/consultation_analyser/consultations/urls.py +++ b/consultation_analyser/consultations/urls.py @@ -5,8 +5,8 @@ urlpatterns = [ path("", pages.home), path("privacy/", pages.privacy), - path("consultations/", consultations.show_questions), path("schema/", schema.show), + path("consultations//", consultations.show_questions), path("schema/.json", schema.raw_schema), path( "consultations//sections//questions//", diff --git a/consultation_analyser/consultations/views/consultations.py b/consultation_analyser/consultations/views/consultations.py index 0960beac..b8c65e6d 100644 --- a/consultation_analyser/consultations/views/consultations.py +++ b/consultation_analyser/consultations/views/consultations.py @@ -1,4 +1,4 @@ -from django.http import HttpRequest +from django.http import HttpRequest, HttpResponse from django.shortcuts import render from waffle.decorators import waffle_switch @@ -6,7 +6,7 @@ @waffle_switch("CONSULTATION_PROCESSING") -def show_questions(request: HttpRequest): - questions = models.Question.objects.all().order_by("id")[:10] +def show_questions(request: HttpRequest, consultation_slug: str) -> HttpResponse: + questions = models.Question.objects.filter(section__consultation__slug=consultation_slug) context = {"questions": questions} return render(request, "consultation.html", context) diff --git a/tests/integration/test_consultation_page.py b/tests/integration/test_consultation_page.py index e2d84374..99b13d20 100644 --- a/tests/integration/test_consultation_page.py +++ b/tests/integration/test_consultation_page.py @@ -8,8 +8,13 @@ @override_switch("CONSULTATION_PROCESSING", True) def test_consultation_page(django_app): consultation = ConsultationFactory(with_question=True) + consultation_slug = consultation.slug question = consultation.section_set.first().question_set.first() +<<<<<<< HEAD homepage = django_app.get("/consultations/") +======= + homepage = django_app.get(f"/consultations/{consultation_slug}") +>>>>>>> ebdd65b (Change to a view per consultation.) question_page = homepage.click("Question summary") assert "Question summary" in question_page diff --git a/tests/request/test_access_consultation_pages.py b/tests/request/test_access_consultation_pages.py index 7e9f63f9..1294b4dd 100644 --- a/tests/request/test_access_consultation_pages.py +++ b/tests/request/test_access_consultation_pages.py @@ -1,16 +1,28 @@ import pytest from waffle.testutils import override_switch +from consultation_analyser.factories import ConsultationFactory + @pytest.mark.django_db @override_switch("CONSULTATION_PROCESSING", True) def test_accessing_when_flag_is_on(client): + consultation = ConsultationFactory() assert client.get("/").status_code == 200 +<<<<<<< HEAD assert client.get("/consultations/").status_code == 200 +======= + assert client.get(f"/consultations/{consultation.slug}").status_code == 200 +>>>>>>> ebdd65b (Change to a view per consultation.) @pytest.mark.django_db @override_switch("CONSULTATION_PROCESSING", False) def test_accessing_when_flag_is_off(client): + consultation = ConsultationFactory() assert client.get("/").status_code == 200 +<<<<<<< HEAD assert client.get("/consultations/").status_code == 404 +======= + assert client.get(f"/consultations/{consultation.slug}").status_code == 404 +>>>>>>> ebdd65b (Change to a view per consultation.) From 3c87639d3720f9754d507caaa6cd170bd3333bdb Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Tue, 16 Apr 2024 22:52:44 +0100 Subject: [PATCH 09/25] Update links in dummy data page --- .../consultations/jinja2/create_dummy_data.html | 7 ++++++- consultation_analyser/consultations/urls.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/consultation_analyser/consultations/jinja2/create_dummy_data.html b/consultation_analyser/consultations/jinja2/create_dummy_data.html index 0ef0d073..ecea4f44 100644 --- a/consultation_analyser/consultations/jinja2/create_dummy_data.html +++ b/consultation_analyser/consultations/jinja2/create_dummy_data.html @@ -33,13 +33,18 @@

Create dummy data for testing

Existing consultations

{% for c in consultations %} -

{{ c.name }}

+ + + {{ c.name }} + + {{ govukButton({ 'text': "Generate themes", 'name': "consultation_id", 'value': c.id }) }} +
{% endfor %} diff --git a/consultation_analyser/consultations/urls.py b/consultation_analyser/consultations/urls.py index f003eaf0..d35aa410 100644 --- a/consultation_analyser/consultations/urls.py +++ b/consultation_analyser/consultations/urls.py @@ -6,7 +6,7 @@ path("", pages.home), path("privacy/", pages.privacy), path("schema/", schema.show), - path("consultations//", consultations.show_questions), + path("consultations//", consultations.show_questions, name="consultation"), path("schema/.json", schema.raw_schema), path( "consultations//sections//questions//", From c913042011c17e11ac88c2e88030f288b8e63e71 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Wed, 17 Apr 2024 13:55:01 +0100 Subject: [PATCH 10/25] Refactor the view generating dummy data - more descriptive naming and moving into the support app. --- consultation_analyser/consultations/urls.py | 2 +- .../consultations/views/staff.py | 33 ------------------- .../support_console/ml_pipeline_test.html} | 0 consultation_analyser/support_console/urls.py | 1 + .../support_console/views.py | 33 ++++++++++++++++++- 5 files changed, 34 insertions(+), 35 deletions(-) delete mode 100644 consultation_analyser/consultations/views/staff.py rename consultation_analyser/{consultations/jinja2/create_dummy_data.html => support_console/jinja2/support_console/ml_pipeline_test.html} (100%) diff --git a/consultation_analyser/consultations/urls.py b/consultation_analyser/consultations/urls.py index d35aa410..939064d9 100644 --- a/consultation_analyser/consultations/urls.py +++ b/consultation_analyser/consultations/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from .views import consultations, pages, questions, responses, schema, staff +from .views import consultations, pages, questions, responses, schema urlpatterns = [ path("", pages.home), diff --git a/consultation_analyser/consultations/views/staff.py b/consultation_analyser/consultations/views/staff.py deleted file mode 100644 index 0da17319..00000000 --- a/consultation_analyser/consultations/views/staff.py +++ /dev/null @@ -1,33 +0,0 @@ -import uuid - -from django.contrib import messages -from django.contrib.messages import get_messages -from django.http import HttpRequest, HttpResponse -from django.shortcuts import redirect, render - -from .. import dummy_data, ml_pipeline, models - - -def create_dummy_data(request: HttpRequest) -> HttpResponse: - if request.POST: - if "generate_dummy_consultation" in request.POST: - try: - dummy_data.DummyConsultation(include_themes=False) - messages.add_message(request, messages.INFO, "New consultation generated") - except RuntimeError as error: - messages.add_message(request, messages.WARN, error.args[0]) - else: - consultation_id = request.POST.get("consultation_id") - themes_already_exist = models.Theme.objects.filter( - answer__question__section__consultation__id=consultation_id - ).exists() - if not themes_already_exist: - ml_pipeline.save_themes_for_consultation(consultation_id=consultation_id) - messages.add_message(request, messages.INFO, "Themes created for consultation") - else: - messages.add_message(request, messages.INFO, "Themes already exist for this consultation") - - consultations = models.Consultation.objects.all() - # Have to pass messages to template as we are using jinja not DTL - context = {"consultations": consultations, "messages": get_messages(request)} - return render(request, "create_dummy_data.html", context=context) diff --git a/consultation_analyser/consultations/jinja2/create_dummy_data.html b/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html similarity index 100% rename from consultation_analyser/consultations/jinja2/create_dummy_data.html rename to consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html diff --git a/consultation_analyser/support_console/urls.py b/consultation_analyser/support_console/urls.py index 0e0ad853..f25055c6 100644 --- a/consultation_analyser/support_console/urls.py +++ b/consultation_analyser/support_console/urls.py @@ -5,4 +5,5 @@ urlpatterns = [ path("", views.support_home), path("sign-out/", views.sign_out), + path("ml-pipeline-test/", views.ml_pipeline_test), ] diff --git a/consultation_analyser/support_console/views.py b/consultation_analyser/support_console/views.py index 714fca7e..934725fc 100644 --- a/consultation_analyser/support_console/views.py +++ b/consultation_analyser/support_console/views.py @@ -1,8 +1,12 @@ +from django.contrib import messages from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth import logout -from django.http import HttpRequest +from django.contrib.messages import get_messages +from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect, render +from consultation_analyser.consultations import dummy_data, ml_pipeline, models + @staff_member_required def support_home(request: HttpRequest): @@ -13,3 +17,30 @@ def support_home(request: HttpRequest): def sign_out(request: HttpRequest): logout(request) return redirect("/") + + +@staff_member_required +def ml_pipeline_test(request: HttpRequest) -> HttpResponse: + if request.POST: + if "generate_dummy_consultation" in request.POST: + try: + dummy_data.DummyConsultation(include_themes=False) + messages.add_message(request, messages.INFO, "New consultation generated") + except RuntimeError as error: + messages.add_message(request, messages.WARN, error.args[0]) + else: + consultation_id = request.POST.get("consultation_id") + themes_already_exist = models.Theme.objects.filter( + answer__question__section__consultation__id=consultation_id + ).exists() + if not themes_already_exist: + ml_pipeline.save_themes_for_consultation(consultation_id=consultation_id) + messages.add_message(request, messages.INFO, "Themes created for consultation") + else: + messages.add_message(request, messages.INFO, "Themes already exist for this consultation") + + consultations = models.Consultation.objects.all() + # TODO - improve the way we deal with messages + # Have to pass messages to template as we are using jinja not DTL + context = {"consultations": consultations, "messages": get_messages(request)} + return render(request, "support_console/ml_pipeline_test.html", context=context) From d25eff598aca4c0e8963b8ac2f6c38edb2765460 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Wed, 17 Apr 2024 17:20:25 +0100 Subject: [PATCH 11/25] Add not-quite working test for ML pipeline test page --- .../integration/test_logging_in_to_support.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/integration/test_logging_in_to_support.py b/tests/integration/test_logging_in_to_support.py index 78569281..6b457ea1 100644 --- a/tests/integration/test_logging_in_to_support.py +++ b/tests/integration/test_logging_in_to_support.py @@ -1,5 +1,6 @@ import pytest +from consultation_analyser.consultations.models import Consultation from consultation_analyser.factories import UserFactory @@ -22,3 +23,22 @@ def test_logging_in_to_support(django_app): logged_out_page = support_home.click("Sign out") assert "Consultation analyser support console" not in logged_out_page + + +@pytest.mark.django_db +def test_generating_dummy_data(django_app): + page_url = "/support/ml-pipeline-test/" + # Login and go to ML test page + UserFactory(email="email@example.com", password="admin", is_staff=True) # pragma: allowlist secret + login_page = django_app.get(page_url).follow() + login_page.form["username"] = "email@example.com" + login_page.form["password"] = "admin" # pragma: allowlist secret + ml_page = login_page.form.submit().follow() + assert "dummy data" in ml_page + + # Check dummy data button does generate a new consultation + initial_count = Consultation.objects.all().count() + # TODO - why isn't this working + ml_page.clickbutton("Generate dummy consultation") + count_after_dummy_data = Consultation.objects.all().count() + assert count_after_dummy_data > initial_count From 4ea02fd123af1d1efb47e29b33dae0085e40cf84 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Wed, 17 Apr 2024 17:32:30 +0100 Subject: [PATCH 12/25] Check we can't access page when not logged in. --- tests/request/test_support_pages.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/request/test_support_pages.py diff --git a/tests/request/test_support_pages.py b/tests/request/test_support_pages.py new file mode 100644 index 00000000..317d9235 --- /dev/null +++ b/tests/request/test_support_pages.py @@ -0,0 +1,6 @@ +import pytest + + +@pytest.mark.django_db +def test_no_login_ml_pipeline_page_support(client): + assert client.get("/support/ml-pipeline-test/").status_code == 302 From af620a352f7fcf25ef24050420a3aa8fbec81da1 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Wed, 17 Apr 2024 20:36:03 +0100 Subject: [PATCH 13/25] Make the formatting of the test ML pipeline page a bit better. --- .../consultations/dummy_data.py | 1 - .../support_console/ml_pipeline_test.html | 56 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/consultation_analyser/consultations/dummy_data.py b/consultation_analyser/consultations/dummy_data.py index 8113ea71..8c5bcb34 100644 --- a/consultation_analyser/consultations/dummy_data.py +++ b/consultation_analyser/consultations/dummy_data.py @@ -21,7 +21,6 @@ def __init__(self, responses=10, include_themes=True, **options): # Timestamp to avoid duplicates - set these as default options timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") if "name" not in options: - # name = f"Dummy consultation generated at {timestamp}" options["name"] = f"Dummy consultation generated at {timestamp}" if "slug" not in options: options["slug"] = f"consultation-slug-{timestamp}" diff --git a/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html b/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html index ecea4f44..e3ef2bc7 100644 --- a/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html +++ b/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html @@ -19,37 +19,43 @@ {% endif %} {% endfor %} -

Create dummy data for testing

+

Test the machine learning pipeline

+
{{ csrf_input }} - -

Local, test, dev environments only. Generate dummy questions and responses only, no themes.

- - {{ csrf_input }} - {{ govukButton({ - 'text': "Generate dummy consultation", - 'name': "generate_dummy_consultation" - }) }} - - -

Existing consultations

- {% for c in consultations %} - - - {{ c.name }} - +

Generate a dummy consultation for testing

+

Local, test, and develop environments only. Generate dummy questions and responses but no dummy themes.

{{ govukButton({ - 'text': "Generate themes", - 'name': "consultation_id", - 'value': c.id + 'text': "Generate dummy consultation", + 'name': "generate_dummy_consultation" }) }} -
- {% endfor %} - -
- {% endblock %} +

Generate themes for existing consultations

+ {% for c in consultations %} +
+ +
+

+ {{ govukButton({ + 'text': "Generate themes", + 'name': "consultation_id", + 'value': c.id + }) }} +

+
+
+ {% endfor %} + + + +{% endblock %} From 35ddd738646245cdeebe5b8421aeb79903565da6 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Wed, 17 Apr 2024 21:39:27 +0100 Subject: [PATCH 14/25] Make test for dummy data work. --- tests/integration/test_logging_in_to_support.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/test_logging_in_to_support.py b/tests/integration/test_logging_in_to_support.py index 6b457ea1..864c6713 100644 --- a/tests/integration/test_logging_in_to_support.py +++ b/tests/integration/test_logging_in_to_support.py @@ -34,11 +34,10 @@ def test_generating_dummy_data(django_app): login_page.form["username"] = "email@example.com" login_page.form["password"] = "admin" # pragma: allowlist secret ml_page = login_page.form.submit().follow() - assert "dummy data" in ml_page + assert "Generate a dummy consultation" in ml_page # Check dummy data button does generate a new consultation initial_count = Consultation.objects.all().count() - # TODO - why isn't this working - ml_page.clickbutton("Generate dummy consultation") + ml_page.form.submit("generate_dummy_consultation") count_after_dummy_data = Consultation.objects.all().count() assert count_after_dummy_data > initial_count From 056b4eb2764f4ad2211d9389e4daf2d8eca04ce8 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 13:22:32 +0100 Subject: [PATCH 15/25] Clean up after slightly messy rebase. --- tests/integration/test_consultation_page.py | 4 ---- tests/request/test_access_consultation_pages.py | 8 -------- 2 files changed, 12 deletions(-) diff --git a/tests/integration/test_consultation_page.py b/tests/integration/test_consultation_page.py index 99b13d20..51e2f3b5 100644 --- a/tests/integration/test_consultation_page.py +++ b/tests/integration/test_consultation_page.py @@ -10,11 +10,7 @@ def test_consultation_page(django_app): consultation = ConsultationFactory(with_question=True) consultation_slug = consultation.slug question = consultation.section_set.first().question_set.first() -<<<<<<< HEAD - homepage = django_app.get("/consultations/") -======= homepage = django_app.get(f"/consultations/{consultation_slug}") ->>>>>>> ebdd65b (Change to a view per consultation.) question_page = homepage.click("Question summary") assert "Question summary" in question_page diff --git a/tests/request/test_access_consultation_pages.py b/tests/request/test_access_consultation_pages.py index 1294b4dd..627de40c 100644 --- a/tests/request/test_access_consultation_pages.py +++ b/tests/request/test_access_consultation_pages.py @@ -9,11 +9,7 @@ def test_accessing_when_flag_is_on(client): consultation = ConsultationFactory() assert client.get("/").status_code == 200 -<<<<<<< HEAD - assert client.get("/consultations/").status_code == 200 -======= assert client.get(f"/consultations/{consultation.slug}").status_code == 200 ->>>>>>> ebdd65b (Change to a view per consultation.) @pytest.mark.django_db @@ -21,8 +17,4 @@ def test_accessing_when_flag_is_on(client): def test_accessing_when_flag_is_off(client): consultation = ConsultationFactory() assert client.get("/").status_code == 200 -<<<<<<< HEAD - assert client.get("/consultations/").status_code == 404 -======= assert client.get(f"/consultations/{consultation.slug}").status_code == 404 ->>>>>>> ebdd65b (Change to a view per consultation.) From 6e61dd9ab1dc3e45d84f78905482bc031921a58a Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 17:50:31 +0100 Subject: [PATCH 16/25] Add a page showing all consultations. --- .../jinja2/all-consultations.html | 18 ++++++++++++++++++ consultation_analyser/consultations/urls.py | 3 ++- .../consultations/views/consultations.py | 10 +++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 consultation_analyser/consultations/jinja2/all-consultations.html diff --git a/consultation_analyser/consultations/jinja2/all-consultations.html b/consultation_analyser/consultations/jinja2/all-consultations.html new file mode 100644 index 00000000..f8b5405e --- /dev/null +++ b/consultation_analyser/consultations/jinja2/all-consultations.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} + +{% set page_title = "Consultations" %} + +{% block content %} +

{{ page_title }}

+ + +{% endblock %} diff --git a/consultation_analyser/consultations/urls.py b/consultation_analyser/consultations/urls.py index 939064d9..25595b93 100644 --- a/consultation_analyser/consultations/urls.py +++ b/consultation_analyser/consultations/urls.py @@ -6,7 +6,8 @@ path("", pages.home), path("privacy/", pages.privacy), path("schema/", schema.show), - path("consultations//", consultations.show_questions, name="consultation"), + path("consultations/", consultations.show_all), + path("consultations//", consultations.show, name="consultation"), path("schema/.json", schema.raw_schema), path( "consultations//sections//questions//", diff --git a/consultation_analyser/consultations/views/consultations.py b/consultation_analyser/consultations/views/consultations.py index b8c65e6d..4a05a229 100644 --- a/consultation_analyser/consultations/views/consultations.py +++ b/consultation_analyser/consultations/views/consultations.py @@ -6,7 +6,15 @@ @waffle_switch("CONSULTATION_PROCESSING") -def show_questions(request: HttpRequest, consultation_slug: str) -> HttpResponse: +def show_all(request: HttpRequest) -> HttpResponse: + # TODO - in future, would restrict to all consultations for user + consultations = models.Consultation.objects.all() + context = {"consultations": consultations} + return render(request, "all-consultations.html", context) + + +@waffle_switch("CONSULTATION_PROCESSING") +def show(request: HttpRequest, consultation_slug: str) -> HttpResponse: questions = models.Question.objects.filter(section__consultation__slug=consultation_slug) context = {"questions": questions} return render(request, "consultation.html", context) From 6a8b0af6fed774704a4efc06baacf1b55f286797 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 19:16:23 +0100 Subject: [PATCH 17/25] Add a consultations page in the support area. --- .../support_console/all-consultations.html | 28 +++++++++++++++++++ consultation_analyser/support_console/urls.py | 2 +- .../support_console/views.py | 19 +++++++++++-- 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 consultation_analyser/support_console/jinja2/support_console/all-consultations.html diff --git a/consultation_analyser/support_console/jinja2/support_console/all-consultations.html b/consultation_analyser/support_console/jinja2/support_console/all-consultations.html new file mode 100644 index 00000000..49f82e7a --- /dev/null +++ b/consultation_analyser/support_console/jinja2/support_console/all-consultations.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} + +{% set page_title = "Consultations" %} + +{% block content %} +

{{ page_title }}

+
{{ csrf_input }} + + + {% if development_env %} + {{ govukButton({ + 'text': "Generate dummy consultation", + 'name': "generate_dummy_consultation" + }) }} + {% endif %} + +
+ +{% endblock %} diff --git a/consultation_analyser/support_console/urls.py b/consultation_analyser/support_console/urls.py index f25055c6..211dc8c5 100644 --- a/consultation_analyser/support_console/urls.py +++ b/consultation_analyser/support_console/urls.py @@ -5,5 +5,5 @@ urlpatterns = [ path("", views.support_home), path("sign-out/", views.sign_out), - path("ml-pipeline-test/", views.ml_pipeline_test), + path("consultations/", views.show_consultations), ] diff --git a/consultation_analyser/support_console/views.py b/consultation_analyser/support_console/views.py index 934725fc..6b4e6985 100644 --- a/consultation_analyser/support_console/views.py +++ b/consultation_analyser/support_console/views.py @@ -6,6 +6,7 @@ from django.shortcuts import redirect, render from consultation_analyser.consultations import dummy_data, ml_pipeline, models +from consultation_analyser.hosting_environment import HostingEnvironment @staff_member_required @@ -39,8 +40,22 @@ def ml_pipeline_test(request: HttpRequest) -> HttpResponse: else: messages.add_message(request, messages.INFO, "Themes already exist for this consultation") + # TODO - messages consultations = models.Consultation.objects.all() - # TODO - improve the way we deal with messages - # Have to pass messages to template as we are using jinja not DTL + context = {"consultations": consultations, "messages": get_messages(request)} return render(request, "support_console/ml_pipeline_test.html", context=context) + + +@staff_member_required +def show_consultations(request: HttpRequest) -> HttpResponse: + if request.POST: + try: + dummy_data.DummyConsultation(include_themes=False) + messages.add_message(request, messages.INFO, "New consultation generated") + except RuntimeError as error: + messages.add_message(request, messages.WARNING, error.args[0]) + consultations = models.Consultation.objects.all() + # TODO - do something with messages + context = {"consultations": consultations, "development_env": HostingEnvironment.is_development_environment()} + return render(request, "support_console/all-consultations.html", context=context) From dec682b13a93bf2d70bc35a8f491ea16f2a58aa9 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 20:28:24 +0100 Subject: [PATCH 18/25] Add consultation page in support area for generating themes. --- .../support_console/all-consultations.html | 2 +- .../jinja2/support_console/consultation.html | 24 +++++++++++++++++++ consultation_analyser/support_console/urls.py | 1 + .../support_console/views.py | 17 +++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 consultation_analyser/support_console/jinja2/support_console/consultation.html diff --git a/consultation_analyser/support_console/jinja2/support_console/all-consultations.html b/consultation_analyser/support_console/jinja2/support_console/all-consultations.html index 49f82e7a..5c194807 100644 --- a/consultation_analyser/support_console/jinja2/support_console/all-consultations.html +++ b/consultation_analyser/support_console/jinja2/support_console/all-consultations.html @@ -9,7 +9,7 @@

{{ page_title }}

    {% for consultation in consultations %}
  • - + {{ consultation.name }}
  • diff --git a/consultation_analyser/support_console/jinja2/support_console/consultation.html b/consultation_analyser/support_console/jinja2/support_console/consultation.html new file mode 100644 index 00000000..41e9fd59 --- /dev/null +++ b/consultation_analyser/support_console/jinja2/support_console/consultation.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} + +{% set page_title = "Consultation" %} + +{% block content %} +

    {{ page_title }}

    +
    {{ csrf_input }} + + +
    + + {{ govukButton({ + 'text': "Generate themes", + 'name': "generate_themes" + }) }} + +
    + +{% endblock %} diff --git a/consultation_analyser/support_console/urls.py b/consultation_analyser/support_console/urls.py index 211dc8c5..b8e1c353 100644 --- a/consultation_analyser/support_console/urls.py +++ b/consultation_analyser/support_console/urls.py @@ -6,4 +6,5 @@ path("", views.support_home), path("sign-out/", views.sign_out), path("consultations/", views.show_consultations), + path("consultation//", views.show_consultation, name="support_consultation"), ] diff --git a/consultation_analyser/support_console/views.py b/consultation_analyser/support_console/views.py index 6b4e6985..b20a8bf5 100644 --- a/consultation_analyser/support_console/views.py +++ b/consultation_analyser/support_console/views.py @@ -59,3 +59,20 @@ def show_consultations(request: HttpRequest) -> HttpResponse: # TODO - do something with messages context = {"consultations": consultations, "development_env": HostingEnvironment.is_development_environment()} return render(request, "support_console/all-consultations.html", context=context) + + +@staff_member_required +def show_consultation(request: HttpRequest, consultation_slug: str) -> HttpResponse: + consultation = models.Consultation.objects.get(slug=consultation_slug) + if request.POST: + themes_already_exist = models.Theme.objects.filter( + answer__question__section__consultation=consultation + ).exists() + if not themes_already_exist: + ml_pipeline.save_themes_for_consultation(consultation_id=consultation.id) + messages.add_message(request, messages.INFO, "Themes created for consultation") + else: + messages.add_message(request, messages.INFO, "Themes already exist for this consultation") + # TODO - do something with messages + context = {"consultation": consultation} + return render(request, "support_console/consultation.html", context=context) From 145f27d076d7f4b78077e7e649d38612ad9f05ef Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 20:31:20 +0100 Subject: [PATCH 19/25] Remove now unused ML pipeline test page. --- .../support_console/ml_pipeline_test.html | 61 ------------------- .../support_console/views.py | 27 -------- 2 files changed, 88 deletions(-) delete mode 100644 consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html diff --git a/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html b/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html deleted file mode 100644 index e3ef2bc7..00000000 --- a/consultation_analyser/support_console/jinja2/support_console/ml_pipeline_test.html +++ /dev/null @@ -1,61 +0,0 @@ -{% extends "base.html" %} -{%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} -{%- from 'govuk_frontend_jinja/components/notification-banner/macro.html' import govukNotificationBanner -%} -{%- from 'govuk_frontend_jinja/components/warning-text/macro.html' import govukWarningText -%} - - -{% block content %} - - {% for message in messages %} - {% if message.tags == "info" %} - {{ govukNotificationBanner({ - 'html': message - }) }} - {% elif message.tags == "warning" %} - {{ govukWarningText({ - 'text': message, - 'iconFallbackText': "Warning" - }) }} - {% endif %} - {% endfor %} - -

    Test the machine learning pipeline

    -
    {{ csrf_input }} - -

    Generate a dummy consultation for testing

    -

    Local, test, and develop environments only. Generate dummy questions and responses but no dummy themes.

    - - {{ govukButton({ - 'text': "Generate dummy consultation", - 'name': "generate_dummy_consultation" - }) }} - - -

    Generate themes for existing consultations

    - {% for c in consultations %} -
    - -
    -

    - {{ govukButton({ - 'text': "Generate themes", - 'name': "consultation_id", - 'value': c.id - }) }} -

    -
    -
    - {% endfor %} - -
    - -{% endblock %} - - - diff --git a/consultation_analyser/support_console/views.py b/consultation_analyser/support_console/views.py index b20a8bf5..eb3f980f 100644 --- a/consultation_analyser/support_console/views.py +++ b/consultation_analyser/support_console/views.py @@ -20,33 +20,6 @@ def sign_out(request: HttpRequest): return redirect("/") -@staff_member_required -def ml_pipeline_test(request: HttpRequest) -> HttpResponse: - if request.POST: - if "generate_dummy_consultation" in request.POST: - try: - dummy_data.DummyConsultation(include_themes=False) - messages.add_message(request, messages.INFO, "New consultation generated") - except RuntimeError as error: - messages.add_message(request, messages.WARN, error.args[0]) - else: - consultation_id = request.POST.get("consultation_id") - themes_already_exist = models.Theme.objects.filter( - answer__question__section__consultation__id=consultation_id - ).exists() - if not themes_already_exist: - ml_pipeline.save_themes_for_consultation(consultation_id=consultation_id) - messages.add_message(request, messages.INFO, "Themes created for consultation") - else: - messages.add_message(request, messages.INFO, "Themes already exist for this consultation") - - # TODO - messages - consultations = models.Consultation.objects.all() - - context = {"consultations": consultations, "messages": get_messages(request)} - return render(request, "support_console/ml_pipeline_test.html", context=context) - - @staff_member_required def show_consultations(request: HttpRequest) -> HttpResponse: if request.POST: From ffb85c8a0e16f0bf8c0243b816e810732287a463 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 20:51:32 +0100 Subject: [PATCH 20/25] Add consultations to the support console menu. --- consultation_analyser/context_processors.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/consultation_analyser/context_processors.py b/consultation_analyser/context_processors.py index fcae4400..8b12e3f1 100644 --- a/consultation_analyser/context_processors.py +++ b/consultation_analyser/context_processors.py @@ -16,10 +16,14 @@ def app_config(request: HttpRequest): name="Consultation analyser support console", path="/support/", menu_items=[ + { + "href": "/support/consultations/", + "text": "Consultations", + }, { "href": "/support/sign-out/", "text": "Sign out", - } + }, ], ) else: From e30d1e36819c86d8f22cbc76626e86ac6a3620f1 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 20:51:50 +0100 Subject: [PATCH 21/25] Tweaks to text. --- .../jinja2/support_console/all-consultations.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consultation_analyser/support_console/jinja2/support_console/all-consultations.html b/consultation_analyser/support_console/jinja2/support_console/all-consultations.html index 5c194807..c3fd36a5 100644 --- a/consultation_analyser/support_console/jinja2/support_console/all-consultations.html +++ b/consultation_analyser/support_console/jinja2/support_console/all-consultations.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {%- from 'govuk_frontend_jinja/components/button/macro.html' import govukButton -%} -{% set page_title = "Consultations" %} +{% set page_title = "All consultations" %} {% block content %}

    {{ page_title }}

    @@ -9,7 +9,7 @@

    {{ page_title }}

      {% for consultation in consultations %}
    • - + {{ consultation.name }}
    • From 612e69c3ba1c5d0942935fc0981aa579c9885b04 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Thu, 18 Apr 2024 21:44:37 +0100 Subject: [PATCH 22/25] add some tests for the support/consultation pages --- consultation_analyser/support_console/urls.py | 2 +- tests/integration/test_consultation_page.py | 2 +- tests/integration/test_logging_in_to_support.py | 9 ++++----- tests/request/test_access_consultation_pages.py | 4 ++-- tests/request/test_support_pages.py | 17 +++++++++++++++-- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/consultation_analyser/support_console/urls.py b/consultation_analyser/support_console/urls.py index b8e1c353..a29a434a 100644 --- a/consultation_analyser/support_console/urls.py +++ b/consultation_analyser/support_console/urls.py @@ -6,5 +6,5 @@ path("", views.support_home), path("sign-out/", views.sign_out), path("consultations/", views.show_consultations), - path("consultation//", views.show_consultation, name="support_consultation"), + path("consultations//", views.show_consultation, name="support_consultation"), ] diff --git a/tests/integration/test_consultation_page.py b/tests/integration/test_consultation_page.py index 51e2f3b5..ad2e37e5 100644 --- a/tests/integration/test_consultation_page.py +++ b/tests/integration/test_consultation_page.py @@ -10,7 +10,7 @@ def test_consultation_page(django_app): consultation = ConsultationFactory(with_question=True) consultation_slug = consultation.slug question = consultation.section_set.first().question_set.first() - homepage = django_app.get(f"/consultations/{consultation_slug}") + homepage = django_app.get(f"/consultations/{consultation_slug}/") question_page = homepage.click("Question summary") assert "Question summary" in question_page diff --git a/tests/integration/test_logging_in_to_support.py b/tests/integration/test_logging_in_to_support.py index 864c6713..40d0a033 100644 --- a/tests/integration/test_logging_in_to_support.py +++ b/tests/integration/test_logging_in_to_support.py @@ -27,17 +27,16 @@ def test_logging_in_to_support(django_app): @pytest.mark.django_db def test_generating_dummy_data(django_app): - page_url = "/support/ml-pipeline-test/" - # Login and go to ML test page + page_url = "/support/consultations/" UserFactory(email="email@example.com", password="admin", is_staff=True) # pragma: allowlist secret login_page = django_app.get(page_url).follow() login_page.form["username"] = "email@example.com" login_page.form["password"] = "admin" # pragma: allowlist secret - ml_page = login_page.form.submit().follow() - assert "Generate a dummy consultation" in ml_page + consultations_page = login_page.form.submit().follow() + assert "All consultations" in consultations_page # Check dummy data button does generate a new consultation initial_count = Consultation.objects.all().count() - ml_page.form.submit("generate_dummy_consultation") + consultations_page.form.submit("generate_dummy_consultation") count_after_dummy_data = Consultation.objects.all().count() assert count_after_dummy_data > initial_count diff --git a/tests/request/test_access_consultation_pages.py b/tests/request/test_access_consultation_pages.py index 627de40c..e9eebf80 100644 --- a/tests/request/test_access_consultation_pages.py +++ b/tests/request/test_access_consultation_pages.py @@ -9,7 +9,7 @@ def test_accessing_when_flag_is_on(client): consultation = ConsultationFactory() assert client.get("/").status_code == 200 - assert client.get(f"/consultations/{consultation.slug}").status_code == 200 + assert client.get(f"/consultations/{consultation.slug}/").status_code == 200 @pytest.mark.django_db @@ -17,4 +17,4 @@ def test_accessing_when_flag_is_on(client): def test_accessing_when_flag_is_off(client): consultation = ConsultationFactory() assert client.get("/").status_code == 200 - assert client.get(f"/consultations/{consultation.slug}").status_code == 404 + assert client.get(f"/consultations/{consultation.slug}/").status_code == 404 diff --git a/tests/request/test_support_pages.py b/tests/request/test_support_pages.py index 317d9235..39e24ac9 100644 --- a/tests/request/test_support_pages.py +++ b/tests/request/test_support_pages.py @@ -1,6 +1,19 @@ import pytest +from consultation_analyser.factories import ConsultationFactory + @pytest.mark.django_db -def test_no_login_ml_pipeline_page_support(client): - assert client.get("/support/ml-pipeline-test/").status_code == 302 +def test_no_login_support_pages(client): + ConsultationFactory(slug="consultation-slug") + support_urls = [ + "", + "sign-out/", + "consultations/", + "consultations/consultation-slug/", + ] + for url in support_urls: + full_url = f"/support/{url}" + response = client.get(full_url) + print(full_url) + assert response.status_code == 302 # No access, redirect to admin login From 0628c1522baa765db0c6f2452af88136ca6a8001 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Fri, 19 Apr 2024 08:05:23 +0100 Subject: [PATCH 23/25] more tests for support area --- .../integration/test_logging_in_to_support.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_logging_in_to_support.py b/tests/integration/test_logging_in_to_support.py index 40d0a033..881a6546 100644 --- a/tests/integration/test_logging_in_to_support.py +++ b/tests/integration/test_logging_in_to_support.py @@ -1,6 +1,7 @@ import pytest -from consultation_analyser.consultations.models import Consultation +from consultation_analyser.consultations.dummy_data import DummyConsultation +from consultation_analyser.consultations.models import Consultation, Theme from consultation_analyser.factories import UserFactory @@ -37,6 +38,25 @@ def test_generating_dummy_data(django_app): # Check dummy data button does generate a new consultation initial_count = Consultation.objects.all().count() - consultations_page.form.submit("generate_dummy_consultation") + consultations_page = consultations_page.form.submit("generate_dummy_consultation") count_after_dummy_data = Consultation.objects.all().count() assert count_after_dummy_data > initial_count + + # Check redirected to individual consultation page in support + latest_consultation = Consultation.objects.all().order_by("created_at").last() + next_page = consultations_page.click(latest_consultation.name) + assert "Generate themes" in next_page + + +@pytest.mark.django_db +def test_generate_themes(django_app): + DummyConsultation(name="Test consultation", slug="test-consultation", responses=5, include_themes=False) + UserFactory(email="email@example.com", password="admin", is_staff=True) # pragma: allowlist secret + login_page = django_app.get("/support/consultations/test-consultation/").follow() + login_page.form["username"] = "email@example.com" + login_page.form["password"] = "admin" # pragma: allowlist secret + consultation_page = login_page.form.submit().follow() + assert "Test consultation" in consultation_page + consultation_page = consultation_page.form.submit("generate_themes") + generated_themes = Theme.objects.filter(answer__question__section__consultation__slug="test-consultation") + assert generated_themes.exists() From 908506529c636b8c98c698de7c044117cbc478b9 Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Fri, 19 Apr 2024 08:33:03 +0100 Subject: [PATCH 24/25] More tweaks to tests for console pages. --- ...t_logging_in_to_support.py => test_support_console_pages.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/integration/{test_logging_in_to_support.py => test_support_console_pages.py} (98%) diff --git a/tests/integration/test_logging_in_to_support.py b/tests/integration/test_support_console_pages.py similarity index 98% rename from tests/integration/test_logging_in_to_support.py rename to tests/integration/test_support_console_pages.py index 881a6546..2edde0a0 100644 --- a/tests/integration/test_logging_in_to_support.py +++ b/tests/integration/test_support_console_pages.py @@ -50,7 +50,7 @@ def test_generating_dummy_data(django_app): @pytest.mark.django_db def test_generate_themes(django_app): - DummyConsultation(name="Test consultation", slug="test-consultation", responses=5, include_themes=False) + DummyConsultation(name="Test consultation", slug="test-consultation", include_themes=False) UserFactory(email="email@example.com", password="admin", is_staff=True) # pragma: allowlist secret login_page = django_app.get("/support/consultations/test-consultation/").follow() login_page.form["username"] = "email@example.com" From 548b4b9f116a7d41e4635c54f418472255a5630a Mon Sep 17 00:00:00 2001 From: Nina Menezes Date: Fri, 19 Apr 2024 10:41:57 +0100 Subject: [PATCH 25/25] Remove messages - to be considered in a separate PR. --- consultation_analyser/support_console/views.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/consultation_analyser/support_console/views.py b/consultation_analyser/support_console/views.py index eb3f980f..4344505e 100644 --- a/consultation_analyser/support_console/views.py +++ b/consultation_analyser/support_console/views.py @@ -22,14 +22,14 @@ def sign_out(request: HttpRequest): @staff_member_required def show_consultations(request: HttpRequest) -> HttpResponse: + # TODO - add messages if request.POST: try: dummy_data.DummyConsultation(include_themes=False) - messages.add_message(request, messages.INFO, "New consultation generated") except RuntimeError as error: - messages.add_message(request, messages.WARNING, error.args[0]) + pass + # TODO - pass through message from the error consultations = models.Consultation.objects.all() - # TODO - do something with messages context = {"consultations": consultations, "development_env": HostingEnvironment.is_development_environment()} return render(request, "support_console/all-consultations.html", context=context) @@ -43,9 +43,6 @@ def show_consultation(request: HttpRequest, consultation_slug: str) -> HttpRespo ).exists() if not themes_already_exist: ml_pipeline.save_themes_for_consultation(consultation_id=consultation.id) - messages.add_message(request, messages.INFO, "Themes created for consultation") - else: - messages.add_message(request, messages.INFO, "Themes already exist for this consultation") - # TODO - do something with messages + # TODO - pass through messages - "themes created" or "consultation already has themes" context = {"consultation": consultation} return render(request, "support_console/consultation.html", context=context)