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

298 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-08-11 09:47 +0000

1from datetime import datetime, timedelta 

2from unittest.mock import patch 

3 

4from mesh.models.orm.editorial_models import EditorSectionRight, EditorSubmissionRight 

5from mesh.models.orm.factories import ( 

6 JournalSectionFactory, 

7 ReviewFactory, 

8 SubmissionAuthorFactory, 

9 SubmissionFactory, 

10 SubmissionVersionFactory, 

11 UserFactory, 

12) 

13from mesh.models.orm.journal_models import JournalSection 

14from mesh.models.orm.submission_models import Submission, SubmissionMainFile, SubmissionState 

15from mesh.models.orm.user_models import User 

16from mesh.models.roles.editor import Editor, get_section_editors 

17from mesh.models.submission_status import SubmissionStatus 

18from mesh.tests.base_test_case import BaseTestCase 

19 

20 

21class EditorTestCase(BaseTestCase): 

22 used_models = [ 

23 EditorSubmissionRight, 

24 EditorSectionRight, 

25 Submission, 

26 JournalSection, 

27 ] 

28 class_used_models = [User] 

29 

30 @classmethod 

31 def setUpClass(cls) -> None: 

32 super().setUpClass() 

33 cls.user_author = UserFactory.create() 

34 cls.user_editor = UserFactory.create() 

35 

36 def test_submissions_from_direct_right(self): 

37 submission_1 = SubmissionFactory.create(state=SubmissionState.ON_REVIEW.value) 

38 _submission_2 = SubmissionFactory.create(state=SubmissionState.ON_REVIEW.value) 

39 

40 role = Editor(self.user_editor) 

41 # self.assertFalse(role.active) 

42 

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

44 role = Editor(self.user_editor) 

45 # self.assertTrue(role.active) 

46 

47 submissions = role.get_submissions() 

48 self.assertEqual(len(submissions), 1) 

49 self.assertEqual(submissions[0], submission_1) 

50 

51 # If the editor is also an author, he must have no admin rights over his publications 

52 # TODO: is this good ? 

53 submission_1.created_by = self.user_editor 

54 submission_1.save() 

55 role = Editor(self.user_editor) 

56 

57 submissions = role.get_submissions() 

58 

59 self.assertEqual(len(submissions), 0) 

60 # self.assertEqual(submissions[0], submission_1) 

61 

62 def test_submissions_from_journal_sections(self): 

63 journal_section_1 = JournalSectionFactory.create() 

64 journal_section_2 = JournalSectionFactory.create(parent=journal_section_1) 

65 journal_section_3 = JournalSectionFactory.create() 

66 

67 submission_1 = SubmissionFactory.create( 

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

69 ) 

70 submission_2 = SubmissionFactory.create( 

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

72 ) 

73 submission_3 = SubmissionFactory.create( # noqa 

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

75 ) 

76 

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

78 role = Editor(self.user_editor) 

79 # self.assertTrue(role.active) 

80 

81 submissions = role.get_submissions() 

82 

83 self.assertEqual(len(submissions), 2) 

84 self.assertIn(submission_1, submissions) 

85 self.assertIn(submission_2, submissions) 

86 

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

88 submission_1.created_by = self.user_editor 

89 submission_1.save() 

90 role = Editor(self.user_editor) 

91 # self.assertTrue(role.active) 

92 

93 submissions = role.get_submissions() 

94 self.assertEqual(len(submissions), 1) 

95 self.assertIn(submission_2, submissions) 

96 

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

98 submission_2.state = SubmissionState.OPENED.value 

99 submission_2.save() 

100 role = Editor(self.user_editor) 

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

102 # self.assertTrue(role.active) 

103 

104 submissions = role.get_submissions() 

105 

106 self.assertEqual(submissions.count(), 0) 

107 

108 def test_all_submissions(self): 

109 journal_section_1 = JournalSectionFactory.create() 

110 journal_section_2 = JournalSectionFactory.create(parent=journal_section_1) 

111 journal_section_3 = JournalSectionFactory.create() 

112 

113 submission_1 = SubmissionFactory.create( 

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

115 ) 

116 submission_2 = SubmissionFactory.create( 

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

118 ) 

119 submission_3 = SubmissionFactory.create( # noqa 

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

121 ) 

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

123 submission_5 = SubmissionFactory.create( # noqa 

124 journal_section=journal_section_1, 

125 state=SubmissionState.SUBMITTED.value, 

126 created_by=self.user_editor, 

127 ) 

128 

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

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

131 

132 role = Editor(self.user_editor) 

133 

134 submissions = role.get_submissions() 

135 

136 self.assertEqual(len(submissions), 3) 

137 self.assertIn(submission_1, submissions) 

138 self.assertIn(submission_2, submissions) 

139 self.assertIn(submission_4, submissions) 

140 

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

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

143 def test_can_invite_reviewer(self): 

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

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

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

147 

148 role = Editor(self.user_editor) 

149 

150 submission = role.get_submissions().get(pk=submission.pk) 

151 self.assertIn(version, submission.versions_censored) 

152 version = next(v for v in submission.versions_censored if v == version) 

153 

154 self.assertFalse(role.can_invite_reviewer(version)) 

155 

156 version.review_open = True 

157 version.save() 

158 

159 submission = role.get_submissions().get(pk=submission.pk) 

160 self.assertIn(version, submission.versions_censored) 

161 version = next(v for v in submission.versions_censored if v == version) 

162 

163 self.assertTrue(role.can_invite_reviewer(version)) 

164 

165 def test_can_access_version(self): 

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

167 version = SubmissionVersionFactory.create(submission=submission) 

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

169 role = Editor(self.user_editor) 

170 

171 submission = role.get_submissions().get(pk=submission.pk) 

172 

173 self.assertFalse(role.can_access_version(version)) 

174 self.assertNotIn(version, submission.versions_censored) 

175 version.submitted = True 

176 version.save() 

177 

178 submission = role.get_submissions().get(pk=submission.pk) 

179 self.assertIn(version, submission.versions_censored) 

180 version = next(v for v in submission.versions_censored if v == version) 

181 self.assertTrue(role.can_access_version(version)) 

182 

183 def test_managed_users(self): 

184 User.objects.all().delete() 

185 user_editor = UserFactory.create() 

186 user_author_1 = UserFactory.create() 

187 user_author_2 = UserFactory.create() 

188 user_reviewer = UserFactory.create() 

189 user_editor_2 = UserFactory.create() 

190 user_editor_3 = UserFactory.create() 

191 user_journal_manager = UserFactory.create(journal_manager=True) 

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

193 

194 submission_1 = SubmissionFactory.create( 

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

196 ) 

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

198 submission_2 = SubmissionFactory.create( 

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

200 ) 

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

202 

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

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

205 

206 journal_section = JournalSectionFactory.create(created_by=user_journal_manager) 

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

208 

209 role = Editor(user_editor) 

210 managed_users = role.get_managed_users() 

211 self.assertEqual(len(managed_users), 3) 

212 self.assertIn(user_author_1, managed_users) 

213 self.assertIn(user_author_2, managed_users) 

214 self.assertIn(user_reviewer, managed_users) 

215 

216 def test_can_impersonate(self): 

217 role = Editor(self.user_editor) 

218 self.assertTrue(role.can_impersonate()) 

219 

220 def test_can_access_submission_log(self): 

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

222 role = Editor(self.user_editor) 

223 with self.assertRaises(Submission.DoesNotExist): 

224 submission = role.get_submissions().get(pk=submission.pk) 

225 # self.assertFalse(role.can_access_submission_log(submission)) 

226 

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

228 role = Editor(self.user_editor) 

229 

230 submission = role.get_submissions().get(pk=submission.pk) 

231 self.assertTrue(role.can_access_submission_log(submission)) 

232 

233 def test_can_create_editorial_decision(self): 

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

235 role = Editor(self.user_editor) 

236 with self.assertRaises(Submission.DoesNotExist): 

237 submission = role.get_submissions().get(pk=submission.pk) 

238 # self.assertFalse(role.can_create_editorial_decision(submission)) 

239 

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

241 role = Editor(self.user_editor) 

242 

243 submission = role.get_submissions().get(pk=submission.pk) 

244 self.assertTrue(role.can_create_editorial_decision(submission)) 

245 

246 submission.state = SubmissionState.ON_REVIEW.value 

247 submission.save() 

248 role = Editor(self.user_editor) 

249 

250 submission = role.get_submissions().get(pk=submission.pk) 

251 self.assertTrue(role.can_create_editorial_decision(submission)) 

252 

253 submission.state = SubmissionState.REVISION_REQUESTED.value 

254 submission.save() 

255 role = Editor(self.user_editor) 

256 

257 submission = role.get_submissions().get(pk=submission.pk) 

258 self.assertTrue(role.can_create_editorial_decision(submission)) 

259 

260 submission.state = SubmissionState.REVISION_SUBMITTED.value 

261 submission.save() 

262 role = Editor(self.user_editor) 

263 

264 submission = role.get_submissions().get(pk=submission.pk) 

265 self.assertTrue(role.can_create_editorial_decision(submission)) 

266 

267 submission.state = SubmissionState.ACCEPTED.value 

268 submission.save() 

269 role = Editor(self.user_editor) 

270 

271 submission = role.get_submissions().get(pk=submission.pk) 

272 self.assertTrue(role.can_create_editorial_decision(submission)) 

273 

274 submission.state = SubmissionState.REJECTED.value 

275 submission.save() 

276 role = Editor(self.user_editor) 

277 

278 submission = role.get_submissions().get(pk=submission.pk) 

279 self.assertTrue(role.can_create_editorial_decision(submission)) 

280 

281 def test_can_start_review_process(self): 

282 submission = SubmissionFactory.create(state=SubmissionState.ON_REVIEW.value) 

283 

284 role = Editor(self.user_editor) 

285 with self.assertRaises(Submission.DoesNotExist): 

286 submission = role.get_submissions().get(pk=submission.pk) 

287 # with patch.object(submission, "is_reviewable", lambda _: True): 

288 # self.assertFalse(role.can_start_review_process(submission)) 

289 

290 # with patch.object(submission, "is_reviewable", lambda _: False): 

291 # self.assertFalse(role.can_start_review_process(submission)) 

292 

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

294 role = Editor(self.user_editor) 

295 

296 submission = role.get_submissions().get(pk=submission.pk) 

297 with patch.object(Submission, "is_reviewable", lambda _: True): 

298 self.assertTrue(role.can_start_review_process(submission)) 

299 

300 with patch.object(Submission, "is_reviewable", lambda _: False): 

301 self.assertFalse(role.can_start_review_process(submission)) 

302 

303 def test_can_assign_editor(self): 

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

305 role = Editor(self.user_editor) 

306 with self.assertRaises(Submission.DoesNotExist): 

307 submission = role.get_submissions().get(pk=submission.pk) 

308 # self.assertFalse(role.can_assign_editor(submission)) 

309 

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

311 role = Editor(self.user_editor) 

312 

313 submission = role.get_submissions().get(pk=submission.pk) 

314 self.assertTrue(role.can_assign_editor(submission)) 

315 

316 def test_can_filter_submissions(self): 

317 role = Editor(self.user_editor) 

318 self.assertTrue(role.can_filter_submissions()) 

319 

320 def test_can_access_journal_sections(self): 

321 role = Editor(self.user_editor) 

322 self.assertTrue(role.can_access_journal_sections()) 

323 

324 def test_can_edit_review_file_right(self): 

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

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

327 review = ReviewFactory.create(version=version, submitted=True) 

328 role = Editor(self.user_editor) 

329 with self.assertRaises(Submission.DoesNotExist): 

330 submission = role.get_submissions().get(pk=submission.pk) 

331 # self.assertFalse(role.can_edit_review_file_right(review)) 

332 

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

334 role = Editor(self.user_editor) 

335 

336 submission = role.get_submissions().get(pk=submission.pk) 

337 version = next(v for v in submission.versions_censored if v == version) 

338 review = next(r for r in version.reviews_censored if r == review) 

339 self.assertTrue(role.can_edit_review_file_right(review, submission=submission)) 

340 

341 def test_editor_submission_status(self): 

342 """ 

343 Test the editor status wrt. the whole submission workflow 

344 """ 

345 submission = SubmissionFactory.create(author_agreement=True) 

346 version = SubmissionVersionFactory.create( 

347 submission=submission, submitted=False, review_open=False 

348 ) 

349 SubmissionAuthorFactory.create(submission=submission) 

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

351 

352 # No rights over the submission 

353 role = Editor(self.user_editor) 

354 with self.assertRaises(Submission.DoesNotExist): 

355 submission = role.get_submissions().get(pk=submission.pk) 

356 

357 # status = role.get_submission_status(submission) 

358 # self.assertEqual(status.status, SubmissionStatus.ERROR) 

359 

360 # OPENED submission 

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

362 role = Editor(self.user_editor) 

363 with self.assertRaises(Submission.DoesNotExist): 

364 submission = role.get_submissions().get(pk=submission.pk) 

365 # status = role.get_submission_status(submission) 

366 # self.assertEqual(status.status, SubmissionStatus.ERROR) 

367 

368 # SUBMITTED submission 

369 request = self.dummy_request() 

370 request.user = submission.created_by 

371 submission.submit(submission.created_by) 

372 

373 submission = role.get_submissions().get(pk=submission.pk) 

374 status = role.get_submission_status(submission) 

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

376 

377 # UNDER REVIEW submission with no reviews 

378 # request.user = self.user_editor 

379 # submission.start_review_process(self.user_editor) 

380 # with patch.object(role, "authors_string_annotate", Value("SQLITE_NOT_SUPPORTED")): 

381 # submission = role.get_submissions().get(pk=submission.pk) 

382 # status = role.get_submission_status(submission) 

383 # self.assertEqual(status.status, SubmissionStatus.TODO) 

384 

385 # UNDER REVIEW with pending answer 

386 review = ReviewFactory.create(version=version) 

387 

388 submission = role.get_submissions().get(pk=submission.pk) 

389 status = role.get_submission_status(submission) 

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

391 

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

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

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

395 

396 submission = role.get_submissions().get(pk=submission.pk) 

397 status = role.get_submission_status(submission) 

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

399 

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

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

402 review_overdue.accepted = True 

403 review_overdue.save() 

404 

405 submission = role.get_submissions().get(pk=submission.pk) 

406 status = role.get_submission_status(submission) 

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

408 

409 # UNDER REVIEW with all reviews submitted or declined 

410 review.accepted = False 

411 review.save() 

412 review_overdue.submitted = True 

413 review_overdue.save() 

414 

415 submission = role.get_submissions().get(pk=submission.pk) 

416 status = role.get_submission_status(submission) 

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

418 

419 # REVISIIONS REQUESTED submission 

420 submission.state = SubmissionState.REVISION_REQUESTED.value 

421 submission.save() 

422 

423 submission = role.get_submissions().get(pk=submission.pk) 

424 status = role.get_submission_status(submission) 

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

426 version.review_open = False 

427 version.save() 

428 

429 # REVISIONS SUBMITTED submission 

430 version_2 = SubmissionVersionFactory.create( 

431 submission=submission, submitted=False, review_open=False 

432 ) 

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

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

435 request.user = self.user_author 

436 submission.submit(self.user_author) 

437 

438 submission = role.get_submissions().get(pk=submission.pk) 

439 status = role.get_submission_status(submission) 

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

441 

442 # ACCEPTED submission 

443 submission.state = SubmissionState.ACCEPTED.value 

444 submission.save() 

445 

446 submission = role.get_submissions().get(pk=submission.pk) 

447 status = role.get_submission_status(submission) 

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

449 

450 # REJECTED submission 

451 submission.state = SubmissionState.REJECTED.value 

452 submission.save() 

453 

454 submission = role.get_submissions().get(pk=submission.pk) 

455 status = role.get_submission_status(submission) 

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

457 

458 

459class EditorUtilsTestCase(BaseTestCase): 

460 def test_section_editors(self): 

461 journal_section_1 = JournalSectionFactory.create() 

462 journal_section_2 = JournalSectionFactory.create(parent=journal_section_1) 

463 journal_section_3 = JournalSectionFactory.create(parent=journal_section_1) 

464 journal_section_4 = JournalSectionFactory.create(parent=journal_section_2) 

465 

466 submission = SubmissionFactory.create(journal_section=journal_section_4) 

467 

468 user_editor_1 = UserFactory.create() 

469 user_editor_2 = UserFactory.create() 

470 user_editor_3 = UserFactory.create() 

471 user_editor_4 = UserFactory.create() 

472 

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

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

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

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

477 

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

479 

480 section_editors = get_section_editors(submission) 

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

482 self.assertIn(user_editor_1, section_editors) 

483 self.assertIn(user_editor_2, section_editors) 

484 self.assertIn(user_editor_4, section_editors)