summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/templates/core/base.html55
-rw-r--r--engagements/forms.py11
-rw-r--r--engagements/templates/engagements/engagement_form.html5
-rw-r--r--engagements/tests/conftest.py39
-rw-r--r--engagements/tests/test_forms.py148
-rw-r--r--engagements/views.py6
6 files changed, 198 insertions, 66 deletions
diff --git a/core/templates/core/base.html b/core/templates/core/base.html
index 1bf6886..2a3f446 100644
--- a/core/templates/core/base.html
+++ b/core/templates/core/base.html
@@ -8,37 +8,42 @@
<link rel="stylesheet" href="{% static 'css/output.css' %}">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
- <script src="https://unpkg.com/htmx.org@1.9.0" integrity="sha384-aOxz9UdWG0yBiyrTwPeMibmaoq07/d3a96GCbb9x60f3mOt5zwkjdbcHFnKH8qls" crossorigin="anonymous"></script>
+ <script src="https://unpkg.com/htmx.org@1.9.0"
+ integrity="sha384-aOxz9UdWG0yBiyrTwPeMibmaoq07/d3a96GCbb9x60f3mOt5zwkjdbcHFnKH8qls"
+ crossorigin="anonymous"></script>
<title>{% block title %}{% endblock title %}</title>
{% block extra_head_tags %}{% endblock extra_head_tags %}
</head>
<body>
{% block navbar %}
-<nav class="bg-blue-600 p-4">
- <div class="container mx-auto flex items-center justify-between">
- <div class="flex items-center space-x-4">
- <a href="#" class="text-white text-xl font-semibold">Home</a>
- <a href="{% url 'engagements:home' %}" class="text-white hover:text-blue-200">Engagement Plans</a>
- <a href="{% url 'engagements:regulatedentities' %}" class="text-white hover:text-blue-200">Regulated Entities</a>
- <a href="#" class="text-white hover:text-blue-200">Reporting</a>
- <a href="#" class="text-white hover:text-blue-200">Dashboards</a>
- </div>
- <div class="flex items-center space-x-4">
- {% if request.user.is_authenticated %}
- <span class="text-white">{{ user }}</span>
- <a href="{% url 'logout' %}" class="text-white hover:text-blue-200">Log Out</a>
- {% else %}
- <a href="{% url 'login' %}" class="text-white hover:text-blue-200">Log In</a>
- {% endif %}
- <a href="#" class="text-white hover:text-blue-200">Help</a>
- </div>
- </div>
-</nav>
+ <nav class="bg-blue-600 p-4">
+ <div class="container mx-auto flex items-center justify-between">
+ <div class="flex items-center space-x-4">
+ <a href="#" class="text-white text-xl font-semibold">Home</a>
+ <a href="{% url 'engagements:home' %}" class="text-white hover:text-blue-200">Engagement Plans</a>
+ <a href="{% url 'engagements:regulatedentities' %}" class="text-white hover:text-blue-200">Regulated
+ Entities</a>
+ <a href="#" class="text-white hover:text-blue-200">Reporting</a>
+ <a href="#" class="text-white hover:text-blue-200">Dashboards</a>
+ </div>
+ <div class="flex items-center space-x-4">
+ {% if request.user.is_authenticated %}
+ <span class="text-white">{{ user }}</span>
+ <a href="{% url 'logout' %}" class="text-white hover:text-blue-200">Log Out</a>
+ {% else %}
+ <a href="{% url 'login' %}" class="text-white hover:text-blue-200">Log In</a>
+ {% endif %}
+ <a href="#" class="text-white hover:text-blue-200">Help</a>
+ </div>
+ </div>
+ </nav>
{% endblock navbar %}
- <div class="container mx-auto">
- {% block content %}
- {% endblock content %}
- </div>
+<div class="container mx-auto">
+ {% block content %}
+ {% block messages %}
+ {% endblock messages %}
+ {% endblock content %}
+</div>
</body>
</html>
diff --git a/engagements/forms.py b/engagements/forms.py
index 2532892..0b097df 100644
--- a/engagements/forms.py
+++ b/engagements/forms.py
@@ -1,5 +1,6 @@
from django import forms
from django.forms.widgets import HiddenInput
+from django.core.exceptions import ValidationError
from .models import Engagement, EngagementEffort
@@ -187,6 +188,16 @@ class EngagementCreateForm(forms.ModelForm):
except KeyError:
pass
+ def clean_proposed_end_date(self):
+ proposed_start_date = self.cleaned_data["proposed_start_date"]
+ proposed_end_date = self.cleaned_data["proposed_end_date"]
+
+ if proposed_start_date and proposed_end_date:
+ if proposed_start_date > proposed_end_date:
+ raise ValidationError("The proposed start date must be before the proposed end date.")
+
+ return proposed_start_date
+
class Meta:
model = Engagement
fields = [
diff --git a/engagements/templates/engagements/engagement_form.html b/engagements/templates/engagements/engagement_form.html
index a0cdea2..89f6b0e 100644
--- a/engagements/templates/engagements/engagement_form.html
+++ b/engagements/templates/engagements/engagement_form.html
@@ -44,7 +44,7 @@
{% endfor %}
</div>
</div>
-
+
<div>
{{ form.proposed_start_date.label_tag }}
<div class="my-2">
@@ -57,6 +57,9 @@
<div class="my-2">
{% render_field form.proposed_end_date class+="block w-full rounded-md border-0 p-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %}
</div>
+ {% for error in form.proposed_end_date.errors %}
+ <p class="text-red-500 text-sm">{{ error }}</p>
+ {% endfor %}
</div>
<div>
diff --git a/engagements/tests/conftest.py b/engagements/tests/conftest.py
new file mode 100644
index 0000000..cb0b9e0
--- /dev/null
+++ b/engagements/tests/conftest.py
@@ -0,0 +1,39 @@
+import pytest
+
+from engagements.models import EngagementType, Organisation, Engagement
+from myuser.models import TeamUser
+
+
+@pytest.fixture
+def engagement():
+ data = {
+ "proposed_start_date": "2022-10-01",
+ "engagement_type": EngagementType.objects.create(name="ET1"),
+ "external_party": Organisation.objects.create(name="O1"),
+ }
+ return Engagement.objects.create(**data)
+
+
+@pytest.fixture
+def user():
+ return TeamUser.objects.create_user(email="ming@ming.com")
+
+
+@pytest.fixture
+def engagement_type():
+ return EngagementType.objects.create(name="ET2")
+
+
+@pytest.fixture
+def external_party():
+ return Organisation.objects.create(name="O2")
+
+
+@pytest.fixture
+def user1():
+ return TeamUser.objects.create_user(email="user1@example.com")
+
+
+@pytest.fixture
+def user2():
+ return TeamUser.objects.create_user(email="user2@example.com")
diff --git a/engagements/tests/test_forms.py b/engagements/tests/test_forms.py
index b6aab9a..3c213c5 100644
--- a/engagements/tests/test_forms.py
+++ b/engagements/tests/test_forms.py
@@ -1,45 +1,113 @@
-from django.test import TestCase
+import pytest
+from django.forms import DateInput, Select, SelectMultiple
+from engagements.forms import EngagementCreateForm
from engagements.forms import EngagementEffortCreateForm
-from engagements.models import Engagement, EngagementType, Organisation
-from myuser.models import TeamUser
+from engagements.models import EngagementType
+pytestmark = pytest.mark.django_db
-class EngagementEffortCreate(TestCase):
- def setUp(self):
- data = {
- "proposed_start_date": "2022-10-01",
- "engagement_type": EngagementType.objects.create(name="ET1"),
- "external_party": Organisation.objects.create(name="O1"),
+def test_basic_validation(engagement, user):
+ form = EngagementEffortCreateForm(
+ data={
+ "is_planned": True,
+ "proposed_start_date": "2022-10-10 10:00",
+ "proposed_end_date": "2022-10-10 12:00",
+ "engagement": engagement,
+ "effort_type": "PLANNING",
+ "officers": [user],
}
- self.e = Engagement.objects.create(**data)
- self.user = TeamUser.objects.create_user(email="ming@ming.com")
-
- def test_basic_validation(self):
- form = EngagementEffortCreateForm(
- data={
- "is_planned": True,
- "proposed_start_date": "2022-10-10 10:00",
- "proposed_end_date": "2022-10-10 12:00",
- "engagement": self.e,
- "effort_type": "PLANNING",
- "officers": [self.user],
- }
- )
- self.assertFalse(form.errors)
-
- def test_basic_validation_on_bad_entry(self):
- form = EngagementEffortCreateForm(
- data={
- "is_planned": True,
- "proposed_start_date": "20240-10-10 10:00",
- "proposed_end_date": "2022-10-10 12:00",
- "engagement": self.e,
- "effort_type": "bobbins",
- "officers": [self.user],
- "sub_instruments": [""],
- }
- )
- self.assertTrue(form.errors["effort_type"])
- self.assertTrue(form.errors["proposed_start_date"])
- self.assertTrue(form.errors["sub_instruments"])
+ )
+ assert not form.errors
+
+
+def test_basic_validation_on_bad_entry(engagement, user):
+ form = EngagementEffortCreateForm(
+ data={
+ "is_planned": True,
+ "proposed_start_date": "20240-10-10 10:00",
+ "proposed_end_date": "2022-10-10 12:00",
+ "engagement": engagement,
+ "effort_type": "bobbins",
+ "officers": [user],
+ "sub_instruments": [""],
+ }
+ )
+ assert "effort_type" in form.errors
+ assert "proposed_start_date" in form.errors
+
+
+def test_form_fields():
+ form = EngagementCreateForm()
+ expected_fields = [
+ "proposed_start_date",
+ "proposed_end_date",
+ "engagement_type",
+ "external_party",
+ "officers",
+ ]
+ assert list(form.fields.keys()) == expected_fields
+
+
+def test_form_labels():
+ form = EngagementCreateForm()
+ assert form.fields["officers"].label == "Inspectors"
+
+
+def test_form_help_texts():
+ form = EngagementCreateForm()
+ assert form.fields["proposed_start_date"].help_text == "<small><em>YYYY-MM-DD</em></small>"
+ assert form.fields["proposed_end_date"].help_text == "<small><em>YYYY-MM-DD</em></small>"
+
+
+def test_form_widgets():
+ form = EngagementCreateForm()
+ assert isinstance(form.fields["proposed_start_date"].widget, DateInput)
+ assert isinstance(form.fields["proposed_end_date"].widget, DateInput)
+ assert isinstance(form.fields["engagement_type"].widget, Select)
+ assert isinstance(form.fields["officers"].widget, SelectMultiple)
+
+
+def test_form_valid_data(engagement_type, external_party, user1, user2):
+ form_data = {
+ "proposed_start_date": "2023-01-01",
+ "proposed_end_date": "2023-01-31",
+ "engagement_type": engagement_type.id,
+ "external_party": external_party.id,
+ "officers": [user1.id, user2.id],
+ }
+ form = EngagementCreateForm(data=form_data)
+ assert form.is_valid()
+
+
+def test_form_invalid_dates(engagement_type, external_party, user1):
+ form_data = {
+ "proposed_start_date": "2023-01-31",
+ "proposed_end_date": "2023-01-01",
+ "engagement_type": engagement_type.id,
+ "external_party": external_party.id,
+ "officers": [user1.id],
+ }
+ form = EngagementCreateForm(data=form_data)
+ assert not form.is_valid()
+
+
+def test_form_missing_required_fields():
+ form_data = {
+ "proposed_start_date": "2023-01-01",
+ }
+ form = EngagementCreateForm(data=form_data)
+ assert not form.is_valid()
+ assert "engagement_type" in form.errors
+ assert "external_party" in form.errors
+
+
+def test_form_engagement_type_queryset():
+ initial_data = {"engagement_type": EngagementType.objects.all()}
+ form = EngagementCreateForm(initial=initial_data)
+ assert form.fields["engagement_type"].queryset == initial_data["engagement_type"]
+
+
+def test_form_engagement_type_queryset_without_initial():
+ form = EngagementCreateForm()
+ assert list(form.fields["engagement_type"].queryset) == list(EngagementType.objects.all())
diff --git a/engagements/views.py b/engagements/views.py
index a76a37d..88f2014 100644
--- a/engagements/views.py
+++ b/engagements/views.py
@@ -155,6 +155,12 @@ def engagement_create(request, slug, reg=None):
ef.external_party = Organisation.objects.get(slug=slug)
ef.save()
return redirect("engagements:plan_for_org", orgslug=slug)
+ else:
+ return render(
+ request,
+ "engagements/engagement_form.html",
+ {"form": form, "title": f"Create Engagement for {slug}", "errors": form.errors},
+ )
else:
if reg:
form = EngagementCreateForm(