From c6ec10cfec43624c64e38d0d57952abd8c7ece64 Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Tue, 12 Sep 2023 11:53:15 +0200
Subject: [PATCH] add voting round tab to nominations

---
 scipost_django/colleges/models/nomination.py  | 14 +++++++++
 .../colleges/_hx_nomination_li_contents.html  | 18 ++++++++----
 .../_hx_nomination_voting_rounds_tab.html     | 28 ++++++++++++++++++
 scipost_django/colleges/urls.py               | 12 +++++++-
 scipost_django/colleges/views.py              | 29 +++++++++++++++++++
 5 files changed, 94 insertions(+), 7 deletions(-)
 create mode 100644 scipost_django/colleges/templates/colleges/_hx_nomination_voting_rounds_tab.html

diff --git a/scipost_django/colleges/models/nomination.py b/scipost_django/colleges/models/nomination.py
index 4c0a5faf0..72e546b3b 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 9cae025f1..4c0684f32 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 000000000..5f9239748
--- /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 ba02334c7..573d0916f 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 3f6aabf10..e18745b55 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)
-- 
GitLab