Skip to content

Commit

Permalink
Update frontend cancellation text logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Bekabyx committed Oct 5, 2023
1 parent 69d8c49 commit 79a9bab
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 96 deletions.
27 changes: 19 additions & 8 deletions wcivf/apps/elections/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,19 +539,30 @@ def short_cancelled_message_html(self):
if not self.cancelled:
return ""
message = None
if self.metadata and self.metadata.get("cancelled_election"):
title = self.metadata["cancelled_election"].get("title")
url = self.metadata["cancelled_election"].get("url")
message = title
if url:
message = """<strong> ❌ <a href="{}">{}</a></strong>""".format(
url, title
)

if self.cancellation_reason:
if self.cancellation_reason == "CANDIDATE_DEATH":
message = """<strong> ❌ This election has been cancelled due to the death of a candidate.</strong>"""
else:
message = """<strong> ❌ The poll for this election will not take place because it is uncontested.</strong>"""
else:
# Leaving this in for now as we transition away from metadata
if self.metadata and self.metadata.get("cancelled_election"):
title = self.metadata["cancelled_election"].get("title")
url = self.metadata["cancelled_election"].get("url")
message = title
if url:
message = (
"""<strong> ❌ <a href="{}">{}</a></strong>""".format(
url, title
)
)
if not message:
if self.election.in_past:
message = "(The poll for this election was cancelled)"
else:
message = "<strong>(The poll for this election has been cancelled)</strong>"

return mark_safe(message)

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
{% load static %}
{% load i18n %}

{% if not object.contested and not object.metadata.cancelled_election %}
{% comment %} Case 1: Election cancelled, uncontested, number of candidates equal seats, no metadata{% endcomment %}
{% if object.winner_count == object.people.count %}
{% if object.cancellation_reason %}
{% if object.cancellation_reason == "EQUAL_CANDIDATES" %}
<h4>{% trans "Uncontested Election" %}</h4>

<p>
{% blocktrans trimmed with is_or_are=object.winner_count|pluralize:"is,are" winner_count=object.winner_count|apnumber post=object.post.full_label num_people=object.people.count|apnumber pluralise_candidates=object.people|pluralize pluralise_seat=object.winner_count|pluralize %}
This election was uncontested because the number of candidates who stood was equal to the number of available seats.
This election was cancelled because the number of candidates who stood was equal to the number of available seats.
There {{ is_or_are }} {{ winner_count }} seat{{ pluralise_seat }} in {{ post }}, and only {{ num_people }} candidate{{ pluralise_candidates }}.
{% endblocktrans %}
</p>
Expand All @@ -20,34 +18,46 @@ <h4>{% trans "Uncontested Election" %}</h4>
the winner{{ pluralise_candidates }}.
{% endblocktrans %}
</p>
{% comment %} Case 2: Election cancelled, uncontested and there are fewer candidates than seats, no metadata {% endcomment %}
{% elif object.winner_count > object.people.count %}
{% elif object.cancellation_reason == "UNDER_CONTESTED" %}
<h4>{% trans "Uncontested and Rescheduled Election" %}</h4>

<p>
{% blocktrans trimmed with winner_count=object.winner_count|apnumber post_label=object.post.full_label num_people=object.people.count|apnumber count counter=object.people.count %}
This election was uncontested because the number of candidates who stood was fewer than the number of available seats.
This election was cancelled because the number of candidates who stood was fewer than the number of available seats.
There is {{ winner_count }} seat in {{ post_label }}, and {{ num_people }} candidate.
{% plural %}
This election was uncontested because the number of candidates who stood was fewer than the number of available seats.
This election was cancelled because the number of candidates who stood was fewer than the number of available seats.
There are {{ winner_count }} seats in {{ post_label }}, and {{ num_people }} candidates.
{% endblocktrans %}
{% blocktrans trimmed with has_or_have=object.people|pluralize:"s,ve" plural=object.people|pluralize %}
No votes will be cast, and the candidate{{ plural }} below
ha{{ has_or_have }} been automatically declared the
winner{{ plural }}.

A new election to fill the unclaimed seat{{ plural }}
will be held within 35 working days of the original election date.
{% endblocktrans %}
</p>
{% comment %} Case 3: Election cancelled, uncontested and zero candidates, no metadata {% endcomment %}
{% if object.people %}
<p>
{% blocktrans trimmed with has_or_have=object.people|pluralize:"s,ve" plural=object.people|pluralize %}
No votes will be cast, and the candidate{{ plural }} below
ha{{ has_or_have }} been automatically declared the
winner{{ plural }}.
{% elif object.cancellation_reason == "NO_CANDIDATES" %}
<h4>{% trans "Uncontested and Rescheduled Election" %}</h4>
<p>
{% blocktrans %}
This election was cancelled because no candidates stood for the available seats.

A new election to fill the unclaimed seat{{ plural }}
will be held within 35 working days of the original election date.
{% endblocktrans %}
</p>
{% endif %}
A new election to fill the unclaimed seat{{ plural }}
will be held within 35 working days of the original election date.
{% endblocktrans %}
</p>
{% elif object.cancellation_reason == "CANDIDATE_DEATH" %}
<h4>{% trans "Cancelled and Rescheduled Election" %}</h4>
<p>
{% blocktrans %}
This election was cancelled due to the death of a candidate.

A new election to fill the unclaimed seat{{ plural }}
will be held within 35 working days of the original election date.
{% endblocktrans %}
</p>
{% endif %}
{% comment %} Case 4: Contested but cancelled for other reasons {% endcomment %}
{% else %}
{% if object.metadata.cancelled_election %}
<h4>{{ object.metadata.cancelled_election.title }}</h4>
Expand Down Expand Up @@ -75,4 +85,3 @@ <h4>{% trans "Cancelled Election" %}</h4>
<a href="{{ object.metadata.cancelled_election.url }}">{% trans "Read more" %}</a>
{% endif %}
</p>

128 changes: 64 additions & 64 deletions wcivf/apps/elections/tests/test_election_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,19 +235,9 @@ def test_num_candidates(self):
response, f"See all 5 candidates in the {self.post.label}"
)

def test_cancelled_with_metadata(self):
"""Case 1: Cancelled election and Metadata
is set in EE"""
self.post_election.winner_count = 4
people = [PersonFactory() for p in range(4)]
for person in people:
PersonPostFactory(
post_election=self.post_election,
election=self.election,
post=self.post,
person=person,
)
def test_cancellation_reason_candidate_death(self):
self.post_election.cancelled = True
self.post_election.cancellation_reason = "CANDIDATE_DEATH"
self.post_election.save()
response = self.client.get(
self.post_election.get_absolute_url(), follow=True
Expand All @@ -266,104 +256,114 @@ def test_cancelled_with_metadata(self):
self.assertNotContains(response, "No candidates known yet.")
self.assertContains(
response,
f"{self.post_election.election.name}: This election has been cancelled",
"This election was cancelled due to the death of a candidate.",
)

def test_cancelled_uncontested_and_equal(self):
"""Case 2: Election cancelled, uncontested,
number of candidates equal seats, no metadata"""
self.post_election.winner_count = 4
people = [PersonFactory() for p in range(4)]
for person in people:
PersonPostFactory(
post_election=self.post_election,
election=self.election,
post=self.post,
person=person,
)
self.post_election.contested = False
def test_cancellation_reason_no_candidates(self):
self.post_election.cancelled = True
self.post_election.metadata = None
self.post_election.cancellation_reason = "NO_CANDIDATES"
self.post_election.save()
response = self.client.get(
self.post_election.get_absolute_url(), follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "elections/post_view.html")
self.assertTemplateUsed(
response, "elections/includes/_post_meta_title.html"
)
self.assertTemplateUsed(
response, "elections/includes/_post_meta_description.html"
)
self.assertTemplateUsed(
response, "elections/includes/_cancelled_election.html"
)
self.assertContains(response, "Uncontested Election")
self.assertNotContains(response, "No candidates known yet.")
self.assertContains(
response,
"No votes will be cast, and the candidates below have been automatically declared",
"This election was cancelled because no candidates stood for the available seats",
)
self.assertNotContains(response, "This election was cancelled.")

def test_cancelled_uncontested_and_fewer_candidates(self):
"""Case 3: Election cancelled, uncontested,
number of candidates fewer than seats, no
metadata"""
self.post_election.winner_count = 5
people = [PersonFactory() for p in range(4)]
for person in people:
PersonPostFactory(
post_election=self.post_election,
election=self.election,
post=self.post,
person=person,
)
self.post_election.contested = False
self.post_election.metadata = None
def test_cancellation_reason_equal_candidates(self):
self.post_election.cancelled = True
self.post_election.cancellation_reason = "EQUAL_CANDIDATES"
self.post_election.save()

response = self.client.get(
self.post_election.get_absolute_url(), follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "elections/post_view.html")
self.assertTemplateUsed(
response, "elections/includes/_post_meta_title.html"
)
self.assertTemplateUsed(
response, "elections/includes/_post_meta_description.html"
)
self.assertTemplateUsed(
response, "elections/includes/_cancelled_election.html"
)

self.assertNotContains(response, "No candidates known yet.")
self.assertContains(
response,
"This election was uncontested because the number of candidates who stood was fewer than the number of available seats.",
"This election was cancelled because the number of candidates who stood was equal to the number of available seats.",
)
self.assertNotContains(response, "This election was cancelled.")

def test_cancelled_uncontested_no_candidates(self):
"""Case 4: Election cancelled, uncontested,
zero candidates, no metadata"""
self.post_election.winner_count = 4
def test_cancellation_reason_under_contested(self):
self.post_election.cancelled = True
self.post_election.contested = False
self.post_election.metadata = None
self.post_election.cancellation_reason = "UNDER_CONTESTED"
self.post_election.save()
response = self.client.get(
self.post_election.get_absolute_url(), follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "elections/post_view.html")
self.assertTemplateUsed(
response, "elections/includes/_post_meta_title.html"
)
self.assertTemplateUsed(
response, "elections/includes/_post_meta_description.html"
)
self.assertTemplateUsed(
response, "elections/includes/_cancelled_election.html"
)
self.assertNotContains(response, "No votes will be cast")
self.assertNotContains(response, "have been automatically declared")
self.assertNotContains(response, "No candidates known yet.")
self.assertContains(
response,
"This election was cancelled because the number of candidates who stood was fewer than the number of available seats.",
)

def test_cancelled_contested(self):
"""Case 5: Election cancelled, contested,
no metadata"""
def test_cancelled_with_metadata(self):
"""Case 1: Cancelled election and Metadata
is set in EE"""
self.post_election.winner_count = 4
people = [PersonFactory() for p in range(4)]
for person in people:
PersonPostFactory(
post_election=self.post_election,
election=self.election,
post=self.post,
person=person,
)
self.post_election.cancelled = True
self.post_election.contested = True
self.post_election.metadata = None
self.post_election.save()
response = self.client.get(
self.post_election.get_absolute_url(), follow=True
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "elections/post_view.html")
self.assertTemplateUsed(
response, "elections/includes/_post_meta_title.html"
)
self.assertTemplateUsed(
response, "elections/includes/_post_meta_description.html"
)
self.assertTemplateUsed(
response, "elections/includes/_cancelled_election.html"
)
self.assertContains(response, "This election was cancelled.")
self.assertNotContains(response, "No votes will be cast")
self.assertNotContains(response, "No candidates known yet.")
self.assertContains(
response,
f"{self.post_election.election.name}: This election has been cancelled",
)

def test_previous_cancelled_elections(self):
"""
Expand Down
27 changes: 27 additions & 0 deletions wcivf/apps/elections/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,30 @@ def test_past_expected_sopn_day(self, post_election, mocker, subtests):
return_value=date[0],
)
assert post_election.past_expected_sopn_day is date[1]

def test_short_cancelled_message_html(self, post_election):
assert post_election.short_cancelled_message_html == ""

post_election.cancelled = True
assert (
post_election.short_cancelled_message_html
== "(The poll for this election was cancelled)"
)

cancellation_reasons = [
"EQUAL_CANDIDATES",
"NO_CANDIDATES",
"UNDER_CONTESTED",
]
for reason in cancellation_reasons:
post_election.cancellation_reason = reason
assert (
post_election.short_cancelled_message_html
== "<strong> ❌ The poll for this election will not take place because it is uncontested.</strong>"
)

post_election.cancellation_reason = "CANDIDATE_DEATH"
assert (
post_election.short_cancelled_message_html
== "<strong> ❌ This election has been cancelled due to the death of a candidate.</strong>"
)

0 comments on commit 79a9bab

Please sign in to comment.