Skip to content

Commit

Permalink
Add the organization to the candidate vote
Browse files Browse the repository at this point in the history
  • Loading branch information
tudoramariei committed Dec 1, 2024
1 parent 1aeb292 commit 7942d96
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 90 deletions.
4 changes: 2 additions & 2 deletions backend/hub/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ def confirmations_count(self, obj):

class CandidateVoteInline(admin.TabularInline):
model = CandidateVote
fields = ["user", "candidate"]
readonly_fields = ["user", "candidate", "domain"]
fields = ["user", "organization", "candidate"]
readonly_fields = ["user", "organization", "candidate", "domain"]
extra = 0

def has_add_permission(self, request, obj=None):
Expand Down
20 changes: 20 additions & 0 deletions backend/hub/migrations/0078_candidatevote_organization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.16 on 2024-12-01 16:53

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("hub", "0077_candidate_old_domain"),
]

operations = [
migrations.AddField(
model_name="candidatevote",
name="organization",
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, to="hub.organization"),
preserve_default=False,
),
]
6 changes: 4 additions & 2 deletions backend/hub/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ def _remove_votes_supports_candidates(self):

if FeatureFlag.flag_enabled(PHASE_CHOICES.enable_candidate_voting):
# Remove votes that the organization has given
for vote in CandidateVote.objects.filter(user__organization=self):
for vote in CandidateVote.objects.filter(organization=self):
vote.delete()

def _change_candidates_domain(self, voting_domain):
Expand Down Expand Up @@ -983,6 +983,8 @@ def __str__(self):

class CandidateVote(TimeStampedModel, CandidateAction):
user = models.ForeignKey(UserModel, on_delete=models.PROTECT)
organization = models.ForeignKey(Organization, on_delete=models.PROTECT)

candidate = models.ForeignKey("Candidate", on_delete=models.CASCADE, related_name="votes")
domain = models.ForeignKey("Domain", on_delete=models.PROTECT, related_name="votes")

Expand All @@ -996,7 +998,7 @@ class Meta:
def save(self, *args, **kwargs):
self.domain = self.candidate.domain

votes_for_domain = CandidateVote.objects.filter(user=self.user, domain=self.domain).count()
votes_for_domain = CandidateVote.objects.filter(organization=self.organization, domain=self.domain).count()
if votes_for_domain >= self.domain.seats:
raise Exception("Maximum number of votes reached")

Expand Down
7 changes: 4 additions & 3 deletions backend/hub/templates/hub/candidate/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

{% if candidate.old_domain %}
<p class="section-text">
Candidatura a fost depusă pe domeniul "{{ candidate.old_domain.name}}".
Candidatura a fost depusă pe domeniul "{{ candidate.old_domain.name }}".
Organizația a solicitat modificarea domeniului ca elector după evaluarea candidaturilor.
</p>
{% endif %}
Expand Down Expand Up @@ -125,10 +125,11 @@
{% endif %}

{% else %}

<p class="button is-disabled">
{% trans "Vote" %}
{% trans "You can't vote this candidate" %}
</p>

{% endif %}

{% endif %}
Expand Down
31 changes: 24 additions & 7 deletions backend/hub/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,27 @@ class ElectorCandidatesListView(LoginRequiredMixin, SearchMixin):
paginate_by = 9
template_name = "hub/ngo/votes.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)

domains = []

if FeatureFlag.flag_enabled(SETTINGS_CHOICES.enable_voting_domain):
user_org = self.request.user.organization
if user_org and user_org.voting_domain:
domains = [user_org.voting_domain]
else:
domains = Domain.objects.order_by("id").all()

context["domains"] = domains

return context

def get_queryset(self):
if not self.request.user.groups.filter(name__in=[NGO_GROUP, NGO_USERS_GROUP]).exists():
raise PermissionDenied

voted_candidates = CandidateVote.objects.filter(user=self.request.user)
voted_candidates = CandidateVote.objects.filter(organization__pk=self.request.user.organization_id)
return [element.candidate for element in voted_candidates]


Expand Down Expand Up @@ -766,15 +782,16 @@ def _get_candidate_vote_context(self, user: User, candidate: Candidate) -> Dict[
domain = candidate.domain

# An organization can only vote for candidates from its own domain
if user.organization and not user.organization.is_elector(domain):
user_org = user.organization
if user_org and not user_org.is_elector(domain):
return context

context["can_vote_candidate"] = True

if CandidateVote.objects.filter(user__pk__in=user.org_user_pks(), candidate=candidate).exists():
if CandidateVote.objects.filter(organization=user_org, candidate=candidate).exists():
context["voted_candidate"] = True

if CandidateVote.objects.filter(user__in=user.org_user_pks(), domain=domain).count() >= domain.seats:
if CandidateVote.objects.filter(organization=user_org, domain=domain).count() >= domain.seats:
context["used_all_domain_votes"] = True

return context
Expand Down Expand Up @@ -1010,11 +1027,11 @@ def candidate_vote(request, pk):
if user_org.status != Organization.STATUS.accepted:
raise PermissionDenied

if CandidateVote.objects.filter(user__pk__in=request.user.org_user_pks(), candidate=candidate).exists():
raise PermissionDenied
if CandidateVote.objects.filter(organization_id=user_org.id, candidate=candidate).exists():
raise PermissionDenied(_("A candidate can't be voted twice by the same organization."))

try:
vote = CandidateVote.objects.create(user=request.user, candidate=candidate)
vote = CandidateVote.objects.create(user=request.user, organization=user_org, candidate=candidate)
except Exception:
raise PermissionDenied

Expand Down
Loading

0 comments on commit 7942d96

Please sign in to comment.