Пример #1
0
def export_channel_task(self,
                        user_id,
                        channel_id,
                        version_notes="",
                        language=settings.LANGUAGE_CODE):
    with translation.override(language):
        channel = publish_channel(
            user_id,
            channel_id,
            version_notes=version_notes,
            send_email=True,
            progress_tracker=self.progress,
        )
    return {
        "changes": [
            generate_update_event(
                channel_id, CHANNEL, {
                    "published": True,
                    "primary_token": channel.get_human_token().token
                }),
            generate_update_event(channel.main_tree.pk, CONTENTNODE, {
                "published": True,
                "changed": False
            }),
        ]
    }
Пример #2
0
    def test_update_files(self):

        file1 = models.File.objects.create(**self.file_db_metadata)
        file2 = models.File.objects.create(**self.file_db_metadata)
        new_preset = format_presets.VIDEO_HIGH_RES

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    file1.id,
                    FILE,
                    {"preset": new_preset},
                ),
                generate_update_event(
                    file2.id,
                    FILE,
                    {"preset": new_preset},
                ),
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(
            models.File.objects.get(id=file1.id).preset_id,
            new_preset,
        )
        self.assertEqual(
            models.File.objects.get(id=file2.id).preset_id,
            new_preset,
        )
Пример #3
0
    def test_viewer_cannot_update_some_channels(self):
        user = testdata.user()
        channel1 = models.Channel.objects.create(**self.channel_metadata)
        channel1.editors.add(user)
        channel2 = models.Channel.objects.create(**self.channel_metadata)
        channel2.viewers.add(user)
        new_name = "This is not the old name"

        self.client.force_authenticate(user=user)
        with self.settings(TEST_ENV=False):
            # Override test env here to check what will happen in production
            response = self.client.post(
                self.sync_url,
                [
                    generate_update_event(channel1.id, CHANNEL,
                                          {"name": new_name}),
                    generate_update_event(channel2.id, CHANNEL,
                                          {"name": new_name}),
                ],
                format="json",
            )
        self.assertEqual(response.status_code, 207, response.content)
        self.assertEqual(
            models.Channel.objects.get(id=channel1.id).name, new_name)
        self.assertNotEqual(
            models.Channel.objects.get(id=channel2.id).name, new_name)
Пример #4
0
    def test_update_channelsets(self):

        channelset1 = models.ChannelSet.objects.create(
            **self.channelset_db_metadata)
        channelset1.editors.add(self.user)
        channelset2 = models.ChannelSet.objects.create(
            **self.channelset_db_metadata)
        channelset2.editors.add(self.user)

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    channelset1.id,
                    CHANNELSET,
                    {"channels": {}},
                ),
                generate_update_event(
                    channelset2.id,
                    CHANNELSET,
                    {"channels": {}},
                ),
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertFalse(
            models.ChannelSet.objects.get(
                id=channelset1.id).secret_token.channels.filter(
                    pk=self.channel.id).exists())
        self.assertFalse(
            models.ChannelSet.objects.get(
                id=channelset2.id).secret_token.channels.filter(
                    pk=self.channel.id).exists())
Пример #5
0
    def test_update_clipboard_extra_fields(self):
        clipboard = models.ContentNode.objects.create(
            **self.clipboard_db_metadata)
        node_id1 = uuid.uuid4().hex

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    clipboard.id,
                    CLIPBOARD,
                    {
                        "extra_fields.excluded_descendants.{}".format(node_id1):
                        True
                    },
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertTrue(
            models.ContentNode.objects.get(id=clipboard.id).
            extra_fields["excluded_descendants"][node_id1])

        node_id2 = uuid.uuid4().hex

        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    clipboard.id,
                    CLIPBOARD,
                    {
                        "extra_fields.excluded_descendants.{}".format(node_id2):
                        True
                    },
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertTrue(
            models.ContentNode.objects.get(id=clipboard.id).
            extra_fields["excluded_descendants"][node_id1])
        self.assertTrue(
            models.ContentNode.objects.get(id=clipboard.id).
            extra_fields["excluded_descendants"][node_id2])
Пример #6
0
    def test_update_assessmentitem_remove_file(self):

        assessmentitem = models.AssessmentItem.objects.create(
            **self.assessmentitem_db_metadata
        )
        image_file = testdata.fileobj_exercise_image()
        image_file.assessment_item = assessmentitem
        image_file.save()
        question = "A different question"

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    [assessmentitem.contentnode_id, assessmentitem.assessment_id],
                    ASSESSMENTITEM,
                    {"question": question},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        try:
            assessmentitem.files.get()
            self.fail("File was not removed")
        except models.File.DoesNotExist:
            pass
Пример #7
0
    def test_update_assessmentitem_with_file_no_permissions(self):

        assessmentitem = models.AssessmentItem.objects.create(
            **self.assessmentitem_db_metadata
        )
        image_file = testdata.fileobj_exercise_image()
        question = "![alt_text](${}/{}.{})".format(
            exercises.IMG_PLACEHOLDER, image_file.checksum, image_file.file_format_id
        )

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    [assessmentitem.contentnode_id, assessmentitem.assessment_id],
                    ASSESSMENTITEM,
                    {"question": question},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 400, response.content)
        try:
            file = assessmentitem.files.get()
            self.assertNotEqual(file.id, image_file.id)
            self.fail("File was updated")
        except models.File.DoesNotExist:
            pass
Пример #8
0
def activate_channel(channel, user):
    user.check_channel_space(channel)

    if channel.previous_tree and channel.previous_tree != channel.main_tree:
        # IMPORTANT: Do not remove this block, MPTT updating the deleted chefs block could hang the server
        with models.ContentNode.objects.disable_mptt_updates():
            garbage_node = get_deleted_chefs_root()
            channel.previous_tree.parent = garbage_node
            channel.previous_tree.title = "Previous tree for channel {}".format(
                channel.pk)
            channel.previous_tree.save()

    channel.previous_tree = channel.main_tree
    channel.main_tree = channel.staging_tree
    channel.staging_tree = None
    channel.save()

    user.staged_files.all().delete()
    user.set_space_used()

    change = generate_update_event(
        channel.id,
        CHANNEL,
        {
            "root_id": channel.main_tree.id,
            "staging_root_id": None
        },
    )
    return change
Пример #9
0
    def test_update_channelset_channels_no_permission(self):
        channelset = models.ChannelSet.objects.create(
            **self.channelset_db_metadata)
        channelset.editors.add(self.user)

        channel1 = testdata.channel()

        channel1.save()

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    channelset.id,
                    CHANNELSET,
                    {"channels.{}".format(channel1.id): True},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 400, response.content)
        self.assertFalse(
            models.ChannelSet.objects.get(
                id=channelset.id).secret_token.channels.filter(
                    id=channel1.id).exists())
Пример #10
0
def move_nodes_task(
    self,
    user_id,
    channel_id,
    target_id,
    node_id,
    position="last-child",
):
    node = ContentNode.objects.get(id=node_id)
    target = ContentNode.objects.get(id=target_id)

    moved = False
    attempts = 0
    try:
        while not moved and attempts < 10:
            try:
                node.move_to(
                    target,
                    position,
                )
                moved = True
            except OperationalError as e:
                if "deadlock detected" in e.args[0]:
                    pass
                else:
                    raise
    except Exception as e:
        report_exception(e)

    return {"changes": [generate_update_event(node.pk, CONTENTNODE, {"parent": node.parent_id})]}
Пример #11
0
 def create(self, validated_data):
     bookmark = validated_data.pop("bookmark", None)
     content_defaults = validated_data.pop("content_defaults", {})
     validated_data["content_defaults"] = self.fields["content_defaults"].create(
         content_defaults
     )
     instance = super(ChannelSerializer, self).create(validated_data)
     if "request" in self.context:
         user = self.context["request"].user
         # This has been newly created so add the current user as an editor
         instance.editors.add(user)
         if bookmark:
             user.bookmarked_channels.add(instance)
     self.changes.append(
         generate_update_event(
             instance.id,
             CHANNEL,
             {
                 "root_id": instance.main_tree.id,
                 "created": instance.main_tree.created,
                 "published": instance.main_tree.published,
                 "content_defaults": instance.content_defaults,
             },
         )
     )
     return instance
Пример #12
0
    def test_update_invitation_accept(self):

        invitation = models.Invitation.objects.create(
            **self.invitation_db_metadata)

        self.client.force_authenticate(user=self.invited_user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    invitation.id,
                    INVITATION,
                    {"accepted": True},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        try:
            models.Invitation.objects.get(id=invitation.id)
        except models.Invitation.DoesNotExist:
            self.fail("Invitation was deleted")
        self.assertTrue(
            self.channel.editors.filter(pk=self.invited_user.id).exists())
        self.assertTrue(
            models.Invitation.objects.filter(email=self.invited_user.email,
                                             channel=self.channel).exists())
Пример #13
0
    def test_duplicate_nodes_task(self):
        ids = []
        node_ids = []
        for i in range(3, 6):
            node_id = "0000000000000000000000000000000" + str(i)
            node_ids.append(node_id)
            node = ContentNode.objects.get(node_id=node_id)
            ids.append(node.pk)

        parent_node = ContentNode.objects.get(
            node_id="00000000000000000000000000000002")

        tasks = []

        for source_id in ids:

            task_args = {
                "user_id": self.user.pk,
                "channel_id": self.channel.pk,
                "source_id": source_id,
                "target_id": parent_node.pk,
                "pk": uuid.uuid4().hex,
            }
            task, task_info = create_async_task("duplicate-nodes",
                                                self.user,
                                                apply_async=False,
                                                **task_args)
            tasks.append((task_args, task_info))

        for task_args, task_info in tasks:
            # progress is retrieved dynamically upon calls to get the task info, so
            # use an API call rather than checking the db directly for progress.
            url = reverse("task-detail", kwargs={"task_id": task_info.task_id})
            response = self.get(url)
            assert (response.data["status"] == states.SUCCESS
                    ), "Task failed, exception: {}".format(
                        response.data["metadata"]["error"]["traceback"])
            self.assertEqual(response.data["status"], states.SUCCESS)
            self.assertEqual(response.data["task_type"], "duplicate-nodes")
            result = response.data["metadata"]["result"]
            node_id = ContentNode.objects.get(pk=task_args["pk"]).node_id
            self.assertEqual(
                result["changes"][0],
                generate_update_event(task_args["pk"], CONTENTNODE, {
                    COPYING_FLAG: False,
                    "node_id": node_id
                }),
            )

        parent_node.refresh_from_db()
        children = parent_node.get_children()

        for child in children:
            # make sure the copies are in the results
            if child.original_source_node_id and child.source_node_id:
                assert child.original_source_node_id in node_ids
                assert child.source_node_id in node_ids
Пример #14
0
    def test_update_channels(self):
        user = testdata.user()
        channel1 = models.Channel.objects.create(**self.channel_metadata)
        channel1.editors.add(user)
        channel2 = models.Channel.objects.create(**self.channel_metadata)
        channel2.editors.add(user)
        new_name = "This is not the old name"

        self.client.force_authenticate(user=user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(channel1.id, CHANNEL, {"name": new_name}),
                generate_update_event(channel2.id, CHANNEL, {"name": new_name}),
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(models.Channel.objects.get(id=channel1.id).name, new_name)
        self.assertEqual(models.Channel.objects.get(id=channel2.id).name, new_name)
Пример #15
0
    def test_update_channel_defaults(self):
        user = testdata.user()
        channel = models.Channel.objects.create(**self.channel_metadata)
        channel.editors.add(user)
        author = "This is not the old author"

        self.client.force_authenticate(user=user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(channel.id, CHANNEL,
                                      {"content_defaults.author": author})
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(
            models.Channel.objects.get(
                id=channel.id).content_defaults["author"], author)

        aggregator = "This is not the old aggregator"

        self.client.force_authenticate(user=user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    channel.id, CHANNEL,
                    {"content_defaults.aggregator": aggregator})
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(
            models.Channel.objects.get(
                id=channel.id).content_defaults["author"], author)
        self.assertEqual(
            models.Channel.objects.get(
                id=channel.id).content_defaults["aggregator"],
            aggregator,
        )
Пример #16
0
    def test_update_file_empty(self):

        file = models.File.objects.create(**self.file_db_metadata)
        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [generate_update_event(
                file.id,
                FILE,
                {},
            )],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
Пример #17
0
    def test_update_invitation_empty(self):

        invitation = models.Invitation.objects.create(
            **self.invitation_db_metadata)
        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [generate_update_event(
                invitation.id,
                INVITATION,
                {},
            )],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
Пример #18
0
    def test_update_assessmentitems(self):

        assessmentitem1 = models.AssessmentItem.objects.create(
            **self.assessmentitem_db_metadata
        )
        assessmentitem2 = models.AssessmentItem.objects.create(
            **self.assessmentitem_db_metadata
        )
        new_question = "{}"

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    [assessmentitem1.contentnode_id, assessmentitem1.assessment_id],
                    ASSESSMENTITEM,
                    {"question": new_question},
                ),
                generate_update_event(
                    [assessmentitem2.contentnode_id, assessmentitem2.assessment_id],
                    ASSESSMENTITEM,
                    {"question": new_question},
                ),
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(
            models.AssessmentItem.objects.get(id=assessmentitem1.id).question,
            new_question,
        )
        self.assertEqual(
            models.AssessmentItem.objects.get(id=assessmentitem2.id).question,
            new_question,
        )
Пример #19
0
    def test_viewer_can_bookmark_channel(self):
        user = testdata.user()
        channel = models.Channel.objects.create(**self.channel_metadata)
        channel.viewers.add(user)

        self.client.force_authenticate(user=user)
        with self.settings(TEST_ENV=False):
            # Override test env here to check what will happen in production
            response = self.client.post(
                self.sync_url,
                [generate_update_event(channel.id, CHANNEL, {"bookmark": True})],
                format="json",
            )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertTrue(user.bookmarked_channels.filter(id=channel.id).exists())
Пример #20
0
    def test_update_channelset_empty(self):

        channelset = models.ChannelSet.objects.create(
            **self.channelset_db_metadata)
        channelset.editors.add(self.user)
        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [generate_update_event(
                channelset.id,
                CHANNELSET,
                {},
            )],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
Пример #21
0
 def create(self, validated_data):
     channels = validated_data.pop("channels", [])
     instance = super(ChannelSetSerializer, self).create(validated_data)
     for channel in channels:
         instance.secret_token.channels.add(channel)
     if "request" in self.context:
         user = self.context["request"].user
         # This has been newly created so add the current user as an editor
         instance.editors.add(user)
     self.changes.append(
         generate_update_event(
             instance.id,
             CHANNELSET,
             {"secret_token": instance.secret_token.token},
         ))
     return instance
Пример #22
0
    def copy(self,
             pk,
             from_key=None,
             target=None,
             position=None,
             mods=None,
             excluded_descendants=None,
             **kwargs):
        try:
            target, position = self.validate_targeting_args(target, position)
        except ValidationError as e:
            return str(e), None

        try:
            source = self.get_queryset().get(pk=from_key)
        except ContentNode.DoesNotExist:
            error = ValidationError("Copy source node does not exist")
            return str(error), [generate_delete_event(pk, CONTENTNODE)]

        # Affected channel for the copy is the target's channel
        channel_id = target.channel_id

        if ContentNode.objects.filter(pk=pk).exists():
            error = ValidationError("Copy pk already exists")
            return str(error), None

        task_args = {
            "user_id": self.request.user.id,
            "channel_id": channel_id,
            "source_id": source.id,
            "target_id": target.id,
            "pk": pk,
            "mods": mods,
            "excluded_descendants": excluded_descendants,
            "position": position,
        }

        task, task_info = create_async_task("duplicate-nodes",
                                            self.request.user, **task_args)

        return (
            None,
            [
                generate_update_event(pk, CONTENTNODE,
                                      {TASK_ID: task_info.task_id})
            ],
        )
Пример #23
0
def duplicate_nodes_task(
    self,
    user_id,
    channel_id,
    target_id,
    source_id,
    pk=None,
    position="last-child",
    mods=None,
    excluded_descendants=None,
):
    source = ContentNode.objects.get(id=source_id)
    target = ContentNode.objects.get(id=target_id)

    can_edit_source_channel = ContentNode.filter_edit_queryset(
        ContentNode.objects.filter(id=source_id), user_id=user_id).exists()

    new_node = None

    try:
        new_node = source.copy_to(
            target,
            position,
            pk,
            mods,
            excluded_descendants,
            can_edit_source_channel=can_edit_source_channel,
            progress_tracker=self.progress,
        )
    except IntegrityError:
        # This will happen if the node has already been created
        # Pass for now and just return the updated data
        # Possible we might want to raise an error here, but not clear
        # whether this could then be a way to sniff for ids
        pass

    changes = []
    if new_node is not None:
        changes.append(
            generate_update_event(pk, CONTENTNODE, {
                COPYING_FLAG: False,
                "node_id": new_node.node_id
            }))

    return {"changes": changes}
Пример #24
0
    def test_update_assessmentitem_unwriteable_fields(self):

        assessmentitem = models.AssessmentItem.objects.create(
            **self.assessmentitem_db_metadata
        )
        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    [assessmentitem.contentnode_id, assessmentitem.assessment_id],
                    ASSESSMENTITEM,
                    {"not_a_field": "not_a_value"},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
Пример #25
0
 def test_update_channel_thumbnail_encoding(self):
     user = testdata.user()
     channel = models.Channel.objects.create(**self.channel_metadata)
     channel.editors.add(user)
     new_encoding = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQA"
     self.client.force_authenticate(user=user)
     response = self.client.post(
         self.sync_url,
         [generate_update_event(channel.id, CHANNEL, {
             "thumbnail_encoding.base64": new_encoding,
             "thumbnail_encoding.orientation": 1,
             "thumbnail_encoding.scale": 0.73602189113443,
             "thumbnail_encoding.startX": -96.66631072431669,
             "thumbnail_encoding.startY": -335.58116356397636,
         })],
         format="json",
     )
     self.assertEqual(response.status_code, 200, response.content)
     self.assertEqual(models.Channel.objects.get(id=channel.id).thumbnail_encoding["base64"], new_encoding)
Пример #26
0
    def test_update_invitation_invited_user_cannot_revoke(self):

        invitation = models.Invitation.objects.create(
            **self.invitation_db_metadata)

        self.client.force_authenticate(user=self.invited_user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    invitation.id,
                    INVITATION,
                    {"revoked": True},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        invitation = models.Invitation.objects.get(id=invitation.id)
        self.assertFalse(invitation.revoked)
Пример #27
0
    def test_attempt_update_missing_assessmentitem(self):

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event([
                            self.channel.main_tree.get_descendants()
                                .filter(kind_id=content_kinds.EXERCISE)
                                .first()
                                .id,
                            uuid.uuid4().hex
                        ],
                    ASSESSMENTITEM,
                    {"question": "but why is it missing in the first place?"},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 400, response.content)
        self.assertEqual(response.data.get("errors")[0].get("error")[0], "Not found")
Пример #28
0
    def test_update_file_no_channel_permission(self):
        file = models.File.objects.create(**self.file_db_metadata)
        new_preset = format_presets.VIDEO_HIGH_RES

        self.channel.editors.remove(self.user)

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [generate_update_event(
                file.id,
                FILE,
                {"preset": new_preset},
            )],
            format="json",
        )
        self.assertEqual(response.status_code, 400, response.content)
        self.assertNotEqual(
            models.File.objects.get(id=file.id).preset_id,
            new_preset,
        )
Пример #29
0
    def test_update_file_no_channel(self):
        file_metadata = self.file_db_metadata
        contentnode_id = file_metadata.pop("contentnode_id")
        file = models.File.objects.create(**file_metadata)

        self.client.force_authenticate(user=self.user)
        response = self.client.post(
            self.sync_url,
            [
                generate_update_event(
                    file.id,
                    FILE,
                    {"contentnode": contentnode_id},
                )
            ],
            format="json",
        )
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(
            models.File.objects.get(id=file.id).contentnode_id,
            contentnode_id,
        )
Пример #30
0
    def test_viewer_cannot_edit_public_bookmarked_channel(self):
        user = testdata.user()
        new_name = "This is not the old name"
        channel = models.Channel.objects.create(**self.channel_metadata)
        channel.viewers.add(user)
        channel.public = True
        channel.save()

        self.client.force_authenticate(user=user)
        with self.settings(TEST_ENV=False):
            # Override test env here to check what will happen in production
            response = self.client.post(
                self.sync_url,
                [generate_update_event(channel.id, CHANNEL, {
                    "bookmark": True,
                    "name": new_name
                })],
                format="json",
            )
        self.assertEqual(response.status_code, 400, response.content)
        self.assertTrue(user.bookmarked_channels.filter(id=channel.id).exists())
        self.assertNotEqual(models.Channel.objects.get(id=channel.id).name, new_name)