Skip to content

Commit 399bba1

Browse files
authored
Merge pull request #5228 from Jakoma02/added-to-community-library-change
Add to community library on submission approve
2 parents 4863c93 + c2dec46 commit 399bba1

18 files changed

Lines changed: 812 additions & 70 deletions

contentcuration/contentcuration/models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,6 +2605,21 @@ def save(self, *args, **kwargs):
26052605

26062606
super().save(*args, **kwargs)
26072607

2608+
def mark_live(self):
2609+
"""
2610+
Marks this submission as the live submission for the channel,
2611+
and marks any previously live submissions as approved but not live.
2612+
"""
2613+
CommunityLibrarySubmission.objects.filter(
2614+
channel=self.channel,
2615+
status=community_library_submission.STATUS_LIVE,
2616+
).update(
2617+
status=community_library_submission.STATUS_APPROVED,
2618+
)
2619+
2620+
self.status = community_library_submission.STATUS_LIVE
2621+
self.save()
2622+
26082623
@classmethod
26092624
def filter_view_queryset(cls, queryset, user):
26102625
if user.is_anonymous:

contentcuration/contentcuration/tests/test_models.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,42 @@ def test_filter_edit_queryset__admin(self):
689689
)
690690
self.assertQuerysetContains(queryset, pk=submission_a.id)
691691

692+
def test_mark_live(self):
693+
submission_a = testdata.community_library_submission()
694+
submission_b = testdata.community_library_submission()
695+
696+
channel = submission_a.channel
697+
channel.version = 2
698+
submission_b.channel = channel
699+
700+
submission_a.channel_version = 1
701+
submission_a.status = community_library_submission.STATUS_LIVE
702+
submission_a.save()
703+
704+
submission_b.channel_version = 2
705+
submission_b.author = submission_a.author
706+
submission_b.status = community_library_submission.STATUS_APPROVED
707+
submission_b.save()
708+
709+
submission_other_channel = testdata.community_library_submission()
710+
submission_other_channel.status = community_library_submission.STATUS_LIVE
711+
submission_other_channel.save()
712+
713+
submission_b.mark_live()
714+
715+
submission_a.refresh_from_db()
716+
submission_b.refresh_from_db()
717+
submission_other_channel.refresh_from_db()
718+
719+
self.assertEqual(
720+
submission_a.status, community_library_submission.STATUS_APPROVED
721+
)
722+
self.assertEqual(submission_b.status, community_library_submission.STATUS_LIVE)
723+
self.assertEqual(
724+
submission_other_channel.status,
725+
community_library_submission.STATUS_LIVE,
726+
)
727+
692728

693729
class AssessmentItemTestCase(PermissionQuerysetTestCase):
694730
@property

contentcuration/contentcuration/tests/viewsets/test_channel.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@
1111
from contentcuration import models
1212
from contentcuration import models as cc
1313
from contentcuration.constants import channel_history
14+
from contentcuration.constants import community_library_submission
15+
from contentcuration.models import Change
16+
from contentcuration.models import CommunityLibrarySubmission
1417
from contentcuration.models import ContentNode
18+
from contentcuration.models import Country
19+
from contentcuration.tasks import apply_channel_changes_task
1520
from contentcuration.tests import testdata
1621
from contentcuration.tests.base import StudioAPITestCase
1722
from contentcuration.tests.viewsets.base import generate_create_event
@@ -24,6 +29,9 @@
2429
from contentcuration.tests.viewsets.base import SyncTestMixin
2530
from contentcuration.viewsets.channel import _unpublished_changes_query
2631
from contentcuration.viewsets.sync.constants import CHANNEL
32+
from contentcuration.viewsets.sync.utils import (
33+
generate_added_to_community_library_event,
34+
)
2735

2836

2937
class SyncTestCase(SyncTestMixin, StudioAPITestCase):
@@ -517,6 +525,115 @@ def test_publish_next_with_incomplete_staging_tree(self):
517525
modified_channel = models.Channel.objects.get(id=channel.id)
518526
self.assertEqual(modified_channel.staging_tree.published, False)
519527

528+
def test_sync_added_to_community_library_change(self):
529+
# Syncing the change from the frontend should be disallowed
530+
self.client.force_authenticate(self.admin_user)
531+
532+
channel = testdata.channel()
533+
channel.version = 1
534+
channel.public = True
535+
channel.save()
536+
537+
added_to_community_library_change = generate_added_to_community_library_event(
538+
key=channel.id,
539+
channel_version=1,
540+
)
541+
response = self.sync_changes([added_to_community_library_change])
542+
543+
self.assertEqual(response.status_code, 200, response.content)
544+
self.assertEqual(len(response.json()["allowed"]), 0, response.content)
545+
self.assertEqual(len(response.json()["disallowed"]), 1, response.content)
546+
547+
@mock.patch("contentcuration.viewsets.channel.export_channel_to_kolibri_public")
548+
def test_process_added_to_community_library_change(self, mock_export_func):
549+
# Creating the change on the backend should be supported
550+
self.client.force_authenticate(self.admin_user)
551+
552+
editor_user = testdata.user("channel@editor.com")
553+
554+
channel = testdata.channel()
555+
channel.version = 2
556+
channel.public = False
557+
channel.editors.add(editor_user)
558+
channel.save()
559+
560+
current_live_submission = CommunityLibrarySubmission.objects.create(
561+
channel=channel,
562+
channel_version=1,
563+
author=editor_user,
564+
status=community_library_submission.STATUS_LIVE,
565+
)
566+
new_submission = CommunityLibrarySubmission.objects.create(
567+
channel=channel,
568+
channel_version=2,
569+
author=editor_user,
570+
status=community_library_submission.STATUS_APPROVED,
571+
)
572+
573+
categories = {
574+
"category1": True,
575+
"category2": True,
576+
}
577+
578+
country1 = Country.objects.create(code="C1", name="Country 1")
579+
country2 = Country.objects.create(code="C2", name="Country 2")
580+
countries = [country1, country2]
581+
country_codes = [country.code for country in countries]
582+
583+
added_to_community_library_change = generate_added_to_community_library_event(
584+
key=channel.id,
585+
channel_version=2,
586+
categories=categories,
587+
country_codes=country_codes,
588+
)
589+
Change.create_change(
590+
added_to_community_library_change, created_by_id=self.admin_user.id
591+
)
592+
593+
# This task will run immediately thanks to SyncTestMixin
594+
apply_channel_changes_task.fetch_or_enqueue(
595+
user=self.admin_user,
596+
channel_id=channel.id,
597+
)
598+
599+
# We cannot easily use the assert_called_once_with method here
600+
# because we are not checking countries for strict equality,
601+
# so we need to check the call arguments manually
602+
mock_export_func.assert_called_once()
603+
604+
(call_args, call_kwargs) = mock_export_func.call_args
605+
self.assertEqual(len(call_args), 0)
606+
self.assertCountEqual(
607+
call_kwargs.keys(),
608+
[
609+
"channel_id",
610+
"channel_version",
611+
"categories",
612+
"countries",
613+
"public",
614+
],
615+
)
616+
self.assertEqual(call_kwargs["channel_id"], channel.id)
617+
self.assertEqual(call_kwargs["channel_version"], 2)
618+
self.assertCountEqual(call_kwargs["categories"], categories.keys())
619+
620+
# The countries argument used when creating the mapper is in fact
621+
# not a list, but a QuerySet, but it contains the same elements
622+
self.assertCountEqual(call_kwargs["countries"], countries)
623+
self.assertEqual(call_kwargs["public"], False)
624+
625+
# Check that the current submission became the live one
626+
current_live_submission.refresh_from_db()
627+
new_submission.refresh_from_db()
628+
self.assertEqual(
629+
current_live_submission.status,
630+
community_library_submission.STATUS_APPROVED,
631+
)
632+
self.assertEqual(
633+
new_submission.status,
634+
community_library_submission.STATUS_LIVE,
635+
)
636+
520637

521638
class CRUDTestCase(StudioAPITestCase):
522639
@property

contentcuration/contentcuration/tests/viewsets/test_community_library_submission.py

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
from contentcuration.constants import (
99
community_library_submission as community_library_submission_constants,
1010
)
11+
from contentcuration.models import Change
1112
from contentcuration.models import CommunityLibrarySubmission
1213
from contentcuration.tests import testdata
1314
from contentcuration.tests.base import StudioAPITestCase
15+
from contentcuration.viewsets.sync.constants import ADDED_TO_COMMUNITY_LIBRARY
1416

1517

1618
def reverse_with_query(
@@ -59,21 +61,21 @@ def setUp(self):
5961
self.country2 = testdata.country(name="Country 2", code="C2")
6062

6163
self.channel_with_submission1 = testdata.channel()
62-
self.channel_with_submission1.public = True
64+
self.channel_with_submission1.public = False
6365
self.channel_with_submission1.version = 1
6466
self.channel_with_submission1.editors.add(self.author_user)
6567
self.channel_with_submission1.editors.add(self.editor_user)
6668
self.channel_with_submission1.save()
6769

6870
self.channel_with_submission2 = testdata.channel()
69-
self.channel_with_submission2.public = True
71+
self.channel_with_submission2.public = False
7072
self.channel_with_submission2.version = 1
7173
self.channel_with_submission2.editors.add(self.author_user)
7274
self.channel_with_submission2.editors.add(self.editor_user)
7375
self.channel_with_submission2.save()
7476

7577
self.channel_without_submission = testdata.channel()
76-
self.channel_without_submission.public = True
78+
self.channel_without_submission.public = False
7779
self.channel_without_submission.version = 1
7880
self.channel_without_submission.editors.add(self.author_user)
7981
self.channel_without_submission.editors.add(self.editor_user)
@@ -86,6 +88,13 @@ def setUp(self):
8688
self.unpublished_channel.editors.add(self.editor_user)
8789
self.unpublished_channel.save()
8890

91+
self.public_channel = testdata.channel()
92+
self.public_channel.public = True
93+
self.public_channel.version = 1
94+
self.public_channel.editors.add(self.author_user)
95+
self.public_channel.editors.add(self.editor_user)
96+
self.public_channel.save()
97+
8998
self.existing_submission1 = testdata.community_library_submission()
9099
self.existing_submission1.channel = self.channel_with_submission1
91100
self.existing_submission1.author = self.author_user
@@ -132,6 +141,18 @@ def test_create_submission__unpublished_channel(self):
132141
)
133142
self.assertEqual(response.status_code, 400, response.content)
134143

144+
def test_create_submission__public_channel(self):
145+
self.client.force_authenticate(user=self.editor_user)
146+
submission = self.new_submission_metadata
147+
submission["channel"] = self.public_channel.id
148+
149+
response = self.client.post(
150+
reverse("community-library-submission-list"),
151+
submission,
152+
format="json",
153+
)
154+
self.assertEqual(response.status_code, 400, response.content)
155+
135156
def test_create_submission__explicit_channel_version(self):
136157
self.client.force_authenticate(user=self.editor_user)
137158
submission_metadata = self.new_submission_metadata
@@ -317,7 +338,7 @@ def test_update_submission__is_editor(self):
317338
)
318339
self.assertEqual(response.status_code, 404, response.content)
319340

320-
def test_update_submission__is_admin(self):
341+
def test_update_submission__is_admin__change_countries(self):
321342
self.client.force_authenticate(user=self.admin_user)
322343
response = self.client.put(
323344
reverse(
@@ -335,6 +356,28 @@ def test_update_submission__is_admin(self):
335356
self.assertEqual(updated_submission.countries.count(), 1)
336357
self.assertEqual(updated_submission.countries.first().code, "C2")
337358

359+
def test_update_submission__is_admin__keep_countries(self):
360+
self.client.force_authenticate(user=self.admin_user)
361+
362+
updated_submission_metadata = self.updated_submission_metadata.copy()
363+
updated_submission_metadata.pop("countries")
364+
365+
response = self.client.put(
366+
reverse(
367+
"community-library-submission-detail",
368+
args=[self.existing_submission1.id],
369+
),
370+
updated_submission_metadata,
371+
format="json",
372+
)
373+
self.assertEqual(response.status_code, 200, response.content)
374+
375+
updated_submission = CommunityLibrarySubmission.objects.get(
376+
id=self.existing_submission1.id
377+
)
378+
self.assertEqual(updated_submission.countries.count(), 1)
379+
self.assertEqual(updated_submission.countries.first().code, "C1")
380+
338381
def test_update_submission__change_channel(self):
339382
self.client.force_authenticate(user=self.admin_user)
340383
submission_metadata = self.updated_submission_metadata
@@ -628,7 +671,10 @@ def test_resolve_submission__editor(self):
628671
)
629672
self.assertEqual(response.status_code, 403, response.content)
630673

631-
def test_resolve_submission__accept_correct(self):
674+
@mock.patch(
675+
"contentcuration.viewsets.community_library_submission.apply_channel_changes_task"
676+
)
677+
def test_resolve_submission__accept_correct(self, apply_task_mock):
632678
self.client.force_authenticate(user=self.admin_user)
633679
response = self.client.post(
634680
reverse(
@@ -652,7 +698,21 @@ def test_resolve_submission__accept_correct(self):
652698
self.assertEqual(resolved_submission.resolved_by, self.admin_user)
653699
self.assertEqual(resolved_submission.date_resolved, self.resolved_time)
654700

655-
def test_resolve_submission__reject_correct(self):
701+
self.assertTrue(
702+
Change.objects.filter(
703+
channel=self.submission.channel,
704+
change_type=ADDED_TO_COMMUNITY_LIBRARY,
705+
).exists()
706+
)
707+
apply_task_mock.fetch_or_enqueue.assert_called_once_with(
708+
self.admin_user,
709+
channel_id=self.submission.channel.id,
710+
)
711+
712+
@mock.patch(
713+
"contentcuration.viewsets.community_library_submission.apply_channel_changes_task"
714+
)
715+
def test_resolve_submission__reject_correct(self, apply_task_mock):
656716
self.client.force_authenticate(user=self.admin_user)
657717
response = self.client.post(
658718
reverse(
@@ -680,6 +740,14 @@ def test_resolve_submission__reject_correct(self):
680740
self.assertEqual(resolved_submission.resolved_by, self.admin_user)
681741
self.assertEqual(resolved_submission.date_resolved, self.resolved_time)
682742

743+
self.assertFalse(
744+
Change.objects.filter(
745+
channel=self.submission.channel,
746+
change_type=ADDED_TO_COMMUNITY_LIBRARY,
747+
).exists()
748+
)
749+
apply_task_mock.fetch_or_enqueue.assert_not_called()
750+
683751
def test_resolve_submission__reject_missing_resolution_reason(self):
684752
self.client.force_authenticate(user=self.admin_user)
685753
metadata = self.resolve_reject_metadata.copy()

0 commit comments

Comments
 (0)