Beispiel #1
0
    def test_contentstore_attrs(self):
        """
        Test getting, setting, and defaulting the locked attr and arbitrary attrs.
        """
        location = Location('edX', 'toy', '2012_Fall', 'course', '2012_Fall')
        course_content, __ = self.content_store.get_all_content_for_course(location.course_key)
        assert_true(len(course_content) > 0)
        # a bit overkill, could just do for content[0]
        for content in course_content:
            assert not content.get('locked', False)
            asset_key = AssetLocation._from_deprecated_son(content.get('content_son', content['_id']), location.run)
            assert not self.content_store.get_attr(asset_key, 'locked', False)
            attrs = self.content_store.get_attrs(asset_key)
            assert_in('uploadDate', attrs)
            assert not attrs.get('locked', False)
            self.content_store.set_attr(asset_key, 'locked', True)
            assert self.content_store.get_attr(asset_key, 'locked', False)
            attrs = self.content_store.get_attrs(asset_key)
            assert_in('locked', attrs)
            assert attrs['locked'] is True
            self.content_store.set_attrs(asset_key, {'miscel': 99})
            assert_equals(self.content_store.get_attr(asset_key, 'miscel'), 99)

        asset_key = AssetLocation._from_deprecated_son(
            course_content[0].get('content_son', course_content[0]['_id']),
            location.run
        )
        assert_raises(
            AttributeError, self.content_store.set_attr, asset_key,
            'md5', 'ff1532598830e3feac91c2449eaa60d6'
        )
        assert_raises(
            AttributeError, self.content_store.set_attrs, asset_key,
            {'foo': 9, 'md5': 'ff1532598830e3feac91c2449eaa60d6'}
        )
        assert_raises(
            NotFoundError, self.content_store.get_attr,
            Location('bogus', 'bogus', 'bogus', 'asset', 'bogus'),
            'displayname'
        )
        assert_raises(
            NotFoundError, self.content_store.set_attr,
            Location('bogus', 'bogus', 'bogus', 'asset', 'bogus'),
            'displayname', 'hello'
        )
        assert_raises(
            NotFoundError, self.content_store.get_attrs,
            Location('bogus', 'bogus', 'bogus', 'asset', 'bogus')
        )
        assert_raises(
            NotFoundError, self.content_store.set_attrs,
            Location('bogus', 'bogus', 'bogus', 'asset', 'bogus'),
            {'displayname': 'hello'}
        )
        assert_raises(
            NotFoundError, self.content_store.set_attrs,
            Location('bogus', 'bogus', 'bogus', 'asset', None),
            {'displayname': 'hello'}
        )
Beispiel #2
0
 def get_location_from_path(path):
     """
     Generate an AssetKey for the given path (old c4x/org/course/asset/name syntax)
     """
     # TODO OpaqueKey - change to from_string once opaque keys lands
     # return AssetLocation.from_string(path)
     return AssetLocation.from_deprecated_string(path)
 def get_location_from_path(path):
     """
     Generate an AssetKey for the given path (old c4x/org/course/asset/name syntax)
     """
     # TODO OpaqueKeys after opaque keys deprecation is working
     # return AssetLocation.from_string(path)
     return AssetLocation.from_deprecated_string(path)
Beispiel #4
0
    def test_delete_image_type_asset(self):
        """ Tests deletion of image type asset """
        image_asset = self.get_sample_asset(self.asset_name, asset_type="image")
        thumbnail_image_asset = self.get_sample_asset('delete_test_thumbnail', asset_type="image")

        # upload image
        response = self.client.post(self.url, {"name": "delete_image_test", "file": image_asset})
        self.assertEquals(response.status_code, 200)
        uploaded_image_url = json.loads(response.content)['asset']['url']

        # upload image thumbnail
        response = self.client.post(self.url, {"name": "delete_image_thumb_test", "file": thumbnail_image_asset})
        self.assertEquals(response.status_code, 200)
        thumbnail_url = json.loads(response.content)['asset']['url']
        thumbnail_location = StaticContent.get_location_from_path(thumbnail_url)

        image_asset_location = AssetLocation.from_deprecated_string(uploaded_image_url)
        content = contentstore().find(image_asset_location)
        content.thumbnail_location = thumbnail_location
        contentstore().save(content)

        with mock.patch('opaque_keys.edx.locator.CourseLocator.make_asset_key') as mock_asset_key:
            mock_asset_key.return_value = thumbnail_location

            test_url = reverse_course_url(
                'assets_handler', self.course.id, kwargs={'asset_key_string': unicode(uploaded_image_url)})
            resp = self.client.delete(test_url, HTTP_ACCEPT="application/json")
            self.assertEquals(resp.status_code, 204)
Beispiel #5
0
    def export_all_for_course(self, course_key, output_directory, assets_policy_file):
        """
        Export all of this course's assets to the output_directory. Export all of the assets'
        attributes to the policy file.

        Args:
            course_key (CourseKey): the :class:`CourseKey` identifying the course
            output_directory: the directory under which to put all the asset files
            assets_policy_file: the filename for the policy file which should be in the same
                directory as the other policy files.
        """
        policy = {}
        assets, __ = self.get_all_content_for_course(course_key)

        for asset in assets:
            asset_location = AssetLocation._from_deprecated_son(asset['_id'], course_key.run)  # pylint: disable=protected-access
            # TODO: On 6/19/14, I had to put a try/except around this
            # to export a course. The course failed on JSON files in
            # the /static/ directory placed in it with an import.
            # 
            # If this hasn't been looked at in a while, remove this comment. 
            #
            # When debugging course exports, this might be a good place
            # to look. -- pmitros
            self.export(asset_location, output_directory) 
            for attr, value in asset.iteritems():
                if attr not in ['_id', 'md5', 'uploadDate', 'length', 'chunkSize']:
                    policy.setdefault(asset_location.name, {})[attr] = value

        with open(assets_policy_file, 'w') as f:
            json.dump(policy, f)
    def test_static_import(self):
        '''
        Stuff in static_import should always be imported into contentstore
        '''
        _, content_store, course = self.load_test_import_course()

        # make sure we have ONE asset in our contentstore ("should_be_imported.html")
        all_assets, count = content_store.get_all_content_for_course(course.id)
        print "len(all_assets)=%d" % len(all_assets)
        self.assertEqual(len(all_assets), 1)
        self.assertEqual(count, 1)

        content = None
        try:
            location = AssetLocation.from_deprecated_string(
                '/c4x/edX/test_import_course/asset/should_be_imported.html'
            )
            content = content_store.find(location)
        except NotFoundError:
            pass

        self.assertIsNotNone(content)

        # make sure course.static_asset_path is correct
        print "static_asset_path = {0}".format(course.static_asset_path)
        self.assertEqual(course.static_asset_path, 'test_import_course')
 def test_can_delete_certificate_with_signatories(self):
     """
     Delete certificate
     """
     self._add_course_certificates(count=2, signatory_count=1)
     certificates = self.course.certificates["certificates"]
     org_logo_url = certificates[1]["org_logo_path"]
     image_asset_location = AssetLocation.from_deprecated_string(org_logo_url)
     content = contentstore().find(image_asset_location)
     self.assertIsNotNone(content)
     response = self.client.delete(
         self._url(cid=1),
         content_type="application/json",
         HTTP_ACCEPT="application/json",
         HTTP_X_REQUESTED_WITH="XMLHttpRequest",
     )
     self.assertEqual(response.status_code, 204)
     self.assert_event_emitted(
         "edx.certificate.configuration.deleted", course_id=unicode(self.course.id), configuration_id="1"
     )
     self.reload_course()
     # Verify that certificates are properly updated in the course.
     certificates = self.course.certificates["certificates"]
     self.assertEqual(len(certificates), 1)
     # make sure certificate org logo is deleted too
     self.assertRaises(NotFoundError, contentstore().find, image_asset_location)
     self.assertEqual(certificates[0].get("name"), "Name 0")
     self.assertEqual(certificates[0].get("description"), "Description 0")
    def test_can_delete_signatory(self):
        """
        Delete an existing certificate signatory
        """
        self._add_course_certificates(count=2, signatory_count=3)
        certificates = self.course.certificates["certificates"]
        signatory = certificates[1].get("signatories")[1]
        image_asset_location = AssetLocation.from_deprecated_string(signatory["signature_image_path"])
        content = contentstore().find(image_asset_location)
        self.assertIsNotNone(content)
        test_url = "{}/signatories/1".format(self._url(cid=1))
        response = self.client.delete(
            test_url,
            content_type="application/json",
            HTTP_ACCEPT="application/json",
            HTTP_X_REQUESTED_WITH="XMLHttpRequest",
        )
        self.assertEqual(response.status_code, 204)
        self.reload_course()

        # Verify that certificates are properly updated in the course.
        certificates = self.course.certificates["certificates"]
        self.assertEqual(len(certificates[1].get("signatories")), 2)
        # make sure signatory signature image is deleted too
        self.assertRaises(NotFoundError, contentstore().find, image_asset_location)
def _clear_assets(location):
    """
    Clear all assets for location.
    """
    store = contentstore()

    assets, __ = store.get_all_content_for_course(location.course_key)
    for asset in assets:
        asset_location = AssetLocation._from_deprecated_son(asset["_id"], location.course_key.run)
        del_cached_content(asset_location)
        store.delete(asset_location)
Beispiel #10
0
    def setUp(self):
        """ Scaffolding """
        super(DeleteAssetTestCase, self).setUp()
        self.url = reverse_course_url('assets_handler', self.course.id)
        # First, upload something.
        self.asset_name = 'delete_test'
        self.asset = self.get_sample_asset(self.asset_name)

        response = self.client.post(self.url, {"name": self.asset_name, "file": self.asset})
        self.assertEquals(response.status_code, 200)
        self.uploaded_url = json.loads(response.content)['asset']['url']

        self.asset_location = AssetLocation.from_deprecated_string(self.uploaded_url)
        self.content = contentstore().find(self.asset_location)
    def test_pdf_asset(self):
        module_store = modulestore()
        course_items = import_course_from_xml(
            module_store, self.user.id, TEST_DATA_DIR, ["toy"], static_content_store=contentstore(), verbose=True
        )
        course = course_items[0]
        url = reverse_course_url("assets_handler", course.id)

        # Test valid contentType for pdf asset (textbook.pdf)
        resp = self.client.get(url, HTTP_ACCEPT="application/json")
        self.assertContains(resp, "/c4x/edX/toy/asset/textbook.pdf")
        asset_location = AssetLocation.from_deprecated_string("/c4x/edX/toy/asset/textbook.pdf")
        content = contentstore().find(asset_location)
        # Check after import textbook.pdf has valid contentType ('application/pdf')

        # Note: Actual contentType for textbook.pdf in asset.json is 'text/pdf'
        self.assertEqual(content.content_type, "application/pdf")
    def compute_location(course_key, path, revision=None, is_thumbnail=False):
        """
        Constructs a location object for static content.

        - course_key: the course that this asset belongs to
        - path: is the name of the static asset
        - revision: is the object's revision information
        - is_thumbnail: is whether or not we want the thumbnail version of this
            asset
        """
        path = path.replace('/', '_')
        return AssetLocation(
            course_key.org, course_key.course, course_key.run,
            'asset' if not is_thumbnail else 'thumbnail',
            AssetLocation.clean_keeping_underscores(path),
            revision
        )
    def test_get_all_content(self, deprecated):
        """
        Test get_all_content_for_course
        """
        self.set_up_assets(deprecated)
        course1_assets, count = self.contentstore.get_all_content_for_course(self.course1_key)
        self.assertEqual(count, len(self.course1_files), course1_assets)
        for asset in course1_assets:
            parsed = AssetLocation.from_deprecated_string(asset['filename'])
            self.assertIn(parsed.name, self.course1_files)

        course1_assets, __ = self.contentstore.get_all_content_for_course(self.course1_key, 1, 1)
        self.assertEqual(len(course1_assets), 1, course1_assets)

        fake_course = SlashSeparatedCourseKey('test', 'fake', 'non')
        course_assets, count = self.contentstore.get_all_content_for_course(fake_course)
        self.assertEqual(count, 0)
        self.assertEqual(course_assets, [])
Beispiel #14
0
    def test_pdf_asset(self):
        module_store = modulestore('direct')
        _, course_items = import_from_xml(
            module_store,
            'common/test/data/',
            ['toy'],
            static_content_store=contentstore(),
            verbose=True
        )
        course = course_items[0]
        url = reverse_course_url('assets_handler', course.id)

        # Test valid contentType for pdf asset (textbook.pdf)
        resp = self.client.get(url, HTTP_ACCEPT='application/json')
        self.assertContains(resp, "/c4x/edX/toy/asset/textbook.pdf")
        asset_location = AssetLocation.from_deprecated_string('/c4x/edX/toy/asset/textbook.pdf')
        content = contentstore().find(asset_location)
        # Check after import textbook.pdf has valid contentType ('application/pdf')

        # Note: Actual contentType for textbook.pdf in asset.json is 'text/pdf'
        self.assertEqual(content.content_type, 'application/pdf')
Beispiel #15
0
    def export_all_for_course(self, course_key, output_directory, assets_policy_file):
        """
        Export all of this course's assets to the output_directory. Export all of the assets'
        attributes to the policy file.

        Args:
            course_key (CourseKey): the :class:`CourseKey` identifying the course
            output_directory: the directory under which to put all the asset files
            assets_policy_file: the filename for the policy file which should be in the same
                directory as the other policy files.
        """
        policy = {}
        assets, __ = self.get_all_content_for_course(course_key)

        for asset in assets:
            asset_location = AssetLocation._from_deprecated_son(asset['_id'], course_key.run)  # pylint: disable=protected-access
            self.export(asset_location, output_directory)
            for attr, value in asset.iteritems():
                if attr not in ['_id', 'md5', 'uploadDate', 'length', 'chunkSize']:
                    policy.setdefault(asset_location.name, {})[attr] = value

        with open(assets_policy_file, 'w') as f:
            json.dump(policy, f)
Beispiel #16
0
    def copy_all_course_assets(self, source_course_key, dest_course_key):
        """
        See :meth:`.ContentStore.copy_all_course_assets`

        This implementation fairly expensively copies all of the data
        """
        source_query = query_for_course(source_course_key)
        # it'd be great to figure out how to do all of this on the db server and not pull the bits over
        for asset in self.fs_files.find(source_query):
            asset_key = self.make_id_son(asset)
            # don't convert from string until fs access
            source_content = self.fs.get(asset_key)
            if isinstance(asset_key, basestring):
                asset_key = AssetLocation.from_string(asset_key)
                __, asset_key = self.asset_db_key(asset_key)
            asset_key['org'] = dest_course_key.org
            asset_key['course'] = dest_course_key.course
            if getattr(dest_course_key, 'deprecated', False):  # remove the run if exists
                if 'run' in asset_key:
                    del asset_key['run']
                asset_id = asset_key
            else:  # add the run, since it's the last field, we're golden
                asset_key['run'] = dest_course_key.run
                asset_id = unicode(dest_course_key.make_asset_key(asset_key['category'], asset_key['name']))

            self.fs.put(
                source_content.read(),
                _id=asset_id, filename=asset['filename'], content_type=asset['contentType'],
                displayname=asset['displayname'], content_son=asset_key,
                # thumbnail is not technically correct but will be functionally correct as the code
                # only looks at the name which is not course relative.
                thumbnail_location=asset['thumbnail_location'],
                import_path=asset['import_path'],
                # getattr b/c caching may mean some pickled instances don't have attr
                locked=asset.get('locked', False)
            )
Beispiel #17
0
    def test_contentstore_attrs(self):
        """
        Test getting, setting, and defaulting the locked attr and arbitrary attrs.
        """
        location = Location("edX", "toy", "2012_Fall", "course", "2012_Fall")
        course_content, __ = self.content_store.get_all_content_for_course(location.course_key)
        assert_true(len(course_content) > 0)
        filter_params = _build_requested_filter("Images")
        filtered_course_content, __ = self.content_store.get_all_content_for_course(
            location.course_key, filter_params=filter_params
        )
        assert_true(len(filtered_course_content) < len(course_content))
        # a bit overkill, could just do for content[0]
        for content in course_content:
            assert not content.get("locked", False)
            asset_key = AssetLocation._from_deprecated_son(content.get("content_son", content["_id"]), location.run)
            assert not self.content_store.get_attr(asset_key, "locked", False)
            attrs = self.content_store.get_attrs(asset_key)
            assert_in("uploadDate", attrs)
            assert not attrs.get("locked", False)
            self.content_store.set_attr(asset_key, "locked", True)
            assert self.content_store.get_attr(asset_key, "locked", False)
            attrs = self.content_store.get_attrs(asset_key)
            assert_in("locked", attrs)
            assert attrs["locked"] is True
            self.content_store.set_attrs(asset_key, {"miscel": 99})
            assert_equals(self.content_store.get_attr(asset_key, "miscel"), 99)

        asset_key = AssetLocation._from_deprecated_son(
            course_content[0].get("content_son", course_content[0]["_id"]), location.run
        )
        assert_raises(AttributeError, self.content_store.set_attr, asset_key, "md5", "ff1532598830e3feac91c2449eaa60d6")
        assert_raises(
            AttributeError,
            self.content_store.set_attrs,
            asset_key,
            {"foo": 9, "md5": "ff1532598830e3feac91c2449eaa60d6"},
        )
        assert_raises(
            NotFoundError,
            self.content_store.get_attr,
            Location("bogus", "bogus", "bogus", "asset", "bogus"),
            "displayname",
        )
        assert_raises(
            NotFoundError,
            self.content_store.set_attr,
            Location("bogus", "bogus", "bogus", "asset", "bogus"),
            "displayname",
            "hello",
        )
        assert_raises(
            NotFoundError, self.content_store.get_attrs, Location("bogus", "bogus", "bogus", "asset", "bogus")
        )
        assert_raises(
            NotFoundError,
            self.content_store.set_attrs,
            Location("bogus", "bogus", "bogus", "asset", "bogus"),
            {"displayname": "hello"},
        )
        assert_raises(
            NotFoundError,
            self.content_store.set_attrs,
            Location("bogus", "bogus", "bogus", "asset", None),
            {"displayname": "hello"},
        )
Beispiel #18
0
 def get_location_from_path(path):
     """
     Generate an AssetKey for the given path (old c4x/org/course/asset/name syntax)
     """
     return AssetLocation.from_deprecated_string(path)