Skip to content

Commit 23e8cdb

Browse files
authored
Merge pull request #5009 from taoerman/unstable
Add publish next change event
2 parents 02442bd + 6ea73b3 commit 23e8cdb

File tree

6 files changed

+133
-0
lines changed

6 files changed

+133
-0
lines changed

contentcuration/contentcuration/tests/viewsets/base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from contentcuration.viewsets.sync.utils import generate_publish_event as base_generate_publish_event
1616
from contentcuration.viewsets.sync.utils import generate_update_event as base_generate_update_event
1717
from contentcuration.viewsets.sync.utils import generate_update_descendants_event as base_generate_update_descendants_event
18+
from contentcuration.viewsets.sync.utils import generate_publish_next_event as base_generate_publish_next_event
1819

1920

2021
def generate_copy_event(*args, **kwargs):
@@ -66,6 +67,11 @@ def generate_publish_channel_event(channel_id):
6667
event["rev"] = random.randint(1, 10000000)
6768
return event
6869

70+
def generate_publish_next_event(channel_id):
71+
event = base_generate_publish_next_event(channel_id)
72+
event["rev"] = random.randint(1, 10000000)
73+
return event
74+
6975

7076
class SyncTestMixin(object):
7177
celery_task_always_eager = None

contentcuration/contentcuration/tests/viewsets/test_channel.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,26 @@
1717
from contentcuration.tests.viewsets.base import generate_delete_event
1818
from contentcuration.tests.viewsets.base import generate_deploy_channel_event
1919
from contentcuration.tests.viewsets.base import generate_publish_channel_event
20+
from contentcuration.tests.viewsets.base import generate_publish_next_event
2021
from contentcuration.tests.viewsets.base import generate_sync_channel_event
2122
from contentcuration.tests.viewsets.base import generate_update_event
2223
from contentcuration.tests.viewsets.base import SyncTestMixin
2324
from contentcuration.viewsets.channel import _unpublished_changes_query
2425
from contentcuration.viewsets.sync.constants import CHANNEL
26+
from mock import patch
2527

2628

2729
class SyncTestCase(SyncTestMixin, StudioAPITestCase):
30+
@classmethod
31+
def setUpClass(cls):
32+
super(SyncTestCase, cls).setUpClass()
33+
cls.patch_copy_db = patch('contentcuration.utils.publish.save_export_database')
34+
cls.mock_save_export = cls.patch_copy_db.start()
35+
36+
@classmethod
37+
def tearDownClass(cls):
38+
super(SyncTestCase, cls).tearDownClass()
39+
cls.patch_copy_db.stop()
2840

2941
@property
3042
def channel_metadata(self):
@@ -391,6 +403,61 @@ def test_publish_does_not_make_publishable(self):
391403

392404
self.assertEqual(_unpublished_changes_query(channel).count(), 0)
393405

406+
def test_publish_next(self):
407+
channel = testdata.channel()
408+
user = testdata.user()
409+
channel.editors.add(user)
410+
self.client.force_authenticate(
411+
user
412+
) # This will skip all authentication checks
413+
414+
channel.staging_tree = testdata.tree()
415+
node = testdata.node({
416+
'kind_id': 'video', 'title': 'title', 'children': []})
417+
node.complete = True
418+
node.parent = channel.staging_tree
419+
node.save()
420+
channel.staging_tree.save()
421+
channel.save()
422+
self.assertEqual(channel.staging_tree.published, False)
423+
424+
response = self.sync_changes(
425+
[
426+
generate_publish_next_event(channel.id)
427+
]
428+
)
429+
430+
self.assertEqual(response.status_code, 200)
431+
modified_channel = models.Channel.objects.get(id=channel.id)
432+
self.assertEqual(modified_channel.staging_tree.published, True)
433+
434+
def test_publish_next_with_incomplete_staging_tree(self):
435+
channel = testdata.channel()
436+
user = testdata.user()
437+
channel.editors.add(user)
438+
self.client.force_authenticate(
439+
user
440+
) # This will skip all authentication checks
441+
442+
channel.staging_tree = cc.ContentNode(
443+
kind_id=content_kinds.TOPIC, title="test", node_id="aaa"
444+
)
445+
channel.staging_tree.save()
446+
channel.save()
447+
self.assertEqual(channel.staging_tree.published, False)
448+
449+
response = self.sync_changes(
450+
[
451+
generate_publish_next_event(channel.id)
452+
]
453+
)
454+
455+
self.assertEqual(response.status_code, 200)
456+
self.assertTrue(
457+
"Channel is not ready to be published" in response.json()["errors"][0]["errors"][0])
458+
modified_channel = models.Channel.objects.get(id=channel.id)
459+
self.assertEqual(modified_channel.staging_tree.published, False)
460+
394461

395462
class CRUDTestCase(StudioAPITestCase):
396463
@property

contentcuration/contentcuration/viewsets/channel.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,55 @@ def publish(self, pk, version_notes="", language=None):
560560
], applied=True, unpublishable=True)
561561
raise
562562

563+
def publish_next_from_changes(self, changes):
564+
errors = []
565+
for publish in changes:
566+
try:
567+
self.publish_next(publish["key"])
568+
except Exception as e:
569+
log_sync_exception(e, user=self.request.user, change=publish)
570+
publish["errors"] = [str(e)]
571+
errors.append(publish)
572+
return errors
573+
574+
def publish_next(self, pk):
575+
logging.debug("Entering the publish staging channel endpoint")
576+
577+
channel = self.get_edit_queryset().get(pk=pk)
578+
579+
if channel.deleted:
580+
raise ValidationError("Cannot publish a deleted channel")
581+
elif channel.staging_tree.publishing:
582+
raise ValidationError("Channel staging tree is already publishing")
583+
584+
channel.staging_tree.publishing = True
585+
channel.staging_tree.save()
586+
587+
with create_change_tracker(pk, CHANNEL, channel.id, self.request.user,
588+
"export-channel-staging-tree") as progress_tracker:
589+
try:
590+
channel = publish_channel(
591+
self.request.user.pk,
592+
channel.id,
593+
progress_tracker=progress_tracker,
594+
use_staging_tree=True,
595+
)
596+
Change.create_changes([
597+
generate_update_event(
598+
channel.id, CHANNEL, {
599+
"primary_token": channel.get_human_token().token,
600+
}, channel_id=channel.id
601+
),
602+
], applied=True)
603+
except ChannelIncompleteError:
604+
channel.staging_tree.publishing = False
605+
channel.staging_tree.save()
606+
raise ValidationError("Channel is not ready to be published")
607+
except Exception:
608+
channel.staging_tree.publishing = False
609+
channel.staging_tree.save()
610+
raise
611+
563612
def sync_from_changes(self, changes):
564613
errors = []
565614
for sync in changes:

contentcuration/contentcuration/viewsets/sync/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from contentcuration.viewsets.sync.constants import DELETED
2525
from contentcuration.viewsets.sync.constants import DEPLOYED
2626
from contentcuration.viewsets.sync.constants import UPDATED_DESCENDANTS
27+
from contentcuration.viewsets.sync.constants import PUBLISHED_NEXT
2728
from contentcuration.viewsets.sync.constants import EDITOR_M2M
2829
from contentcuration.viewsets.sync.constants import FILE
2930
from contentcuration.viewsets.sync.constants import INVITATION
@@ -96,6 +97,7 @@ def get_change_type(obj):
9697
SYNCED: "sync_from_changes",
9798
DEPLOYED: "deploy_from_changes",
9899
UPDATED_DESCENDANTS: "update_descendants_from_changes",
100+
PUBLISHED_NEXT: "publish_next_from_changes"
99101
}
100102

101103

contentcuration/contentcuration/viewsets/sync/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
SYNCED = 7
99
DEPLOYED = 8
1010
UPDATED_DESCENDANTS = 9
11+
PUBLISHED_NEXT = 10
1112

1213

1314
ALL_CHANGES = set([
@@ -20,6 +21,7 @@
2021
SYNCED,
2122
DEPLOYED,
2223
UPDATED_DESCENDANTS,
24+
PUBLISHED_NEXT,
2325
])
2426

2527
# Client-side table constants

contentcuration/contentcuration/viewsets/sync/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from contentcuration.viewsets.sync.constants import PUBLISHED
1515
from contentcuration.viewsets.sync.constants import UPDATED
1616
from contentcuration.viewsets.sync.constants import UPDATED_DESCENDANTS
17+
from contentcuration.viewsets.sync.constants import PUBLISHED_NEXT
1718

1819

1920
def validate_table(table):
@@ -88,6 +89,12 @@ def generate_update_descendants_event(key, mods, channel_id=None, user_id=None):
8889
event["mods"] = mods
8990
return event
9091

92+
def generate_publish_next_event(key, version_notes="", language=None):
93+
event = _generate_event(key, CHANNEL, PUBLISHED_NEXT, key, None)
94+
event["version_notes"] = version_notes
95+
event["language"] = language
96+
return event
97+
9198
def log_sync_exception(e, user=None, change=None, changes=None):
9299
# Capture exception and report, but allow sync
93100
# to complete properly.

0 commit comments

Comments
 (0)