Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions apps/nominations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,13 @@ def visible(self, user=None):
if self.accepted and self.approved and not self.election.nominations_open:
return True

if user is None:
if user is None or not user.is_authenticated:
return False

return bool(user.is_staff or user == self.user)
if user.is_staff or user == self.user:
return True

return self.nominations.filter(election=self.election, nominator=user).exists()


class Nomination(models.Model):
Expand Down
56 changes: 56 additions & 0 deletions apps/nominations/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,62 @@ def test_nomination_create_404s(self):
self.assertEqual(self.client.get(url).status_code, 404)


class OpenNomineeVisibilityTests(TestCase):
def setUp(self):
self.nominator = UserFactory(first_name="Ada", last_name="Lovelace")
self.other_user = UserFactory()
self.election = open_election("2026 Board Election")
self.other_election = open_election("2027 Board Election")

self.nominated = Nominee.objects.create(
user=UserFactory(first_name="Grace", last_name="Hopper"),
election=self.election,
)
Nomination.objects.create(
election=self.election,
nominator=self.nominator,
nominee=self.nominated,
name="Grace Hopper",
email="grace@example.com",
nomination_statement="A strong candidate.",
)

self.own_candidacy = Nominee.objects.create(user=self.nominator, election=self.election)
Nomination.objects.create(
election=self.election,
nominator=self.other_user,
nominee=self.own_candidacy,
name=self.nominator.get_full_name(),
email=self.nominator.email,
nomination_statement="Another strong candidate.",
)

self.unrelated = Nominee.objects.create(user=UserFactory(), election=self.election)
self.other_election_candidacy = Nominee.objects.create(user=self.nominator, election=self.other_election)
self.client.force_login(self.nominator)

def _list_url(self):
return reverse("nominations:nominees_list", kwargs={"election": self.election.slug})

def test_list_shows_only_nominees_relevant_to_user_in_current_election(self):
response = self.client.get(self._list_url())

self.assertEqual(response.status_code, 200)
self.assertCountEqual(response.context["object_list"], [self.nominated, self.own_candidacy])

def test_nominator_can_view_their_nominee_while_nominations_are_open(self):
response = self.client.get(self.nominated.get_absolute_url())

self.assertEqual(response.status_code, 200)

def test_unrelated_user_cannot_view_nominee_while_nominations_are_open(self):
self.client.force_login(self.other_user)

response = self.client.get(self.nominated.get_absolute_url())

self.assertEqual(response.status_code, 404)


class NominationCreateFormSelectionTests(TestCase):
def setUp(self):
self.user = UserFactory()
Expand Down
8 changes: 7 additions & 1 deletion apps/nominations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django.contrib import messages
from django.contrib.auth.mixins import UserPassesTestMixin
from django.db.models import Q
from django.http import Http404, JsonResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse
Expand Down Expand Up @@ -72,7 +73,12 @@ def get_queryset(self, *args, **kwargs):
return Nominee.objects.filter(accepted=True, approved=True, election=election).exclude(user=None)

if self.request.user.is_authenticated:
return Nominee.objects.filter(user=self.request.user)
return (
Nominee.objects.filter(election=election)
.filter(Q(user=self.request.user) | Q(nominations__nominator=self.request.user))
.exclude(user=None)
.distinct()
)
return None


Expand Down