wbwriter 2.2.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wbwriter might be problematic. Click here for more details.

Files changed (70) hide show
  1. wbwriter/__init__.py +1 -0
  2. wbwriter/admin.py +142 -0
  3. wbwriter/apps.py +5 -0
  4. wbwriter/dynamic_preferences_registry.py +15 -0
  5. wbwriter/factories/__init__.py +13 -0
  6. wbwriter/factories/article.py +181 -0
  7. wbwriter/factories/meta_information.py +29 -0
  8. wbwriter/filters/__init__.py +2 -0
  9. wbwriter/filters/article.py +47 -0
  10. wbwriter/filters/metainformationinstance.py +24 -0
  11. wbwriter/migrations/0001_initial_squashed_squashed_0008_alter_article_author_alter_article_feedback_contact_and_more.py +653 -0
  12. wbwriter/migrations/0009_dependantarticle.py +41 -0
  13. wbwriter/migrations/0010_alter_article_options.py +20 -0
  14. wbwriter/migrations/0011_auto_20240103_0953.py +39 -0
  15. wbwriter/migrations/__init__.py +0 -0
  16. wbwriter/models/__init__.py +9 -0
  17. wbwriter/models/article.py +1179 -0
  18. wbwriter/models/article_type.py +59 -0
  19. wbwriter/models/block.py +24 -0
  20. wbwriter/models/block_parameter.py +19 -0
  21. wbwriter/models/in_editor_template.py +102 -0
  22. wbwriter/models/meta_information.py +87 -0
  23. wbwriter/models/mixins.py +9 -0
  24. wbwriter/models/publication_models.py +170 -0
  25. wbwriter/models/style.py +13 -0
  26. wbwriter/models/template.py +34 -0
  27. wbwriter/pdf_generator.py +172 -0
  28. wbwriter/publication_parser.py +258 -0
  29. wbwriter/serializers/__init__.py +28 -0
  30. wbwriter/serializers/article.py +359 -0
  31. wbwriter/serializers/article_type.py +14 -0
  32. wbwriter/serializers/in_editor_template.py +37 -0
  33. wbwriter/serializers/meta_information.py +67 -0
  34. wbwriter/serializers/publication.py +82 -0
  35. wbwriter/templatetags/__init__.py +0 -0
  36. wbwriter/templatetags/writer.py +72 -0
  37. wbwriter/tests/__init__.py +0 -0
  38. wbwriter/tests/conftest.py +32 -0
  39. wbwriter/tests/signals.py +23 -0
  40. wbwriter/tests/test_filter.py +58 -0
  41. wbwriter/tests/test_model.py +591 -0
  42. wbwriter/tests/test_writer.py +38 -0
  43. wbwriter/tests/tests.py +18 -0
  44. wbwriter/typings.py +23 -0
  45. wbwriter/urls.py +83 -0
  46. wbwriter/viewsets/__init__.py +22 -0
  47. wbwriter/viewsets/article.py +270 -0
  48. wbwriter/viewsets/article_type.py +49 -0
  49. wbwriter/viewsets/buttons.py +61 -0
  50. wbwriter/viewsets/display/__init__.py +6 -0
  51. wbwriter/viewsets/display/article.py +404 -0
  52. wbwriter/viewsets/display/article_type.py +27 -0
  53. wbwriter/viewsets/display/in_editor_template.py +39 -0
  54. wbwriter/viewsets/display/meta_information.py +37 -0
  55. wbwriter/viewsets/display/meta_information_instance.py +28 -0
  56. wbwriter/viewsets/display/publication.py +55 -0
  57. wbwriter/viewsets/endpoints/__init__.py +2 -0
  58. wbwriter/viewsets/endpoints/article.py +12 -0
  59. wbwriter/viewsets/endpoints/meta_information.py +14 -0
  60. wbwriter/viewsets/in_editor_template.py +68 -0
  61. wbwriter/viewsets/menu.py +42 -0
  62. wbwriter/viewsets/meta_information.py +51 -0
  63. wbwriter/viewsets/meta_information_instance.py +48 -0
  64. wbwriter/viewsets/publication.py +117 -0
  65. wbwriter/viewsets/titles/__init__.py +2 -0
  66. wbwriter/viewsets/titles/publication_title_config.py +18 -0
  67. wbwriter/viewsets/titles/reviewer_article_title_config.py +6 -0
  68. wbwriter-2.2.1.dist-info/METADATA +8 -0
  69. wbwriter-2.2.1.dist-info/RECORD +70 -0
  70. wbwriter-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,591 @@
1
+ from unittest.mock import patch
2
+
3
+ import pytest
4
+ from django.forms.models import model_to_dict
5
+ from django_fsm import has_transition_perm
6
+ from wbcore.contrib.authentication.factories import UserFactory
7
+ from wbcore.contrib.authentication.models import Permission, User
8
+ from wbwriter.factories import (
9
+ ArticleFactory,
10
+ ArticleTypeFactory,
11
+ DependantArticleFactory,
12
+ MetaInformationInstanceFactory,
13
+ )
14
+ from wbwriter.models import ArticleType, Publication
15
+ from wbwriter.models.article import (
16
+ Article,
17
+ DependantArticle,
18
+ can_access_article,
19
+ can_administrate_article,
20
+ can_edit_article_content,
21
+ can_edit_article_meta_data,
22
+ can_edit_article_type,
23
+ can_request_peer_review,
24
+ generate_publications,
25
+ )
26
+ from wbwriter.models.meta_information import MetaInformationInstance
27
+
28
+
29
+ @pytest.mark.django_db
30
+ class TestArticleTransitions:
31
+ @pytest.mark.parametrize("author", [True, False])
32
+ def test_requestfeedback(self, author):
33
+ user = UserFactory(is_superuser=False)
34
+ if author:
35
+ article = ArticleFactory(status=Article.Status.DRAFT, author=user.profile)
36
+ assert has_transition_perm(article.requestfeedback, user) is True
37
+ else:
38
+ article = ArticleFactory(status=Article.Status.DRAFT)
39
+ assert has_transition_perm(article.requestfeedback, user) is False
40
+
41
+ @pytest.mark.parametrize("reviewer", [True, False])
42
+ def test_submitfeedback(self, reviewer):
43
+ author_user = UserFactory(is_superuser=False)
44
+ reviewer_user = UserFactory(is_superuser=False)
45
+ article = ArticleFactory(
46
+ status=Article.Status.FEEDBACK,
47
+ author=author_user.profile,
48
+ reviewer=reviewer_user.profile if reviewer else UserFactory().profile,
49
+ )
50
+ if reviewer:
51
+ assert has_transition_perm(article.submitfeedback, reviewer_user) is True
52
+ assert has_transition_perm(article.submitfeedback, author_user) is False
53
+ else:
54
+ article = ArticleFactory(status=Article.Status.FEEDBACK)
55
+ assert has_transition_perm(article.submitfeedback, reviewer_user) is False
56
+
57
+ @pytest.mark.parametrize("author", [True, False])
58
+ def test_requestpeerreview(self, author):
59
+ author_user = UserFactory(is_superuser=False)
60
+ reviewer_user = UserFactory(is_superuser=False)
61
+ article_review_approved = ArticleFactory(
62
+ status=Article.Status.DRAFT,
63
+ author=author_user.profile if author else UserFactory().profile,
64
+ reviewer=reviewer_user.profile,
65
+ peer_reviewer_approved=True,
66
+ )
67
+ article_not_review_approved = ArticleFactory(
68
+ status=Article.Status.DRAFT,
69
+ author=author_user.profile if author else UserFactory().profile,
70
+ reviewer=reviewer_user.profile,
71
+ peer_reviewer_approved=False,
72
+ )
73
+ if author:
74
+ assert has_transition_perm(article_review_approved.requestpeerreview, author_user) is False
75
+ assert has_transition_perm(article_review_approved.requestpeerreview, reviewer_user) is False
76
+ assert has_transition_perm(article_not_review_approved.requestpeerreview, author_user) is True
77
+ else:
78
+ assert has_transition_perm(article_review_approved.requestpeerreview, author_user) is False
79
+ assert has_transition_perm(article_not_review_approved.requestpeerreview, author_user) is False
80
+
81
+ @pytest.mark.parametrize("author", [True, False])
82
+ def test_requestqareview(self, author):
83
+ author_user = UserFactory(is_superuser=False)
84
+ reviewer_user = UserFactory(is_superuser=False)
85
+ article_review_approved = ArticleFactory(
86
+ status=Article.Status.DRAFT,
87
+ author=author_user.profile if author else UserFactory().profile,
88
+ reviewer=reviewer_user.profile,
89
+ peer_reviewer_approved=True,
90
+ )
91
+ article_not_review_approved = ArticleFactory(
92
+ status=Article.Status.DRAFT,
93
+ author=author_user.profile if author else UserFactory().profile,
94
+ reviewer=reviewer_user.profile,
95
+ peer_reviewer_approved=False,
96
+ )
97
+ if author:
98
+ assert has_transition_perm(article_review_approved.requestqareview, author_user) is True
99
+ assert has_transition_perm(article_not_review_approved.requestqareview, author_user) is False
100
+ assert has_transition_perm(article_review_approved.requestqareview, reviewer_user) is False
101
+ else:
102
+ assert has_transition_perm(article_review_approved.requestqareview, author_user) is False
103
+ assert has_transition_perm(article_not_review_approved.requestqareview, author_user) is False
104
+
105
+ def test_peerapprove(self):
106
+ super_user = UserFactory(is_superuser=True)
107
+ author_user = UserFactory(is_superuser=False)
108
+ reviewer_user = UserFactory(is_superuser=False)
109
+ peer_reviewer_user_a = UserFactory(is_superuser=False)
110
+ peer_reviewer_user_b = UserFactory(is_superuser=False)
111
+ article_type_a = ArticleTypeFactory(peer_reviewers=[peer_reviewer_user_a.profile])
112
+ ArticleTypeFactory(peer_reviewers=[peer_reviewer_user_b.profile])
113
+
114
+ article = ArticleFactory(
115
+ status=Article.Status.PEER_REVIEW,
116
+ author=author_user.profile,
117
+ reviewer=reviewer_user.profile,
118
+ peer_reviewer=peer_reviewer_user_a.profile,
119
+ type=article_type_a,
120
+ )
121
+
122
+ assert has_transition_perm(article.peerapprove, author_user) is False
123
+ assert has_transition_perm(article.peerapprove, reviewer_user) is False
124
+ assert has_transition_perm(article.peerapprove, peer_reviewer_user_b) is False
125
+ assert has_transition_perm(article.peerapprove, peer_reviewer_user_a) is True
126
+ assert has_transition_perm(article.peerapprove, super_user) is True
127
+
128
+ def test_peerreject(self):
129
+ super_user = UserFactory(is_superuser=True)
130
+ author_user = UserFactory(is_superuser=False)
131
+ reviewer_user = UserFactory(is_superuser=False)
132
+ peer_reviewer_user_a = UserFactory(is_superuser=False)
133
+ peer_reviewer_user_b = UserFactory(is_superuser=False)
134
+ ArticleTypeFactory(peer_reviewers=[peer_reviewer_user_b.profile])
135
+ article_type_a = ArticleTypeFactory(peer_reviewers=[peer_reviewer_user_a.profile])
136
+
137
+ article = ArticleFactory(
138
+ status=Article.Status.PEER_REVIEW,
139
+ author=author_user.profile,
140
+ reviewer=reviewer_user.profile,
141
+ peer_reviewer=peer_reviewer_user_a.profile,
142
+ type=article_type_a,
143
+ )
144
+
145
+ assert has_transition_perm(article.peerapprove, author_user) is False
146
+ assert has_transition_perm(article.peerapprove, reviewer_user) is False
147
+ assert has_transition_perm(article.peerapprove, peer_reviewer_user_b) is False
148
+ assert has_transition_perm(article.peerapprove, peer_reviewer_user_a) is True
149
+ assert has_transition_perm(article.peerapprove, super_user) is True
150
+
151
+ def test_qa_reject(self):
152
+ super_user = UserFactory(is_superuser=True)
153
+ author_user = UserFactory(is_superuser=False)
154
+ reviewer_user = UserFactory(is_superuser=False)
155
+ peer_reviewer_user = UserFactory(is_superuser=False)
156
+ qa_reviewer_user_a = UserFactory(is_superuser=False)
157
+ qa_reviewer_user_b = UserFactory(is_superuser=False)
158
+ ArticleTypeFactory(qa_reviewers=[qa_reviewer_user_b.profile])
159
+
160
+ article_type_a = ArticleTypeFactory(
161
+ peer_reviewers=[peer_reviewer_user.profile],
162
+ qa_reviewers=[qa_reviewer_user_a.profile],
163
+ )
164
+
165
+ article = ArticleFactory(
166
+ status=Article.Status.QA_REVIEW,
167
+ author=author_user.profile,
168
+ reviewer=reviewer_user.profile,
169
+ peer_reviewer=peer_reviewer_user.profile,
170
+ qa_reviewer=qa_reviewer_user_a.profile,
171
+ type=article_type_a,
172
+ )
173
+
174
+ assert has_transition_perm(article.qareject, author_user) is False
175
+ assert has_transition_perm(article.qareject, reviewer_user) is False
176
+ assert has_transition_perm(article.qareject, peer_reviewer_user) is False
177
+ assert has_transition_perm(article.qareject, qa_reviewer_user_b) is False
178
+ assert has_transition_perm(article.qareject, super_user) is True
179
+ assert has_transition_perm(article.qareject, qa_reviewer_user_a) is True
180
+
181
+ def test_qa_approve(self):
182
+ super_user = UserFactory(is_superuser=True)
183
+ author_user = UserFactory(is_superuser=False)
184
+ reviewer_user = UserFactory(is_superuser=False)
185
+ peer_reviewer_user = UserFactory(is_superuser=False)
186
+ qa_reviewer_user_a = UserFactory(is_superuser=False)
187
+ qa_reviewer_user_b = UserFactory(is_superuser=False)
188
+ ArticleTypeFactory(qa_reviewers=[qa_reviewer_user_b.profile])
189
+
190
+ article_type_a = ArticleTypeFactory(
191
+ peer_reviewers=[peer_reviewer_user.profile],
192
+ qa_reviewers=[qa_reviewer_user_a.profile],
193
+ )
194
+
195
+ article = ArticleFactory(
196
+ status=Article.Status.QA_REVIEW,
197
+ author=author_user.profile,
198
+ reviewer=reviewer_user.profile,
199
+ peer_reviewer=peer_reviewer_user.profile,
200
+ qa_reviewer=qa_reviewer_user_a.profile,
201
+ type=article_type_a,
202
+ )
203
+
204
+ assert has_transition_perm(article.qaapprove, author_user) is False
205
+ assert has_transition_perm(article.qaapprove, reviewer_user) is False
206
+ assert has_transition_perm(article.qaapprove, peer_reviewer_user) is False
207
+ assert has_transition_perm(article.qaapprove, qa_reviewer_user_b) is False
208
+ assert has_transition_perm(article.qaapprove, super_user) is True
209
+ assert has_transition_perm(article.qaapprove, qa_reviewer_user_a) is True
210
+
211
+ def test_authorreject(self):
212
+ super_user = UserFactory(is_superuser=True)
213
+ author_user = UserFactory(is_superuser=False)
214
+ reviewer_user = UserFactory(is_superuser=False)
215
+ peer_reviewer_user = UserFactory(is_superuser=False)
216
+ qa_reviewer_user = UserFactory(is_superuser=False)
217
+ article_type_a = ArticleTypeFactory(
218
+ peer_reviewers=[peer_reviewer_user.profile],
219
+ qa_reviewers=[qa_reviewer_user.profile],
220
+ )
221
+ article = ArticleFactory(
222
+ status=Article.Status.AUTHOR_APPROVAL,
223
+ author=author_user.profile,
224
+ reviewer=reviewer_user.profile,
225
+ peer_reviewer=peer_reviewer_user.profile,
226
+ qa_reviewer=qa_reviewer_user.profile,
227
+ type=article_type_a,
228
+ )
229
+
230
+ assert has_transition_perm(article.authorreject, reviewer_user) is False
231
+ assert has_transition_perm(article.authorreject, peer_reviewer_user) is False
232
+ assert has_transition_perm(article.authorreject, qa_reviewer_user) is False
233
+ assert has_transition_perm(article.authorreject, super_user) is True
234
+ assert has_transition_perm(article.authorreject, author_user) is True
235
+
236
+ def test_authorapprove(self):
237
+ super_user = UserFactory(is_superuser=True)
238
+ author_user = UserFactory(is_superuser=False)
239
+ reviewer_user = UserFactory(is_superuser=False)
240
+ peer_reviewer_user = UserFactory(is_superuser=False)
241
+ qa_reviewer_user = UserFactory(is_superuser=False)
242
+ article_type_a = ArticleTypeFactory(
243
+ peer_reviewers=[peer_reviewer_user.profile],
244
+ qa_reviewers=[qa_reviewer_user.profile],
245
+ )
246
+ article = ArticleFactory(
247
+ status=Article.Status.AUTHOR_APPROVAL,
248
+ author=author_user.profile,
249
+ reviewer=reviewer_user.profile,
250
+ peer_reviewer=peer_reviewer_user.profile,
251
+ qa_reviewer=qa_reviewer_user.profile,
252
+ type=article_type_a,
253
+ )
254
+
255
+ assert has_transition_perm(article.authorapprove, reviewer_user) is False
256
+ assert has_transition_perm(article.authorapprove, peer_reviewer_user) is False
257
+ assert has_transition_perm(article.authorapprove, qa_reviewer_user) is False
258
+ assert has_transition_perm(article.authorapprove, super_user) is True
259
+ assert has_transition_perm(article.authorapprove, author_user) is True
260
+
261
+ def test_publish(self):
262
+ super_user = UserFactory(is_superuser=True)
263
+ author_user = UserFactory(is_superuser=False)
264
+ reviewer_user = UserFactory(is_superuser=False)
265
+ peer_reviewer_user = UserFactory(is_superuser=False)
266
+ qa_reviewer_user = UserFactory(is_superuser=False)
267
+ can_publish_user: User = UserFactory(is_superuser=False)
268
+ can_publish_user.user_permissions.add(Permission.objects.get(codename="administrate_article"))
269
+
270
+ article_type = ArticleTypeFactory(
271
+ peer_reviewers=[peer_reviewer_user.profile],
272
+ qa_reviewers=[qa_reviewer_user.profile],
273
+ label="one-off-article",
274
+ )
275
+ article = ArticleFactory(
276
+ status=Article.Status.APPROVED,
277
+ author=author_user.profile,
278
+ reviewer=reviewer_user.profile,
279
+ peer_reviewer=peer_reviewer_user.profile,
280
+ qa_reviewer=qa_reviewer_user.profile,
281
+ type=article_type,
282
+ )
283
+ assert has_transition_perm(article.publish, reviewer_user) is False
284
+ assert has_transition_perm(article.publish, peer_reviewer_user) is False
285
+ assert has_transition_perm(article.publish, qa_reviewer_user) is False
286
+ assert has_transition_perm(article.publish, author_user) is False
287
+ assert has_transition_perm(article.publish, super_user) is True
288
+ assert has_transition_perm(article.publish, can_publish_user) is True
289
+
290
+ def test_unpublish(self):
291
+ super_user = UserFactory(is_superuser=True)
292
+ author_user = UserFactory(is_superuser=False)
293
+ reviewer_user = UserFactory(is_superuser=False)
294
+ peer_reviewer_user = UserFactory(is_superuser=False)
295
+ qa_reviewer_user = UserFactory(is_superuser=False)
296
+ can_publish_user: User = UserFactory(is_superuser=False)
297
+ can_publish_user.user_permissions.add(Permission.objects.get(codename="administrate_article"))
298
+
299
+ article_type = ArticleTypeFactory(
300
+ peer_reviewers=[peer_reviewer_user.profile],
301
+ qa_reviewers=[qa_reviewer_user.profile],
302
+ label="one-off-article",
303
+ )
304
+ article = ArticleFactory(
305
+ status=Article.Status.PUBLISHED,
306
+ author=author_user.profile,
307
+ reviewer=reviewer_user.profile,
308
+ peer_reviewer=peer_reviewer_user.profile,
309
+ qa_reviewer=qa_reviewer_user.profile,
310
+ type=article_type,
311
+ )
312
+ assert has_transition_perm(article.unpublish, reviewer_user) is False
313
+ assert has_transition_perm(article.unpublish, peer_reviewer_user) is False
314
+ assert has_transition_perm(article.unpublish, qa_reviewer_user) is False
315
+ assert has_transition_perm(article.unpublish, author_user) is False
316
+ assert has_transition_perm(article.unpublish, super_user) is True
317
+ assert has_transition_perm(article.unpublish, can_publish_user) is True
318
+
319
+ def test_authorrevise(self):
320
+ super_user = UserFactory(is_superuser=True)
321
+ author_user = UserFactory(is_superuser=False)
322
+ reviewer_user = UserFactory(is_superuser=False)
323
+ peer_reviewer_user = UserFactory(is_superuser=False)
324
+ qa_reviewer_user = UserFactory(is_superuser=False)
325
+ administrate_user: User = UserFactory(is_superuser=False)
326
+ administrate_user.user_permissions.add(Permission.objects.get(codename="administrate_article"))
327
+
328
+ article_type = ArticleTypeFactory(
329
+ peer_reviewers=[peer_reviewer_user.profile],
330
+ qa_reviewers=[qa_reviewer_user.profile],
331
+ label="one-off-article",
332
+ )
333
+ article = ArticleFactory(
334
+ status=Article.Status.APPROVED,
335
+ author=author_user.profile,
336
+ reviewer=reviewer_user.profile,
337
+ peer_reviewer=peer_reviewer_user.profile,
338
+ qa_reviewer=qa_reviewer_user.profile,
339
+ type=article_type,
340
+ )
341
+ assert has_transition_perm(article.authorrevise, reviewer_user) is False
342
+ assert has_transition_perm(article.authorrevise, peer_reviewer_user) is False
343
+ assert has_transition_perm(article.authorrevise, qa_reviewer_user) is False
344
+ assert has_transition_perm(article.authorrevise, author_user) is True
345
+ assert has_transition_perm(article.authorrevise, super_user) is True
346
+ assert has_transition_perm(article.authorrevise, administrate_user) is True
347
+
348
+ def test_qarevise(self):
349
+ super_user = UserFactory(is_superuser=True)
350
+ author_user = UserFactory(is_superuser=False)
351
+ reviewer_user = UserFactory(is_superuser=False)
352
+ peer_reviewer_user = UserFactory(is_superuser=False)
353
+ qa_reviewer_user_a = UserFactory(is_superuser=False)
354
+ qa_reviewer_user_b = UserFactory(is_superuser=False)
355
+ administrate_user: User = UserFactory(is_superuser=False)
356
+ administrate_user.user_permissions.add(Permission.objects.get(codename="administrate_article"))
357
+
358
+ article_type = ArticleTypeFactory(
359
+ peer_reviewers=[peer_reviewer_user.profile],
360
+ qa_reviewers=[qa_reviewer_user_a.profile, qa_reviewer_user_b.profile],
361
+ label="one-off-article",
362
+ )
363
+ article = ArticleFactory(
364
+ status=Article.Status.APPROVED,
365
+ author=author_user.profile,
366
+ reviewer=reviewer_user.profile,
367
+ peer_reviewer=peer_reviewer_user.profile,
368
+ qa_reviewer=qa_reviewer_user_a.profile,
369
+ type=article_type,
370
+ )
371
+ assert has_transition_perm(article.qarevise, reviewer_user) is False
372
+ assert has_transition_perm(article.qarevise, peer_reviewer_user) is False
373
+ assert has_transition_perm(article.qarevise, qa_reviewer_user_a) is True
374
+ assert has_transition_perm(article.qarevise, qa_reviewer_user_b) is True
375
+ assert has_transition_perm(article.qarevise, author_user) is False
376
+ assert has_transition_perm(article.qarevise, super_user) is True
377
+ assert has_transition_perm(article.qarevise, administrate_user) is True
378
+
379
+
380
+ @pytest.mark.django_db
381
+ class TestArticlePermissions:
382
+ def test_can_administrate_article(self):
383
+ super_user: User = UserFactory(is_superuser=True)
384
+ article_admin_user: User = UserFactory(is_superuser=False)
385
+ article_admin_user.user_permissions.add(Permission.objects.get(codename="administrate_article"))
386
+ unalligned_user: User = UserFactory(is_superuser=False)
387
+
388
+ article = ArticleFactory()
389
+ assert can_administrate_article(article, super_user)
390
+ assert can_administrate_article(article, article_admin_user)
391
+ assert not can_administrate_article(article, unalligned_user)
392
+
393
+ def test_can_publish_articles(self):
394
+ super_user: User = UserFactory(is_superuser=True)
395
+ article_admin_user: User = UserFactory(is_superuser=False)
396
+ article_admin_user.user_permissions.add(Permission.objects.get(codename="administrate_article"))
397
+ unalligned_user: User = UserFactory(is_superuser=False)
398
+
399
+ article: Article = ArticleFactory()
400
+ assert can_administrate_article(article, super_user)
401
+ assert can_administrate_article(article, article_admin_user)
402
+ assert not can_administrate_article(article, unalligned_user)
403
+
404
+ @patch.object(Publication, "create_or_update_from_parser_and_object")
405
+ def test_can_be_published(self, mock_fct):
406
+ article_a: Article = ArticleFactory(type=ArticleTypeFactory(label="One Off Article"))
407
+
408
+ assert article_a.can_be_published() is False
409
+ generate_publications(article_a.id)
410
+ assert mock_fct.call_count == 0
411
+
412
+ article_a.status = Article.Status.APPROVED
413
+ article_a.save()
414
+ assert article_a.can_be_published()
415
+ generate_publications(article_a.id)
416
+ assert mock_fct.call_count == 1
417
+
418
+ article_b: Article = ArticleFactory(
419
+ status=Article.Status.APPROVED, type=ArticleTypeFactory(label="Deep Dive Article")
420
+ )
421
+ article_c: Article = ArticleFactory(
422
+ status=Article.Status.APPROVED, type=ArticleTypeFactory(label="Mid Year Review")
423
+ )
424
+ article_d: Article = ArticleFactory(
425
+ status=Article.Status.APPROVED, type=ArticleTypeFactory(label="Unalligned Article")
426
+ )
427
+ assert article_a.can_be_published()
428
+ assert article_b.can_be_published()
429
+ assert article_c.can_be_published()
430
+ generate_publications(article_a.id)
431
+ generate_publications(article_b.id)
432
+ generate_publications(article_c.id)
433
+ assert mock_fct.call_count == 4
434
+ assert not article_d.can_be_published()
435
+ generate_publications(article_d.id)
436
+ assert mock_fct.call_count == 4
437
+
438
+ def test_can_access_article(self):
439
+ super_user: User = UserFactory(is_superuser=True)
440
+ reviewer_user: User = UserFactory(is_superuser=False)
441
+ is_qa_reviewer_user: User = UserFactory(is_superuser=False)
442
+ is_peer_reviewer_user: User = UserFactory(is_superuser=False)
443
+ user_can_administrate_article: User = UserFactory(is_superuser=False)
444
+ unalligned_user: User = UserFactory(is_superuser=False)
445
+
446
+ user_can_administrate_article.user_permissions.add(Permission.objects.get(codename="administrate_article"))
447
+ article_type: ArticleType = ArticleTypeFactory(
448
+ peer_reviewers=[is_peer_reviewer_user.profile], qa_reviewers=[is_qa_reviewer_user.profile]
449
+ )
450
+ article: Article = ArticleFactory(type=article_type, reviewer=reviewer_user.profile)
451
+
452
+ assert can_access_article(article, super_user)
453
+ # assert can_access_article(article, employee_user)
454
+ assert can_access_article(article, is_qa_reviewer_user)
455
+ assert can_access_article(article, is_peer_reviewer_user)
456
+ assert can_access_article(article, user_can_administrate_article)
457
+ assert not can_access_article(article, unalligned_user)
458
+
459
+ def test_can_edit_article_author(self):
460
+ self.test_can_administrate_article()
461
+
462
+ def test_can_edit_article_content(self):
463
+ user = UserFactory(is_superuser=False)
464
+ user_unalligned = UserFactory(is_superuser=False)
465
+ user_su = UserFactory(is_superuser=True)
466
+
467
+ article_type = ArticleTypeFactory(peer_reviewers=[user.profile], qa_reviewers=[user.profile])
468
+
469
+ article_draft: Article = ArticleFactory(status=Article.Status.DRAFT, author=user.profile)
470
+ article_feedback: Article = ArticleFactory(status=Article.Status.FEEDBACK, reviewer=user.profile)
471
+ article_peer_review: Article = ArticleFactory(
472
+ status=Article.Status.PEER_REVIEW, peer_reviewer=user.profile, type=article_type
473
+ )
474
+ article_qa_review: Article = ArticleFactory(
475
+ status=Article.Status.QA_REVIEW, qa_reviewer=user.profile, type=article_type
476
+ )
477
+ article_approved: Article = ArticleFactory(status=Article.Status.APPROVED)
478
+
479
+ assert can_edit_article_content(article_draft, user)
480
+ assert not can_edit_article_content(article_draft, user_unalligned)
481
+ assert can_edit_article_content(article_feedback, user)
482
+ assert not can_edit_article_content(article_feedback, user_unalligned)
483
+ assert can_edit_article_content(article_peer_review, user)
484
+ assert not can_edit_article_content(article_peer_review, user_unalligned)
485
+ assert can_edit_article_content(article_qa_review, user)
486
+ assert not can_edit_article_content(article_qa_review, user_unalligned)
487
+ assert can_edit_article_content(article_approved, user_su)
488
+ assert not can_edit_article_content(article_approved, user_unalligned)
489
+
490
+ def test_can_edit_article_meta_data(self):
491
+ user = UserFactory(is_superuser=False)
492
+ user_unalligned = UserFactory(is_superuser=False)
493
+
494
+ article_type = ArticleTypeFactory(peer_reviewers=[user.profile], qa_reviewers=[user.profile])
495
+
496
+ article_draft: Article = ArticleFactory(status=Article.Status.DRAFT, author=user.profile)
497
+ article_feedback: Article = ArticleFactory(status=Article.Status.FEEDBACK, reviewer=user.profile)
498
+ article_peer_review: Article = ArticleFactory(
499
+ status=Article.Status.PEER_REVIEW, peer_reviewer=user.profile, type=article_type
500
+ )
501
+ article_qa_review: Article = ArticleFactory(
502
+ status=Article.Status.QA_REVIEW, qa_reviewer=user.profile, type=article_type
503
+ )
504
+
505
+ assert can_edit_article_meta_data(article_draft, user=user)
506
+ assert not can_edit_article_meta_data(article_draft, user=user_unalligned)
507
+ assert can_edit_article_meta_data(article_feedback, user=user)
508
+ assert not can_edit_article_meta_data(article_feedback, user=user_unalligned)
509
+ assert can_edit_article_meta_data(article_peer_review, user=user)
510
+ assert not can_edit_article_meta_data(article_peer_review, user=user_unalligned)
511
+ assert can_edit_article_meta_data(article_qa_review, user=user)
512
+ assert not can_edit_article_meta_data(article_qa_review, user=user_unalligned)
513
+
514
+ def test_can_edit_article_type(self):
515
+ user = UserFactory(is_superuser=False)
516
+ user_unalligned = UserFactory(is_superuser=False)
517
+ article_draft: Article = ArticleFactory(status=Article.Status.DRAFT, author=user.profile)
518
+ article_feedback: Article = ArticleFactory(status=Article.Status.FEEDBACK, author=user.profile)
519
+
520
+ assert can_edit_article_type(article_draft, user)
521
+ assert not can_edit_article_type(article_feedback, user)
522
+ assert not can_edit_article_type(article_draft, user_unalligned)
523
+
524
+ @pytest.mark.parametrize("peer_reviewer_approved", [True, False])
525
+ def test_can_request_peer_review(self, peer_reviewer_approved):
526
+ article = ArticleFactory(peer_reviewer_approved=peer_reviewer_approved)
527
+ if peer_reviewer_approved:
528
+ assert not can_request_peer_review(article)
529
+ else:
530
+ assert can_request_peer_review(article)
531
+
532
+
533
+ @pytest.mark.django_db
534
+ class TestArticleCloning:
535
+ def test_clone(self, user):
536
+ article = ArticleFactory()
537
+ article = Article.objects.get(
538
+ id=article.id
539
+ ) # To get updated tag_detail_endpoint and tag_representation from db
540
+ meta_information_instance = MetaInformationInstanceFactory(article=article)
541
+ dependender_relationship = DependantArticleFactory(article=article)
542
+ dependendee_relationship = DependantArticleFactory(dependant_article=article)
543
+ assert Article.objects.count() == 3
544
+ assert DependantArticle.objects.count() == 2
545
+ assert MetaInformationInstance.objects.count() == 1
546
+
547
+ cloned_article = article.clone(user=user)
548
+
549
+ # Article was correctly cloned
550
+ article_dict = model_to_dict(article)
551
+ del article_dict["id"]
552
+ del article_dict["teaser_image"]
553
+ article_clone_dict = model_to_dict(cloned_article)
554
+ assert article_clone_dict
555
+ del article_clone_dict["id"]
556
+ del article_clone_dict["teaser_image"]
557
+ article_dict["name"] += "_clone"
558
+ article_dict["slug"] += "-clone"
559
+ article_dict["title"] += " (Clone)"
560
+ article_dict["author"] = user.profile.id
561
+ assert article_dict == article_clone_dict
562
+ assert Article.objects.count() == 4
563
+
564
+ # Related dependant articles were correctly cloned
565
+ dependender_relationship_dict = model_to_dict(dependender_relationship)
566
+ del dependender_relationship_dict["id"]
567
+ dependender_relationship_clone_dict = model_to_dict(DependantArticle.objects.get(id=3))
568
+ assert dependender_relationship_clone_dict
569
+ del dependender_relationship_clone_dict["id"]
570
+ dependender_relationship_clone_dict["article"] = article.id
571
+ assert dependender_relationship_dict == dependender_relationship_clone_dict
572
+
573
+ dependendee_relationship_dict = model_to_dict(dependendee_relationship)
574
+ del dependendee_relationship_dict["id"]
575
+ dependendee_relationship_clone_dict = model_to_dict(DependantArticle.objects.get(id=4))
576
+ assert dependendee_relationship_clone_dict
577
+ del dependendee_relationship_clone_dict["id"]
578
+ dependendee_relationship_clone_dict["dependant_article"] = article.id
579
+ assert dependendee_relationship_dict == dependendee_relationship_clone_dict
580
+
581
+ assert DependantArticle.objects.count() == 4
582
+
583
+ # Related meta information instances were correctly cloned
584
+ meta_information_instance_dict = model_to_dict(meta_information_instance)
585
+ del meta_information_instance_dict["id"]
586
+ meta_information_instance_clone_dict = model_to_dict(MetaInformationInstance.objects.last())
587
+ assert meta_information_instance_clone_dict
588
+ del meta_information_instance_clone_dict["id"]
589
+ meta_information_instance_clone_dict["article"] = article.id
590
+ assert meta_information_instance_dict == meta_information_instance_clone_dict
591
+ assert MetaInformationInstance.objects.count() == 2
@@ -0,0 +1,38 @@
1
+ import pytest
2
+ from wbwriter.templatetags.writer import cite_article, table_of_contents
3
+
4
+
5
+ @pytest.mark.django_db
6
+ class TestWriter:
7
+ def test_table_of_contents(self, article_factory):
8
+ article_dict = {"article": article_factory(title="Test Article Title", name="Test Article Name")}
9
+ toc = table_of_contents(article_dict, "ToC ")
10
+ test_toc = {
11
+ "title": "Test Article Title",
12
+ "custom_enumeration": True,
13
+ "anchor": "test-article-name",
14
+ "enumerator": None,
15
+ "level": 0,
16
+ "articles": [],
17
+ }
18
+ assert toc == test_toc
19
+
20
+ def test_table_of_contents_no_context(self):
21
+ no_article_dict = {"blog": "Some Blog"}
22
+ toc = table_of_contents(no_article_dict, "ToC ")
23
+ test_toc = {"not_working": "<i>Table of content is only rendered in the exported PDF Version.</i>"}
24
+ assert toc == test_toc
25
+
26
+ def test_cite_article(self, article_factory):
27
+ article = article_factory(title="Test Article Title", name="Test Article Name")
28
+ article_dict: dict = {"article": article}
29
+ ca = cite_article(article_dict, article.id)
30
+ test_ca = {"anchor": "test-article-name", "text": "(see Test Article Title)"}
31
+ assert ca == test_ca
32
+
33
+ def test_cite_article_no_context(self, article_factory):
34
+ article = article_factory()
35
+ no_article_dict = {"blog": "Some Blog"}
36
+ ca = cite_article(no_article_dict, article.id)
37
+ test_ca = {"not_working": "(article citations only work in a rendered pdf.)"}
38
+ assert ca == test_ca
@@ -0,0 +1,18 @@
1
+ import pytest
2
+ from wbcore.test import GenerateTest, default_config
3
+
4
+ config = {}
5
+
6
+ for key, value in default_config.items():
7
+ config[key] = list(
8
+ filter(
9
+ lambda x: x.__module__.startswith("wbwriter"),
10
+ value,
11
+ )
12
+ )
13
+
14
+
15
+ @pytest.mark.django_db
16
+ @GenerateTest(config)
17
+ class TestProject:
18
+ pass
wbwriter/typings.py ADDED
@@ -0,0 +1,23 @@
1
+ from dataclasses import asdict, dataclass
2
+ from datetime import datetime
3
+ from io import BytesIO
4
+ from typing import Any
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class ArticleDTO:
9
+ name: str
10
+ slug: str
11
+ title: str
12
+ teaser_image: BytesIO | None
13
+ created: datetime
14
+ modified: datetime
15
+ content: dict[str, str]
16
+ is_private: bool
17
+ article_structure: dict[str, str]
18
+ status: str
19
+ meta_information: list[dict[str, Any]]
20
+ tags: list[int]
21
+
22
+ def to_dict(self):
23
+ return asdict(self)