From a1a705865113e984b9caeff16236397007cd3c8b Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Thu, 1 Aug 2024 17:07:22 +0200
Subject: [PATCH] generalize editorial communications tool

add links for author - edadmin communication & viceversa

fixes #299
---
 .../submissions/managers/communication.py     |  8 ++--
 .../submissions/_communication_thread.html    | 38 +++-------------
 .../_submission_author_information.html       |  1 +
 .../templates/submissions/communication.html  |  8 ++--
 .../submissions/pool/editorial_page.html      |  9 ++--
 scipost_django/submissions/utils.py           |  5 +++
 scipost_django/submissions/views/__init__.py  | 43 +++++++++++--------
 7 files changed, 52 insertions(+), 60 deletions(-)

diff --git a/scipost_django/submissions/managers/communication.py b/scipost_django/submissions/managers/communication.py
index dbb7fe1b6..e1cd8ecb5 100644
--- a/scipost_django/submissions/managers/communication.py
+++ b/scipost_django/submissions/managers/communication.py
@@ -7,9 +7,9 @@ from django.db import models
 
 class EditorialCommunicationQuerySet(models.QuerySet):
     def for_referees(self):
-        """Only return communication between Referees and Editors."""
-        return self.filter(comtype__in=["EtoR", "RtoE"])
+        """Only return communication related to Referees."""
+        return self.filter(comtype__contains="R")
 
     def for_authors(self):
-        """Only return communication between Authors and Editors."""
-        return self.filter(comtype__in=["EtoA", "AtoE"])
+        """Only return communication related to Authors."""
+        return self.filter(comtype__contains="A")
diff --git a/scipost_django/submissions/templates/submissions/_communication_thread.html b/scipost_django/submissions/templates/submissions/_communication_thread.html
index d9b024d9b..5c1a6e949 100644
--- a/scipost_django/submissions/templates/submissions/_communication_thread.html
+++ b/scipost_django/submissions/templates/submissions/_communication_thread.html
@@ -1,45 +1,19 @@
 <ul class="mt-2 communications {{ css_class }}">
+
   {% for comm in communication %}
-    <li class="date"><span>{{ comm.timestamp|date:'d F Y' }}</span></li>
+    <li class="date">
+      <span>{{ comm.timestamp|date:'d F Y' }}</span>
+    </li>
     <li class="comm comm-{{ comm.comtype }}">
       <span class="datetime">{{ comm.timestamp|date:'d F Y G:i' }}</span>
       <span class="time">{{ comm.timestamp|date:'G:i' }}</span>
       <div class="content">
-        <span class="header">
-          {% if comm.comtype == 'RtoE' %}
-            From {{ comm.referee.user.first_name }} {{ comm.referee.user.last_name }} to {{ reader_is_editor|yesno:'you,Editor-in-charge' }}
-          {% elif comm.comtype == 'EtoR' %}
-            From {{ reader_is_editor|yesno:'you,Editor-in-charge' }} to
-            {% if comm.referee %}
-              {{ comm.referee.user.first_name }} {{ comm.referee.user.last_name }}
-            {% else %}
-              referee (?)
-            {% endif %}
-          {% elif comm.comtype == 'AtoE' %}
-            From
-            {% if comm.referee %}
-              {{ comm.referee.user.first_name }} {{ comm.referee.user.last_name }}
-            {% else %}
-              author (?)
-            {% endif %}
-            to {{ reader_is_editor|yesno:'you,Editor-in-charge' }}
-          {% elif comm.comtype == 'EtoA' %}
-            From {{ reader_is_editor|yesno:'you,Editor-in-charge' }} to
-            {% if comm.referee %}
-              {{ comm.referee.user.first_name }} {{ comm.referee.user.last_name }}
-            {% else %}
-              author (?)
-            {% endif %}
-          {% elif comm.comtype == 'StoE' %}
-            From Editorial Administration to {{ reader_is_editor|yesno:'you,Editor-in-charge' }}
-          {% elif comm.comtype == 'EtoS' %}
-            From {{ reader_is_editor|yesno:'you,Editor-in-charge' }} to Editorial Administration
-          {% endif %}
-        </span>
+        <span class="header">From {{ comm.author_name }} to {{ comm.recipient_name }}</span>
         <p class="comm-text">{{ comm.text|linebreaksbr }}</p>
       </div>
     </li>
   {% empty %}
     <li>There have been no communications.</li>
   {% endfor %}
+
 </ul>
diff --git a/scipost_django/submissions/templates/submissions/_submission_author_information.html b/scipost_django/submissions/templates/submissions/_submission_author_information.html
index a926de48d..58fbbf75e 100644
--- a/scipost_django/submissions/templates/submissions/_submission_author_information.html
+++ b/scipost_django/submissions/templates/submissions/_submission_author_information.html
@@ -96,6 +96,7 @@
       {% if submission.editor_in_charge %}
         <a href="{% url 'submissions:communication' submission.preprint.identifier_w_vn_nr 'AtoE' %}">Write to the Editor-in-charge</a>
       {% endif %}
+      <a href="{% url 'submissions:communication' submission.preprint.identifier_w_vn_nr 'AtoS' %}">Write to the SciPost Editorial Administration</a>
       {% include 'submissions/_communication_thread.html' with communication=submission.editorial_communications.for_authors css_class='wide' %}
     </div>
   </div>
diff --git a/scipost_django/submissions/templates/submissions/communication.html b/scipost_django/submissions/templates/submissions/communication.html
index 6c653bce6..16bc4981d 100644
--- a/scipost_django/submissions/templates/submissions/communication.html
+++ b/scipost_django/submissions/templates/submissions/communication.html
@@ -26,13 +26,13 @@
   <div class="card bg-light mb-3">
     <div class="card-body">
       <h1 class="pb-0">Send a Communication</h1>
-      {% if comtype == 'EtoA' %}
+      {% if comtype|last == 'A' %}
         <h3 class="mb-0">to the submitting Author of Submission</h3>
-      {% elif comtype == 'AtoE' or comtype == 'RtoE' or comtype == 'StoE' %}
+      {% elif comtype|last == 'E' %}
         <h3 class="mb-0">to the Editor-in-charge of Submission</h3>
-      {% elif comtype == 'EtoR' %}
+      {% elif comtype|last == 'R' %}
         <h3 class="mb-0">to Referee of Submission</h3>
-      {% elif comtype == 'EtoS' %}
+      {% elif comtype|last == 'S' %}
         <h3 class="mb-0">to SciPost Editorial Administrators</h3>
       {% endif %}
     </div>
diff --git a/scipost_django/submissions/templates/submissions/pool/editorial_page.html b/scipost_django/submissions/templates/submissions/pool/editorial_page.html
index 248f463f1..543a66458 100644
--- a/scipost_django/submissions/templates/submissions/pool/editorial_page.html
+++ b/scipost_django/submissions/templates/submissions/pool/editorial_page.html
@@ -497,14 +497,17 @@
         <li><a href="{% url 'submissions:communication' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr comtype='EtoS' %}">Draft and send a communication with SciPost Editorial Administration</a></li>
       {% endif %}
       {% if is_ed_admin %}
-        <li><a href="{% url 'submissions:communication' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr comtype='StoE' %}">Draft and send a communication as Editorial Administrator to the Editor-in-charge</a></li>
+        {% if submission.editor_in_charge %}
+          <li><a href="{% url 'submissions:communication' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr comtype='StoE' %}">Draft and send a communication as Editorial Administrator to the Editor-in-charge</a></li>
+        {% endif %}
+        <li><a href="{% url 'submissions:communication' identifier_w_vn_nr=submission.preprint.identifier_w_vn_nr comtype='StoA' %}">Draft and send a communication as Editorial Administrator to the submitting Author</a></li>
       {% endif %}
     </ul>
 
     {% if submission.editor_in_charge == request.user.contributor %}
-      {% include 'submissions/_communication_thread.html' with communication=submission.editorial_communications.all css_class='wide' reader_is_editor=1 %}
+      {% include 'submissions/_communication_thread.html' with communication=submission.editorial_communications.all css_class='wide' %}
     {% else %}
-      {% include 'submissions/_communication_thread.html' with communication=submission.editorial_communications.all css_class='wide' reader_is_editor=0 %}
+      {% include 'submissions/_communication_thread.html' with communication=submission.editorial_communications.all css_class='wide' %}
     {% endif %}
 
     <h2 class="mt-3" id="events">Events</h2>
diff --git a/scipost_django/submissions/utils.py b/scipost_django/submissions/utils.py
index 8cb1e566c..344c9558b 100644
--- a/scipost_django/submissions/utils.py
+++ b/scipost_django/submissions/utils.py
@@ -735,6 +735,11 @@ class SubmissionUtils(BaseMailUtil):
             raise ValueError("No communication attribute found. Please `.load()` it.")
 
         valid_comtypes = [comtype[0] for comtype in ED_COMM_CHOICES]
+
+        # Referee to Author communication is strictly forbidden
+        valid_comtypes.remove("RtoA")
+        valid_comtypes.remove("AtoR")
+
         if communication.comtype not in valid_comtypes:
             raise ValueError(
                 f"Invalid comtype {communication.comtype}. "
diff --git a/scipost_django/submissions/views/__init__.py b/scipost_django/submissions/views/__init__.py
index 91f826228..f8c4626a3 100644
--- a/scipost_django/submissions/views/__init__.py
+++ b/scipost_django/submissions/views/__init__.py
@@ -3,6 +3,7 @@ __license__ = "AGPL v3"
 
 
 import datetime
+import re
 
 from django.core.paginator import Paginator
 from django.template.response import TemplateResponse
@@ -43,6 +44,7 @@ from scipost.permissions import (
 )
 
 from ..constants import (
+    ED_COMM_CHOICES,
     STATUS_VETTED,
     STATUS_DRAFT,
     CYCLE_DIRECT_REC,
@@ -2023,19 +2025,26 @@ def communication(request, identifier_w_vn_nr, comtype, referee_id=None):
     Communication may be between two of: editor-in-charge, author and referee.
     """
     referee = None
-    if comtype in ["EtoA", "EtoR", "EtoS"]:
-        # Editor to {Author, Referee, Editorial Administration}
+    author, recipient = re.match(r"(\w)to(\w)", comtype).groups()
+
+    valid_comtypes = [comtype[0] for comtype in ED_COMM_CHOICES]
+
+    # Referee to Author communication is strictly forbidden
+    valid_comtypes.remove("RtoA")
+    valid_comtypes.remove("AtoR")
+
+    if comtype not in valid_comtypes:
+        raise Http404("Invalid communication type")
+
+    if author == "E":
         submissions_qs = Submission.objects.in_pool_filter_for_eic(
             request.user,
             latest=False,
             historical=True,
         )
-    elif comtype == "AtoE":
-        # Author to Editor
+    elif author == "A":
         submissions_qs = Submission.objects.filter_for_author(request.user)
-        referee = request.user.contributor
-    elif comtype == "RtoE":
-        # Referee to Editor (Contributor account required)
+    elif author == "R":
         if not hasattr(request.user, "contributor"):
             # Raise PermissionDenied to let the user know something is wrong with its account.
             raise PermissionDenied
@@ -2044,8 +2053,7 @@ def communication(request, identifier_w_vn_nr, comtype, referee_id=None):
             referee_invitations__referee__user=request.user
         )
         referee = request.user.contributor
-    elif comtype == "StoE":
-        # Editorial Administration to Editor
+    elif author == "S":
         if not request.user.has_perm("scipost.can_oversee_refereeing"):
             raise PermissionDenied
         submissions_qs = Submission.objects.in_pool(
@@ -2055,7 +2063,7 @@ def communication(request, identifier_w_vn_nr, comtype, referee_id=None):
         referee = request.user.contributor
     else:
         # Invalid commtype in the url!
-        raise Http404
+        raise Http404("Invalid communication type")
 
     # Uniquify and get the showpiece itself or return 404
     submissions_qs = submissions_qs.distinct()
@@ -2063,12 +2071,12 @@ def communication(request, identifier_w_vn_nr, comtype, referee_id=None):
         submissions_qs, preprint__identifier_w_vn_nr=identifier_w_vn_nr
     )
 
-    if referee_id and comtype in ["EtoA", "EtoR", "EtoS"]:
+    if recipient == "R" and referee_id:
         # Get the Contributor to communicate with if not already defined (`Eto?` communication)
         # To Fix: Assuming the Editorial Administrator won't make any `referee_id` mistakes
         referee = get_object_or_404(Contributor.objects.active(), pk=referee_id)
-    elif comtype == "EtoA":
-        referee = submission.submitted_by
+    else:
+        referee = None
 
     form = EditorialCommunicationForm(request.POST or None)
     if form.is_valid():
@@ -2084,22 +2092,23 @@ def communication(request, identifier_w_vn_nr, comtype, referee_id=None):
         except Exception as e:
             messages.error(
                 request,
-                "Communication submitted, but an error occurred while sending the email: " + str(e),
+                "Communication submitted, but an error occurred while sending the email: "
+                + str(e),
             )
             sentry_sdk.capture_exception(e)
             return redirect(submission.get_absolute_url())
 
         messages.success(request, "Communication submitted")
-        if comtype in ["EtoA", "EtoR", "EtoS"]:
+        if author == "E":
             return redirect(
                 reverse(
                     "submissions:editorial_page",
                     kwargs={"identifier_w_vn_nr": identifier_w_vn_nr},
                 )
             )
-        elif comtype == "AtoE":
+        elif author == "A":
             return redirect(submission.get_absolute_url())
-        elif comtype == "StoE":
+        elif author == "S":
             return redirect(reverse("submissions:pool:pool"))
         return redirect(submission.get_absolute_url())
 
-- 
GitLab