diff --git a/scipost_django/submissions/constants.py b/scipost_django/submissions/constants.py index a4519b4a690a00c8630503c0c01ee9c8f7529afb..8c2b6ee5af1b05882daba84d29fb8fe6442ea629 100644 --- a/scipost_django/submissions/constants.py +++ b/scipost_django/submissions/constants.py @@ -1,14 +1,19 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" +import itertools -ED_COMM_CHOICES = ( - ("EtoA", "Editor-in-charge to Author"), - ("EtoR", "Editor-in-charge to Referee"), - ("EtoS", "Editor-in-charge to SciPost Editorial Administration"), - ("AtoE", "Author to Editor-in-charge"), - ("RtoE", "Referee to Editor-in-charge"), - ("StoE", "SciPost Editorial Administration to Editor-in-charge"), + +ED_COMM_PARTIES = ( + ("E", "Editor-in-charge"), + ("A", "Author"), + ("R", "Referee"), + ("S", "SciPost Editorial Administration"), +) +ED_COMM_CHOICES = tuple( + (f"{X}to{Y}", f"{x} to {y}") + for (X, x), (Y, y) in itertools.product(ED_COMM_PARTIES, repeat=2) + if X != Y ) REFEREE_QUALIFICATION = ( diff --git a/scipost_django/submissions/models/communication.py b/scipost_django/submissions/models/communication.py index c7742e92eac3553271c5c802ae92a1f8c3c4142b..657fe8bd4f0581f91a7e0b5d5b8ab735a97d3209 100644 --- a/scipost_django/submissions/models/communication.py +++ b/scipost_django/submissions/models/communication.py @@ -6,6 +6,8 @@ from django.db import models from django.urls import reverse from django.utils import timezone +from common.utils.models import get_current_domain + from ..behaviors import SubmissionRelatedObjectMixin from ..constants import ED_COMM_CHOICES from ..managers import EditorialCommunicationQuerySet @@ -51,3 +53,59 @@ class EditorialCommunication(SubmissionRelatedObjectMixin, models.Model): def get_absolute_url(self): """Return the url of the related Submission detail page.""" return self.submission.get_absolute_url() + + def _resolve_contributor_from_letter(self, letter: str): + recipients: dict[str, "Contributor | None"] = { + "E": self.submission.editor_in_charge, + "A": self.submission.submitted_by, + "R": self.referee, + } + + return recipients.get(letter) + + def _resolve_contributor_name(self, letter: str): + if letter == "S": + return "SciPost Editorial Administration" + elif contributor := self._resolve_contributor_from_letter(letter): + return f"{contributor.profile_title} {contributor.user.last_name}" + return "Unknown" + + def _resolve_contributor_email(self, letter: str): + if letter == "S": + domain = get_current_domain() + return f"editorial@{domain}" + elif contributor := self._resolve_contributor_from_letter(letter): + return contributor.user.email + return "" + + @property + def author_letter(self): + return self.comtype[0] + + @property + def recipient_letter(self): + return self.comtype[-1] + + @property + def author(self): + return self._resolve_contributor_from_letter(self.author_letter) + + @property + def recipient(self): + return self._resolve_contributor_from_letter(self.recipient_letter) + + @property + def author_name(self): + return self._resolve_contributor_name(self.author_letter) + + @property + def recipient_name(self): + return self._resolve_contributor_name(self.recipient_letter) + + @property + def author_email(self): + return self._resolve_contributor_email(self.author_letter) + + @property + def recipient_email(self): + return self._resolve_contributor_email(self.recipient_letter) diff --git a/scipost_django/submissions/utils.py b/scipost_django/submissions/utils.py index 015a2564e9dd0544c0edd57915c240d85fbb6413..8cb1e566c84812c6188aa627c0fffeccc6a37f85 100644 --- a/scipost_django/submissions/utils.py +++ b/scipost_django/submissions/utils.py @@ -15,6 +15,8 @@ from django.template import Context, Template from common.utils.urls import absolute_reverse from .constants import ( + ED_COMM_CHOICES, + ED_COMM_PARTIES, STATUS_VETTED, STATUS_UNCLEAR, STATUS_INCORRECT, @@ -725,15 +727,6 @@ class SubmissionUtils(BaseMailUtil): """ recipient_email = [] bcc_emails = [] - further_action_page = None - - PARTIES = ["E", "A", "R", "S"] - # Allow only comtype to and from E(ditor) - valid_comtypes = [ - f"{x}to{y}" - for x, y in itertools.product(PARTIES, repeat=2) - if "E" in [x, y] and x != y - ] communication: "EditorialCommunication | None" = getattr( cls, "communication", None @@ -741,44 +734,23 @@ class SubmissionUtils(BaseMailUtil): if communication is None: raise ValueError("No communication attribute found. Please `.load()` it.") + valid_comtypes = [comtype[0] for comtype in ED_COMM_CHOICES] if communication.comtype not in valid_comtypes: raise ValueError( f"Invalid comtype {communication.comtype}. " f"Valid comtypes are {valid_comtypes}." ) - recipients: dict[str, "Contributor | None"] = { - "E": communication.submission.editor_in_charge, - "A": communication.submission.submitted_by, - "R": communication.referee, - } - - author, recipient = re.match(r"(\w)to(\w)", communication.comtype).groups() - - # Use standard greeting for all communications except to Editorial Administrator - if recipient != "S": - recipient_contributor = recipients.get(recipient, None) - if recipient_contributor is None: - raise ValueError( - f"Recipient not found for comtype {communication.comtype}. Must be one of {recipients.keys()}" - ) - - recipient_email.append(recipient_contributor.user.email) - recipient_greeting = f"Dear {recipient_contributor.profile_title} {recipient_contributor.user.last_name}" - - # BCC all non-edadmin communications to the Editorial Administrator + # BCC all non-edadmin communications to the Editorial Administrator + if communication.recipient_letter != "S": bcc_emails.append(f"submissions@{domain}") - else: - # Communication to Editorial Administrator doesn't have a specific recipient contributor - recipient_email.append(f"submissions@{domain}") - recipient_greeting = "Dear Editorial Administrators" # BCC all editor-authored communications to the Editor-in-charge - if author == "E": - bcc_emails.append(communication.submission.editor_in_charge.user.email) + if communication.author_letter == "E": + bcc_emails.append(communication.author_email) # Further action page for Editor and Editorial Administrator - if recipient in ["E", "S"]: # EtoS and _toE + if communication.recipient_letter in ["E", "S"]: # _toS and _toE editorial_page_url = absolute_reverse( "submissions:editorial_page", args=[communication.submission.preprint.identifier_w_vn_nr], @@ -787,24 +759,32 @@ class SubmissionUtils(BaseMailUtil): f"You can take follow-up actions from {editorial_page_url}." ) # Further action page for Author and Referee - elif recipient in ["R", "A"]: # EtoA and EtoR + elif communication.recipient_letter in ["R", "A"]: # _toA and _toR preprint_identifier = communication.submission.preprint.identifier_w_vn_nr - communication_url = absolute_reverse( + reverse_communication_url = absolute_reverse( "submissions:communication", - args=[preprint_identifier, recipient + "toE"], + args=[ + preprint_identifier, + communication.recipient_letter + "to" + communication.author_letter, + # Reverse the communication direction, e.g. EtoA -> AtoE + ], ) submission_page_url = absolute_reverse( "submissions:submission", args=[preprint_identifier], ) + + # Create a dictionary mapping author letters to author kinds + author_kinds = dict(zip(*zip(*ED_COMM_PARTIES))) + author_kind = author_kinds.get(communication.author_letter) further_action = ( - f"To reply to the Editor-in-charge, please visit {communication_url}. " - "You can find all previous communications between you and the Editor-in-charge, as well as other communications tools, " + f"To reply to the {author_kind}, please visit {reverse_communication_url}. " + f"You can find all previous communications between you and the {author_kind}, as well as other communications tools, " f"on the submission page at {submission_page_url} (login needed)." ) email_text = ( - f"{recipient_greeting},\n\n" + f"Dear {communication.recipient_name},\n\n" f"Please find here a communication ({communication.get_comtype_display()}) concerning Submission:\n\n" f"{communication.submission.title}\nby {communication.submission.author_list}.\n" f"(https://{domain}/{communication.submission.get_absolute_url()})\n\n" @@ -819,10 +799,10 @@ class SubmissionUtils(BaseMailUtil): ) emailmessage = EmailMessage( - "SciPost: communication (" + communication.get_comtype_display() + ")", + f"SciPost: communication ({communication.get_comtype_display()})", email_text, f"SciPost Editorial Admin <submissions@{domain}>", - recipient_email, + [communication.recipient_email], bcc_emails, reply_to=[f"submissions@{domain}"], )