Coverage for src / mesh / models / roles / author.py: 96%
70 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-05-04 12:41 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-05-04 12:41 +0000
1from typing import ClassVar
3# from django.urls import reverse_lazy
4from django.db.models import Value
5from django.utils.translation import gettext as _
6from opentelemetry import trace
8from mesh.app_settings import BlindMode, app_settings
9from mesh.models.orm.review_models import Review
10from mesh.models.orm.submission_models import Submission, SubmissionState, SubmissionVersion
12# from ..views.components.button import Button
13from mesh.models.roles.base_role import Role
14from mesh.models.submission_status import SubmissionStatus, SubmissionStatusData
16tracer = trace.get_tracer(__name__)
19class Author(Role):
20 """
21 Author role.
22 This is the base role of mesh app, always active.
23 """
25 _CODE: ClassVar[str] = "author"
26 _NAME: ClassVar[str] = _("Author")
27 _ICON_CLASS: ClassVar[str] = "fa-pen-nib"
28 _SUBMISSION_LIST_TITLE: ClassVar[str] = _("My submissions")
30 @tracer.start_as_current_span("Author.__init__")
31 def __init__(self, user) -> None:
32 super().__init__(user)
33 self.reviews_queryset = Review.objects.filter(
34 version__review_open=False,
35 submitted=True,
36 accepted=True,
37 recommendation__isnull=False,
38 additional_files__author_access=True,
39 )
41 if app_settings.BLIND_MODE != BlindMode.NO_BLIND:
42 self.reviewer_censored_annotate = Value("****, ****")
44 self.versions_queryset = SubmissionVersion.objects.all()
45 self.submissions_queryset = Submission.objects.filter(created_by=self.user)
47 def _get_is_active(self):
48 return True
50 def get_submissions(self):
51 return self._annotate_submission_query(self.submissions_queryset).annotate(
52 user_is_editor=Value(False)
53 )
55 def can_access_submission(self, submission):
56 return submission.created_by == self.user
58 def can_edit_submission(self, submission):
59 result = self.can_access_submission(submission)
60 result = (
61 result
62 and submission.is_draft
63 or submission.state == SubmissionState.REVISION_REQUESTED.value
64 )
65 return result
67 def can_create_submission(self):
68 return True
70 def can_create_version(self, submission):
71 if not self.can_access_submission(submission):
72 return False
73 current_version = submission.versions.first()
74 # The author must have entered at least 1 submission author to proceed
75 # with the submission version.
76 if submission.is_draft and current_version is None:
77 return submission.authors.exists()
78 return (
79 submission.state == SubmissionState.REVISION_REQUESTED.value
80 and current_version is not None
81 and current_version.submitted
82 )
84 def can_access_version(self, version):
85 return self.can_access_submission(version.submission)
87 def can_edit_version(self, version):
88 return not version.submitted and self.can_access_submission(version.submission)
90 def can_access_reviews(self, version):
91 """
92 An author can access reviews when the review process is closed.
93 """
94 return not version.review_open and self.can_access_submission(version.submission)
96 def can_access_review(self, submission, review):
97 """
98 An author can access review with at least one accessible file.
99 """
100 return (
101 self.can_access_reviews(review.version)
102 and review.submitted
103 and review.recommendation is not None
104 and any(self.can_access_review_file(f) for f in review.additional_files.all())
105 )
107 def can_access_review_file(self, file):
108 return file.author_access
110 def get_submission_status(self, submission):
111 """
112 For an author, the submission status is one of the following:
113 - "Submission is still in draft", True - when STATUS_OPENED
114 - "A new version must be submitted", True - when STATUS_REVISIONS_REQUESTED
115 - "Submission accepted", False - when STATUS_ACCEPTED
116 - "Submission declined", False - when STATUS_DECLINED
117 - "Waiting for editorial actions" - when STATUS_SUBMITTED or STATUS_REVISIONS_SUBMITTED
118 - "Under review", False - For other state
119 """
120 # Should not happen ?
121 if not self.can_access_submission(submission):
122 return SubmissionStatusData(
123 submission=submission, status=SubmissionStatus.ERROR, description=""
124 )
126 if submission.state in [
127 SubmissionState.SUBMITTED.value,
128 SubmissionState.REVISION_SUBMITTED.value,
129 ]:
130 return SubmissionStatusData(
131 submission=submission,
132 status=SubmissionStatus.WAITING,
133 description=_("Under review"),
134 )
135 elif submission.state == SubmissionState.OPENED.value:
136 status_data = SubmissionStatusData(
137 submission=submission,
138 status=SubmissionStatus.TODO,
139 description=_("Complete your submission"),
140 )
141 return status_data
143 elif submission.state == SubmissionState.REVISION_REQUESTED.value:
144 status_data = SubmissionStatusData(
145 submission=submission,
146 status=SubmissionStatus.TODO,
147 description=_("Submit a new version"),
148 )
149 # if submission.state == SubmissionState.OPENED.value and self.can_submit_submission(
150 # submission
151 # ):
152 # status_data.shortcut_actions.append(
153 # Button(
154 # id=f"submission-submit-{submission.pk}",
155 # title=_("Resume submission"),
156 # icon_class="fa-list-check",
157 # attrs={
158 # "href": [
159 # reverse_lazy(
160 # "mesh:submission_resume", kwargs={"pk": submission.pk}
161 # )
162 # ],
163 # "class": ["as-button"],
164 # },
165 # )
166 # )
167 # elif (
168 # submission.state == SubmissionState.REVISION_REQUESTED.value
169 # and self.can_create_version(submission)
170 # ):
171 # status_data.shortcut_actions.append(
172 # Button(
173 # id=f"submission-submit-{submission.pk}",
174 # title=_("Submit revisions"),
175 # icon_class="fa-plus",
176 # attrs={
177 # "href": [
178 # reverse_lazy(
179 # "mesh:submission_version_create",
180 # kwargs={"submission_pk": submission.pk},
181 # )
182 # ],
183 # "class": ["as-button"],
184 # },
185 # )
186 # )
187 # elif (
188 # submission.state == SubmissionState.REVISION_REQUESTED.value
189 # and submission.current_version
190 # and not submission.current_version.submitted
191 # ):
192 # status_data.shortcut_actions.append(
193 # Button(
194 # id=f"submission-submit-{submission.pk}",
195 # title=_("Resume revisions"),
196 # icon_class="fa-list-check",
197 # attrs={
198 # "href": [
199 # reverse_lazy(
200 # "mesh:submission_version_update",
201 # kwargs={"pk": submission.current_version.pk},
202 # )
203 # ],
204 # "class": ["as-button"],
205 # },
206 # )
207 # )
208 return status_data
210 elif submission.state == SubmissionState.ON_REVIEW.value:
211 return SubmissionStatusData(
212 submission=submission,
213 status=SubmissionStatus.WAITING,
214 description=_("Submission is under review"),
215 )
216 elif submission.state in [
217 SubmissionState.ACCEPTED.value,
218 SubmissionState.REJECTED.value,
219 ]:
220 return SubmissionStatusData(
221 submission=submission,
222 status=SubmissionStatus.DONE,
223 description=_("Submission") + " " + submission.get_state_display(),
224 )
226 return SubmissionStatusData(
227 submission=submission, status=SubmissionStatus.ERROR, description=""
228 )
230 def can_access_last_activity(self) -> bool:
231 return False