Coverage for src/mesh/tests/roles/test_editor.py: 100%

281 statements  

« prev     ^ index     » next       coverage.py v7.9.0, created at 2026-02-04 09:42 +0000

1from datetime import datetime, timedelta 

2from unittest.mock import patch 

3 

4from mesh.model.roles.editor import Editor, EditorRights, get_section_editors 

5 

6from ...model.submission_status import SubmissionStatus 

7from ...models.editorial_models import EditorSectionRight, EditorSubmissionRight 

8from ...models.factories import ( 

9 JournalSectionFactory, 

10 ReviewFactory, 

11 SubmissionAuthorFactory, 

12 SubmissionFactory, 

13 SubmissionVersionFactory, 

14 UserFactory, 

15) 

16from ...models.journal_models import JournalSection 

17from ...models.submission_models import Submission, SubmissionMainFile, SubmissionState 

18from ...models.user_models import User 

19from ..base_test_case import BaseTestCase 

20 

21 

22class EditorTestCase(BaseTestCase): 

23 used_models = [ 

24 EditorSubmissionRight, 

25 EditorSectionRight, 

26 Submission, 

27 JournalSection, 

28 ] 

29 class_used_models = [User] 

30 

31 @classmethod 

32 def setUpClass(cls) -> None: 

33 super().setUpClass() 

34 cls.user_author = UserFactory.create() 

35 cls.user_editor = UserFactory.create() 

36 

37 def test_submissions_from_direct_right(self): 

38 submission_1 = SubmissionFactory.create() 

39 submission_2 = SubmissionFactory.create() # noqa 

40 

41 role = Editor(self.user_editor) 

42 self.assertFalse(role.active) 

43 

44 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission_1) 

45 role = Editor(self.user_editor) 

46 self.assertTrue(role.active) 

47 rights = role.rights 

48 

49 self.assertEqual(len(rights.submissions), 1) 

50 self.assertEqual(rights.submissions[0], submission_1) 

51 

52 submission_1.created_by = self.user_editor 

53 submission_1.save() 

54 role = Editor(self.user_editor) 

55 self.assertTrue(role.active) 

56 rights = role.rights 

57 self.assertEqual(len(rights.submissions), 1) 

58 self.assertEqual(rights.submissions[0], submission_1) 

59 

60 def test_submissions_from_journal_sections(self): 

61 journal_section_1 = JournalSectionFactory.create() 

62 journal_section_2 = JournalSectionFactory.create(parent=journal_section_1) 

63 journal_section_3 = JournalSectionFactory.create() 

64 

65 submission_1 = SubmissionFactory.create( 

66 journal_section=journal_section_1, state=SubmissionState.SUBMITTED.value 

67 ) 

68 submission_2 = SubmissionFactory.create( 

69 journal_section=journal_section_2, state=SubmissionState.SUBMITTED.value 

70 ) 

71 submission_3 = SubmissionFactory.create( # noqa 

72 journal_section=journal_section_3, state=SubmissionState.SUBMITTED.value 

73 ) 

74 

75 EditorSectionRight.objects.create(user=self.user_editor, journal_section=journal_section_1) 

76 role = Editor(self.user_editor) 

77 self.assertTrue(role.active) 

78 rights = role.rights 

79 

80 self.assertEqual(len(rights.submissions), 2) 

81 self.assertIn(submission_1, rights.submissions) 

82 self.assertIn(submission_2, rights.submissions) 

83 

84 # Self-made submission are not available to the editor. 

85 submission_1.created_by = self.user_editor 

86 submission_1.save() 

87 role = Editor(self.user_editor) 

88 self.assertTrue(role.active) 

89 rights = role.rights 

90 self.assertEqual(len(rights.submissions), 1) 

91 self.assertIn(submission_2, rights.submissions) 

92 

93 # OPENED submissions are not availabe to anyone but to its author. 

94 submission_2.state = SubmissionState.OPENED.value 

95 submission_2.save() 

96 role = Editor(self.user_editor) 

97 # Editor role is actve if it has rights over any journal_section or any submissions 

98 self.assertTrue(role.active) 

99 rights = role.rights 

100 self.assertEqual(len(rights.submissions), 0) 

101 

102 def test_all_submissions(self): 

103 journal_section_1 = JournalSectionFactory.create() 

104 journal_section_2 = JournalSectionFactory.create(parent=journal_section_1) 

105 journal_section_3 = JournalSectionFactory.create() 

106 

107 submission_1 = SubmissionFactory.create( 

108 journal_section=journal_section_1, state=SubmissionState.SUBMITTED.value 

109 ) 

110 submission_2 = SubmissionFactory.create( 

111 journal_section=journal_section_2, state=SubmissionState.SUBMITTED.value 

112 ) 

113 submission_3 = SubmissionFactory.create( # noqa 

114 journal_section=journal_section_3, state=SubmissionState.SUBMITTED.value 

115 ) 

116 submission_4 = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

117 submission_5 = SubmissionFactory.create( # noqa 

118 journal_section=journal_section_1, 

119 state=SubmissionState.SUBMITTED.value, 

120 created_by=self.user_editor, 

121 ) 

122 

123 EditorSectionRight.objects.create(user=self.user_editor, journal_section=journal_section_1) 

124 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission_4) 

125 

126 rights = EditorRights(self.user_editor) 

127 self.assertEqual(len(rights.submissions), 3) 

128 self.assertIn(submission_1, rights.submissions) 

129 self.assertIn(submission_2, rights.submissions) 

130 self.assertIn(submission_4, rights.submissions) 

131 

132 # All the following tests are rights exclusive to the Editor+ roles. 

133 # We just ensure they resolve to True when the editor has rights over the submission. 

134 def test_can_invite_reviewer(self): 

135 submission = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

136 version = SubmissionVersionFactory.create(submission=submission, submitted=True) 

137 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

138 

139 rights = EditorRights(self.user_editor) 

140 self.assertFalse(rights.can_invite_reviewer(version)) 

141 

142 version.review_open = True 

143 self.assertTrue(rights.can_invite_reviewer(version)) 

144 

145 def test_can_access_version(self): 

146 submission = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

147 version = SubmissionVersionFactory.create(submission=submission) 

148 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

149 

150 rights = EditorRights(self.user_editor) 

151 self.assertFalse(rights.can_access_version(version)) 

152 

153 version.submitted = True 

154 self.assertTrue(rights.can_access_version(version)) 

155 

156 def test_managed_users(self): 

157 User.objects.all().delete() 

158 user_editor = UserFactory.create() 

159 user_author_1 = UserFactory.create() 

160 user_author_2 = UserFactory.create() 

161 user_reviewer = UserFactory.create() 

162 user_editor_2 = UserFactory.create() 

163 user_editor_3 = UserFactory.create() 

164 user_journal_manager = UserFactory.create(journal_manager=True) 

165 user_admin = UserFactory.create(is_superuser=True) # noqa 

166 

167 submission_1 = SubmissionFactory.create( 

168 created_by=user_author_1, state=SubmissionState.SUBMITTED.value 

169 ) 

170 version_1 = SubmissionVersionFactory(submission=submission_1, submitted=True) 

171 submission_2 = SubmissionFactory.create( 

172 created_by=user_author_2, state=SubmissionState.SUBMITTED.value 

173 ) 

174 review = ReviewFactory.create(reviewer=user_reviewer, version=version_1) # noqa 

175 

176 EditorSubmissionRight.objects.create(user=user_editor, submission=submission_1) 

177 EditorSubmissionRight.objects.create(user=user_editor_2, submission=submission_2) 

178 

179 journal_section = JournalSectionFactory.create(created_by=user_journal_manager) 

180 EditorSectionRight.objects.create(journal_section=journal_section, user=user_editor_3) 

181 

182 rights = EditorRights(user_editor) 

183 self.assertEqual(len(rights.managed_users), 3) 

184 self.assertIn(user_author_1, rights.managed_users) 

185 self.assertIn(user_author_2, rights.managed_users) 

186 self.assertIn(user_reviewer, rights.managed_users) 

187 

188 def test_can_impersonate(self): 

189 rights = EditorRights(self.user_editor) 

190 self.assertTrue(rights.can_impersonate()) 

191 

192 def test_can_access_submission_log(self): 

193 submission = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

194 rights = EditorRights(self.user_editor) 

195 self.assertFalse(rights.can_access_submission_log(submission)) 

196 

197 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

198 rights = EditorRights(self.user_editor) 

199 self.assertTrue(rights.can_access_submission_log(submission)) 

200 

201 def test_can_create_editorial_decision(self): 

202 submission = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

203 rights = EditorRights(self.user_editor) 

204 self.assertFalse(rights.can_create_editorial_decision(submission)) 

205 

206 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

207 rights = EditorRights(self.user_editor) 

208 self.assertTrue(rights.can_create_editorial_decision(submission)) 

209 

210 submission.state = SubmissionState.ON_REVIEW.value 

211 submission.save() 

212 rights = EditorRights(self.user_editor) 

213 self.assertTrue(rights.can_create_editorial_decision(submission)) 

214 

215 submission.state = SubmissionState.REVISION_REQUESTED.value 

216 submission.save() 

217 rights = EditorRights(self.user_editor) 

218 self.assertTrue(rights.can_create_editorial_decision(submission)) 

219 

220 submission.state = SubmissionState.REVISION_SUBMITTED.value 

221 submission.save() 

222 rights = EditorRights(self.user_editor) 

223 self.assertTrue(rights.can_create_editorial_decision(submission)) 

224 

225 submission.state = SubmissionState.ACCEPTED.value 

226 submission.save() 

227 rights = EditorRights(self.user_editor) 

228 self.assertTrue(rights.can_create_editorial_decision(submission)) 

229 

230 submission.state = SubmissionState.REJECTED.value 

231 submission.save() 

232 rights = EditorRights(self.user_editor) 

233 self.assertTrue(rights.can_create_editorial_decision(submission)) 

234 

235 def test_can_start_review_process(self): 

236 submission = SubmissionFactory.create() 

237 

238 rights = EditorRights(self.user_editor) 

239 with patch.object(Submission, "is_reviewable", True): 

240 self.assertFalse(rights.can_start_review_process(submission)) 

241 

242 with patch.object(Submission, "is_reviewable", False): 

243 self.assertFalse(rights.can_start_review_process(submission)) 

244 

245 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

246 rights = EditorRights(self.user_editor) 

247 with patch.object(Submission, "is_reviewable", True): 

248 self.assertTrue(rights.can_start_review_process(submission)) 

249 

250 with patch.object(Submission, "is_reviewable", False): 

251 self.assertFalse(rights.can_start_review_process(submission)) 

252 

253 def test_can_assign_editor(self): 

254 submission = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

255 rights = EditorRights(self.user_editor) 

256 self.assertFalse(rights.can_assign_editor(submission)) 

257 

258 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

259 rights = EditorRights(self.user_editor) 

260 self.assertTrue(rights.can_assign_editor(submission)) 

261 

262 def test_can_filter_submissions(self): 

263 rights = EditorRights(self.user_editor) 

264 self.assertTrue(rights.can_filter_submissions()) 

265 

266 def test_can_access_journal_sections(self): 

267 rights = EditorRights(self.user_editor) 

268 self.assertTrue(rights.can_access_journal_sections()) 

269 

270 def test_can_edit_review_file_right(self): 

271 submission = SubmissionFactory.create(state=SubmissionState.SUBMITTED.value) 

272 version = SubmissionVersionFactory.create(submission=submission, submitted=True) 

273 review = ReviewFactory.create(version=version) 

274 rights = EditorRights(self.user_editor) 

275 self.assertFalse(rights.can_edit_review_file_right(review)) 

276 

277 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

278 rights = EditorRights(self.user_editor) 

279 self.assertTrue(rights.can_edit_review_file_right(review)) 

280 

281 def test_editor_submission_status(self): 

282 """ 

283 Test the editor status wrt. the whole submission workflow 

284 """ 

285 submission = SubmissionFactory.create(author_agreement=True) 

286 version = SubmissionVersionFactory.create( 

287 submission=submission, submitted=False, review_open=False 

288 ) 

289 SubmissionAuthorFactory.create(submission=submission) 

290 SubmissionMainFile.objects.create(file=self.dummy_file, attached_to=version) 

291 

292 # No rights over the submission 

293 submission = Submission.objects.get(pk=submission.pk) 

294 rights = EditorRights(self.user_editor) 

295 status = rights.get_submission_status(submission) 

296 self.assertEqual(status.status, SubmissionStatus.ERROR) 

297 

298 # OPENED submission 

299 EditorSubmissionRight.objects.create(user=self.user_editor, submission=submission) 

300 rights = EditorRights(self.user_editor) 

301 status = rights.get_submission_status(submission) 

302 self.assertEqual(status.status, SubmissionStatus.ERROR) 

303 

304 # SUBMITTED submission 

305 request = self.dummy_request() 

306 request.user = submission.created_by 

307 submission.submit(submission.created_by) 

308 submission = Submission.objects.get(pk=submission.pk) 

309 status = rights.get_submission_status(submission) 

310 self.assertEqual(status.status, SubmissionStatus.TODO) 

311 

312 # UNDER REVIEW submission with no reviews 

313 request.user = self.user_editor 

314 # submission.start_review_process(self.user_editor) 

315 submission = Submission.objects.get(pk=submission.pk) 

316 status = rights.get_submission_status(submission) 

317 self.assertEqual(status.status, SubmissionStatus.TODO) 

318 

319 # UNDER REVIEW with pending answer 

320 review = ReviewFactory.create(version=version) 

321 submission = Submission.objects.get(pk=submission.pk) 

322 status = rights.get_submission_status(submission) 

323 self.assertEqual(status.status, SubmissionStatus.WAITING) 

324 

325 # UNDER REVIEW with 1 pending review & 1 overdue review 

326 yesterday = (datetime.utcnow() - timedelta(days=1)).date() 

327 review_overdue = ReviewFactory.create(version=version, date_response_due=yesterday) 

328 submission = Submission.objects.get(pk=submission.pk) 

329 status = rights.get_submission_status(submission) 

330 self.assertEqual(status.status, SubmissionStatus.TODO) 

331 

332 # UNDER REVIEW with 1 pending review, 1 pending answer 

333 review_overdue.date_response_due = (datetime.utcnow() + timedelta(days=1)).date() 

334 review_overdue.accepted = True 

335 review_overdue.save() 

336 submission = Submission.objects.get(pk=submission.pk) 

337 status = rights.get_submission_status(submission) 

338 self.assertEqual(status.status, SubmissionStatus.WAITING) 

339 

340 # UNDER REVIEW with all reviews submitted or declined 

341 review.accepted = False 

342 review.save() 

343 review_overdue.submitted = True 

344 review_overdue.save() 

345 submission = Submission.objects.get(pk=submission.pk) 

346 status = rights.get_submission_status(submission) 

347 self.assertEqual(status.status, SubmissionStatus.TODO) 

348 

349 # REVISIIONS REQUESTED submission 

350 submission.state = SubmissionState.REVISION_REQUESTED.value 

351 submission.save() 

352 submission = Submission.objects.get(pk=submission.pk) 

353 status = rights.get_submission_status(submission) 

354 self.assertEqual(status.status, SubmissionStatus.WAITING) 

355 version.review_open = False 

356 version.save() 

357 

358 # REVISIONS SUBMITTED submission 

359 version_2 = SubmissionVersionFactory.create( 

360 submission=submission, submitted=False, review_open=False 

361 ) 

362 SubmissionMainFile.objects.create(file=self.dummy_file, attached_to=version_2) 

363 submission = Submission.objects.get(pk=submission.pk) 

364 request.user = self.user_author 

365 submission.submit(self.user_author) 

366 submission = Submission.objects.get(pk=submission.pk) 

367 status = rights.get_submission_status(submission) 

368 self.assertEqual(status.status, SubmissionStatus.TODO) 

369 

370 # ACCEPTED submission 

371 submission.state = SubmissionState.ACCEPTED.value 

372 submission.save() 

373 submission = Submission.objects.get(pk=submission.pk) 

374 status = rights.get_submission_status(submission) 

375 self.assertEqual(status.status, SubmissionStatus.DONE) 

376 

377 # REJECTED submission 

378 submission.state = SubmissionState.REJECTED.value 

379 submission.save() 

380 submission = Submission.objects.get(pk=submission.pk) 

381 status = rights.get_submission_status(submission) 

382 self.assertEqual(status.status, SubmissionStatus.DONE) 

383 

384 

385class EditorUtilsTestCase(BaseTestCase): 

386 def test_section_editors(self): 

387 journal_section_1 = JournalSectionFactory.create() 

388 journal_section_2 = JournalSectionFactory.create(parent=journal_section_1) 

389 journal_section_3 = JournalSectionFactory.create(parent=journal_section_1) 

390 journal_section_4 = JournalSectionFactory.create(parent=journal_section_2) 

391 

392 submission = SubmissionFactory.create(journal_section=journal_section_4) 

393 

394 user_editor_1 = UserFactory.create() 

395 user_editor_2 = UserFactory.create() 

396 user_editor_3 = UserFactory.create() 

397 user_editor_4 = UserFactory.create() 

398 

399 EditorSectionRight.objects.create(journal_section=journal_section_1, user=user_editor_1) 

400 EditorSectionRight.objects.create(journal_section=journal_section_2, user=user_editor_2) 

401 EditorSectionRight.objects.create(journal_section=journal_section_3, user=user_editor_3) 

402 EditorSectionRight.objects.create(journal_section=journal_section_4, user=user_editor_4) 

403 

404 EditorSubmissionRight.objects.create(submission=submission, user=user_editor_3) 

405 

406 section_editors = get_section_editors(submission) 

407 self.assertEqual(len(section_editors), 3) 

408 self.assertIn(user_editor_1, section_editors) 

409 self.assertIn(user_editor_2, section_editors) 

410 self.assertIn(user_editor_4, section_editors)