diff --git a/scipost_django/colleges/models/nomination.py b/scipost_django/colleges/models/nomination.py index 4c0a5faf0ed4c5d7c5bdfa6426cf8118e70ab421..72e546b3b7ff93014b8238e5efeb3ea5aa0f2cf0 100644 --- a/scipost_django/colleges/models/nomination.py +++ b/scipost_django/colleges/models/nomination.py @@ -6,6 +6,8 @@ from django.db import models from django.utils import timezone from django.utils.functional import cached_property +from colleges.permissions import is_edadmin + from ..managers import ( FellowshipNominationQuerySet, FellowshipNominationVotingRoundQuerySet, @@ -239,6 +241,18 @@ class FellowshipNominationVotingRound(models.Model): else: return FellowshipNominationDecision.OUTCOME_NOT_ELECTED + def can_view(self, user) -> bool: + """Return whether the user can view this voting round. + They must be authenticated and have voting eligibility or be edadmin.""" + + eligibility_per_fellowship = [ + fellowship in self.eligible_to_vote.all() + for fellowship in user.contributor.fellowships.all() + ] + eligible_to_vote = any(eligibility_per_fellowship) + + return user.is_authenticated and (eligible_to_vote or is_edadmin(user)) + class FellowshipNominationVote(models.Model): VOTE_AGREE = "agree" diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html b/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html index 9cae025f1ec22f2d1de847ce1b29ba646863b823..4c0684f327f274747cb6685743f2adff72ab1d99 100644 --- a/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html @@ -124,11 +124,15 @@ </div> </div> + <div class="card"> + <div class="card-header">Voting Rounds</div> + <div class="card-body p-0"> + <div hx-get="{% url 'colleges:_hx_nomination_voting_rounds_tab' nomination_id=nomination.id round_id=nomination.latest_voting_round.id %}" + hx-trigger="intersect once"></div> + </div> + </div> - {% with round=nomination.voting_rounds.first %}TEMP BROKEN{% endwith %} - - - {% if "edadmin" in user_roles %} + {% comment %} {% if "edadmin" in user_roles %} <div class="row"> <div class="col"> <details class="border"> @@ -152,6 +156,8 @@ </details> </div> </div> - {% endif %} + {% else %} + {% include "colleges/_hx_voting_round_results.html" with voting_round=nomination.latest_voting_round %} + {% endif %} {% endcomment %} - </div> +</div> diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html b/scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html new file mode 100644 index 0000000000000000000000000000000000000000..5f923974836f65477d8c04084e6044ae0ede720f --- /dev/null +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html @@ -0,0 +1,28 @@ +<div id="nomination-{{ nomination_id }}-round-tab-holder"> + + <nav class="nav nav-pills m-2 overflow-scroll"> + + {% for voting_round in voting_rounds %} + <div type="button" class="nav-link {% if selected_round.id == voting_round.id %}active{% endif %} {% if voting_round.id in inaccessible_round_ids %}disabled opacity-50{% endif %}" + hx-get="{% url 'colleges:_hx_nomination_voting_rounds_tab' nomination_id=nomination_id round_id=voting_round.id %}" + hx-target="#nomination-{{ nomination_id }}-round-tab-holder" + hx-swap="outerHTML"> + <span class="d-block text-nowrap"> + <span class="d-flex justify-content-between"> + <span>Round #{{ forloop.counter0|add:1 }}</span> + {% if voting_round.is_open %} + <span class="text-success">Open</span> + {% endif %} + </span> + <small>{{ voting_round.voting_opens|date:"d M Y" }} - {{ voting_round.voting_deadline|date:"d M Y" }}</small> + </span> + </div> + {% endfor %} + + </nav> + + <div id="nomination-{{ nomination_id }}-round-{{ selected_round.id }}-tab-content-holder"> + {% include "colleges/_hx_voting_round_results.html" with voting_round=selected_round %} + </div> + +</div> diff --git a/scipost_django/colleges/urls.py b/scipost_django/colleges/urls.py index ba02334c726b134816fefe0e0f54427ae1305524..573d0916f90e436d03fc6735b10e29414ea96f5d 100644 --- a/scipost_django/colleges/urls.py +++ b/scipost_django/colleges/urls.py @@ -200,7 +200,7 @@ urlpatterns = [ name="_hx_nominations_no_round_started", ), path( - "<int:nomination_id>", + "<int:nomination_id>/", include( [ path( @@ -213,6 +213,11 @@ urlpatterns = [ views._hx_nomination_round_start, name="_hx_nomination_round_start", ), + path( + "_hx_nomination_voting_rounds_tab/<int:round_id>", + views._hx_nomination_voting_rounds_tab, + name="_hx_nomination_voting_rounds_tab", + ), ] ), ), @@ -227,6 +232,11 @@ urlpatterns = [ views._hx_voting_round_li_contents, name="_hx_voting_round_li_contents", ), + path( + "results", + views._hx_voting_round_results, + name="_hx_voting_round_results", + ), # Manage voters of a nomination round path( "voter/<int:voter_id>/", diff --git a/scipost_django/colleges/views.py b/scipost_django/colleges/views.py index 3f6aabf10a8934f0b5bca71c4077e62230de46a6..e18745b55f85a0892ce09a25f67a0ceae3e39326 100644 --- a/scipost_django/colleges/views.py +++ b/scipost_django/colleges/views.py @@ -889,6 +889,35 @@ def _hx_nominations_list(request): return render(request, "colleges/_hx_nominations_list.html", context) +def _hx_voting_round_results(request, round_id): + """For (re)loading the details if modified.""" + round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id) + context = { + "round": round, + } + return render(request, "colleges/_hx_voting_round_results.html", context) + + +@login_required +@user_passes_test(is_edadmin_or_advisory_or_active_regular_or_senior_fellow) +def _hx_nomination_voting_rounds_tab(request, nomination_id, round_id): + """Render the selected voting round contents and display the others as tabs.""" + nomination = get_object_or_404(FellowshipNomination, pk=nomination_id) + voting_rounds = nomination.voting_rounds.all() + + inaccessible_round_ids = [ + round.id for round in voting_rounds if not round.can_view(request.user) + ] + + context = { + "nomination_id": nomination_id, + "voting_rounds": voting_rounds, + "selected_round": voting_rounds.get(id=round_id), + "inaccessible_round_ids": inaccessible_round_ids, + } + return render(request, "colleges/_hx_nomination_voting_rounds_tab.html", context) + + def _hx_voting_round_li_contents(request, round_id): """For (re)loading the details if modified.""" round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id)