Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions contentcuration/contentcuration/tests/viewsets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from contentcuration.viewsets.sync.utils import generate_publish_event as base_generate_publish_event
from contentcuration.viewsets.sync.utils import generate_update_event as base_generate_update_event
from contentcuration.viewsets.sync.utils import generate_update_descendants_event as base_generate_update_descendants_event
from contentcuration.viewsets.sync.utils import generate_publish_next_event as base_generate_publish_next_event


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

def generate_publish_next_event(channel_id):
event = base_generate_publish_next_event(channel_id)
event["rev"] = random.randint(1, 10000000)
return event


class SyncTestMixin(object):
celery_task_always_eager = None
Expand Down
67 changes: 67 additions & 0 deletions contentcuration/contentcuration/tests/viewsets/test_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,26 @@
from contentcuration.tests.viewsets.base import generate_delete_event
from contentcuration.tests.viewsets.base import generate_deploy_channel_event
from contentcuration.tests.viewsets.base import generate_publish_channel_event
from contentcuration.tests.viewsets.base import generate_publish_next_event
from contentcuration.tests.viewsets.base import generate_sync_channel_event
from contentcuration.tests.viewsets.base import generate_update_event
from contentcuration.tests.viewsets.base import SyncTestMixin
from contentcuration.viewsets.channel import _unpublished_changes_query
from contentcuration.viewsets.sync.constants import CHANNEL
from mock import patch


class SyncTestCase(SyncTestMixin, StudioAPITestCase):
@classmethod
def setUpClass(cls):
super(SyncTestCase, cls).setUpClass()
cls.patch_copy_db = patch('contentcuration.utils.publish.save_export_database')
cls.mock_save_export = cls.patch_copy_db.start()

@classmethod
def tearDownClass(cls):
super(SyncTestCase, cls).tearDownClass()
cls.patch_copy_db.stop()

@property
def channel_metadata(self):
Expand Down Expand Up @@ -391,6 +403,61 @@ def test_publish_does_not_make_publishable(self):

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

def test_publish_next(self):
channel = testdata.channel()
user = testdata.user()
channel.editors.add(user)
self.client.force_authenticate(
user
) # This will skip all authentication checks

channel.staging_tree = testdata.tree()
node = testdata.node({
'kind_id': 'video', 'title': 'title', 'children': []})
node.complete = True
node.parent = channel.staging_tree
node.save()
channel.staging_tree.save()
channel.save()
self.assertEqual(channel.staging_tree.published, False)

response = self.sync_changes(
[
generate_publish_next_event(channel.id)
]
)

self.assertEqual(response.status_code, 200)
modified_channel = models.Channel.objects.get(id=channel.id)
self.assertEqual(modified_channel.staging_tree.published, True)

def test_publish_next_with_incomplete_staging_tree(self):
channel = testdata.channel()
user = testdata.user()
channel.editors.add(user)
self.client.force_authenticate(
user
) # This will skip all authentication checks

channel.staging_tree = cc.ContentNode(
kind_id=content_kinds.TOPIC, title="test", node_id="aaa"
)
channel.staging_tree.save()
channel.save()
self.assertEqual(channel.staging_tree.published, False)

response = self.sync_changes(
[
generate_publish_next_event(channel.id)
]
)

self.assertEqual(response.status_code, 200)
self.assertTrue(
"Channel is not ready to be published" in response.json()["errors"][0]["errors"][0])
modified_channel = models.Channel.objects.get(id=channel.id)
self.assertEqual(modified_channel.staging_tree.published, False)


class CRUDTestCase(StudioAPITestCase):
@property
Expand Down
49 changes: 49 additions & 0 deletions contentcuration/contentcuration/viewsets/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,55 @@ def publish(self, pk, version_notes="", language=None):
], applied=True, unpublishable=True)
raise

def publish_next_from_changes(self, changes):
errors = []
for publish in changes:
try:
self.publish_next(publish["key"])
except Exception as e:
log_sync_exception(e, user=self.request.user, change=publish)
publish["errors"] = [str(e)]
errors.append(publish)
return errors

def publish_next(self, pk):
logging.debug("Entering the publish staging channel endpoint")

channel = self.get_edit_queryset().get(pk=pk)

if channel.deleted:
raise ValidationError("Cannot publish a deleted channel")
elif channel.staging_tree.publishing:
raise ValidationError("Channel staging tree is already publishing")

channel.staging_tree.publishing = True
channel.staging_tree.save()

with create_change_tracker(pk, CHANNEL, channel.id, self.request.user,
"export-channel-staging-tree") as progress_tracker:
try:
channel = publish_channel(
self.request.user.pk,
channel.id,
progress_tracker=progress_tracker,
use_staging_tree=True,
)
Change.create_changes([
generate_update_event(
channel.id, CHANNEL, {
"primary_token": channel.get_human_token().token,
}, channel_id=channel.id
),
], applied=True)
except ChannelIncompleteError:
channel.staging_tree.publishing = False
channel.staging_tree.save()
raise ValidationError("Channel is not ready to be published")
except Exception:
channel.staging_tree.publishing = False
channel.staging_tree.save()
raise

def sync_from_changes(self, changes):
errors = []
for sync in changes:
Expand Down
2 changes: 2 additions & 0 deletions contentcuration/contentcuration/viewsets/sync/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from contentcuration.viewsets.sync.constants import DELETED
from contentcuration.viewsets.sync.constants import DEPLOYED
from contentcuration.viewsets.sync.constants import UPDATED_DESCENDANTS
from contentcuration.viewsets.sync.constants import PUBLISHED_NEXT
from contentcuration.viewsets.sync.constants import EDITOR_M2M
from contentcuration.viewsets.sync.constants import FILE
from contentcuration.viewsets.sync.constants import INVITATION
Expand Down Expand Up @@ -96,6 +97,7 @@ def get_change_type(obj):
SYNCED: "sync_from_changes",
DEPLOYED: "deploy_from_changes",
UPDATED_DESCENDANTS: "update_descendants_from_changes",
PUBLISHED_NEXT: "publish_next_from_changes"
}


Expand Down
2 changes: 2 additions & 0 deletions contentcuration/contentcuration/viewsets/sync/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
SYNCED = 7
DEPLOYED = 8
UPDATED_DESCENDANTS = 9
PUBLISHED_NEXT = 10


ALL_CHANGES = set([
Expand All @@ -20,6 +21,7 @@
SYNCED,
DEPLOYED,
UPDATED_DESCENDANTS,
PUBLISHED_NEXT,
])

# Client-side table constants
Expand Down
7 changes: 7 additions & 0 deletions contentcuration/contentcuration/viewsets/sync/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from contentcuration.viewsets.sync.constants import PUBLISHED
from contentcuration.viewsets.sync.constants import UPDATED
from contentcuration.viewsets.sync.constants import UPDATED_DESCENDANTS
from contentcuration.viewsets.sync.constants import PUBLISHED_NEXT


def validate_table(table):
Expand Down Expand Up @@ -88,6 +89,12 @@ def generate_update_descendants_event(key, mods, channel_id=None, user_id=None):
event["mods"] = mods
return event

def generate_publish_next_event(key, version_notes="", language=None):
event = _generate_event(key, CHANNEL, PUBLISHED_NEXT, key, None)
event["version_notes"] = version_notes
event["language"] = language
return event

def log_sync_exception(e, user=None, change=None, changes=None):
# Capture exception and report, but allow sync
# to complete properly.
Expand Down