コード例 #1
0
ファイル: assets.py プロジェクト: CraftAcademy/edx-platform
def _update_asset(request, course_key, asset_key):
    """
    restful CRUD operations for a course asset.
    Currently only DELETE, POST, and PUT methods are implemented.

    asset_path_encoding: the odd /c4x/org/course/category/name repr of the asset (used by Backbone as the id)
    """
    if request.method == 'DELETE':
        try:
            delete_asset(course_key, asset_key)
            return JsonResponse()
        except AssetNotFoundException:
            return JsonResponse(status=404)

    elif request.method in ('PUT', 'POST'):
        if 'file' in request.FILES:
            return _upload_asset(request, course_key)
        else:
            # Update existing asset
            try:
                modified_asset = json.loads(request.body)
            except ValueError:
                return HttpResponseBadRequest()
            contentstore().set_attr(asset_key, 'locked', modified_asset['locked'])
            # Delete the asset from the cache so we check the lock status the next time it is requested.
            del_cached_content(asset_key)
            return JsonResponse(modified_asset, status=201)
コード例 #2
0
ファイル: assets.py プロジェクト: CraftAcademy/edx-platform
def delete_asset(course_key, asset_key):
    """
    Deletes asset represented by given 'asset_key' in the course represented by given course_key.
    """
    # Make sure the item to delete actually exists.
    try:
        content = contentstore().find(asset_key)
    except NotFoundError:
        raise AssetNotFoundException

    # ok, save the content into the trashcan
    contentstore('trashcan').save(content)

    # see if there is a thumbnail as well, if so move that as well
    if content.thumbnail_location is not None:
        # We are ignoring the value of the thumbnail_location-- we only care whether
        # or not a thumbnail has been stored, and we can now easily create the correct path.
        thumbnail_location = course_key.make_asset_key('thumbnail', asset_key.name)
        try:
            thumbnail_content = contentstore().find(thumbnail_location)
            contentstore('trashcan').save(thumbnail_content)
            # hard delete thumbnail from origin
            contentstore().delete(thumbnail_content.get_id())
            # remove from any caching
            del_cached_content(thumbnail_location)
        except Exception:  # pylint: disable=broad-except
            logging.warning('Could not delete thumbnail: %s', thumbnail_location)

    # delete the original
    contentstore().delete(content.get_id())
    # remove from cache
    del_cached_content(content.location)
コード例 #3
0
 def test_delete(self):
     set_cached_content(self.mockAsset)
     del_cached_content(self.nonUnicodeLocation)
     self.assertEqual(None, get_cached_content(self.unicodeLocation),
                      'should not be stored in cache with unicodeLocation')
     self.assertEqual(None, get_cached_content(self.nonUnicodeLocation),
                      'should not be stored in cache with nonUnicodeLocation')
コード例 #4
0
def delete_asset(course_key, asset_key):
    """
    Deletes asset represented by given 'asset_key' in the course represented by given course_key.
    """
    # Make sure the item to delete actually exists.
    try:
        content = contentstore().find(asset_key)
    except NotFoundError:
        raise AssetNotFoundException

    # ok, save the content into the trashcan
    contentstore('trashcan').save(content)

    # see if there is a thumbnail as well, if so move that as well
    if content.thumbnail_location is not None:
        # We are ignoring the value of the thumbnail_location-- we only care whether
        # or not a thumbnail has been stored, and we can now easily create the correct path.
        thumbnail_location = course_key.make_asset_key('thumbnail',
                                                       asset_key.name)
        try:
            thumbnail_content = contentstore().find(thumbnail_location)
            contentstore('trashcan').save(thumbnail_content)
            # hard delete thumbnail from origin
            contentstore().delete(thumbnail_content.get_id())
            # remove from any caching
            del_cached_content(thumbnail_location)
        except Exception:  # pylint: disable=broad-except
            logging.warning('Could not delete thumbnail: %s',
                            thumbnail_location)

    # delete the original
    contentstore().delete(content.get_id())
    # remove from cache
    del_cached_content(content.location)
コード例 #5
0
def _update_asset(request, course_key, asset_key):
    """
    restful CRUD operations for a course asset.
    Currently only DELETE, POST, and PUT methods are implemented.

    asset_path_encoding: the odd /c4x/org/course/category/name repr of the asset (used by Backbone as the id)
    """
    if request.method == 'DELETE':
        try:
            delete_asset(course_key, asset_key)
            return JsonResponse()
        except AssetNotFoundException:
            return JsonResponse(status=404)

    elif request.method in ('PUT', 'POST'):
        if 'file' in request.FILES:
            return _upload_asset(request, course_key)
        else:
            # Update existing asset
            try:
                modified_asset = json.loads(request.body)
            except ValueError:
                return HttpResponseBadRequest()
            contentstore().set_attr(asset_key, 'locked',
                                    modified_asset['locked'])
            # Delete the asset from the cache so we check the lock status the next time it is requested.
            del_cached_content(asset_key)
            return JsonResponse(modified_asset, status=201)
コード例 #6
0
 def test_delete(self):
     set_cached_content(self.mockAsset)
     del_cached_content(self.nonUnicodeLocation)
     self.assertEqual(None, get_cached_content(self.unicodeLocation),
                      'should not be stored in cache with unicodeLocation')
     self.assertEqual(
         None, get_cached_content(self.nonUnicodeLocation),
         'should not be stored in cache with nonUnicodeLocation')
コード例 #7
0
def _upload_file(subs_file, location, filename):
    mime_type = subs_file.content_type
    content_location = StaticContent.compute_location(
        location.course_key, filename
    )
    content = StaticContent(content_location, filename, mime_type, subs_file.read())
    contentstore().save(content)
    del_cached_content(content.location)
コード例 #8
0
def _upload_file(subs_file, location, filename):
    mime_type = subs_file.content_type
    content_location = StaticContent.compute_location(location.course_key,
                                                      filename)
    content = StaticContent(content_location, filename, mime_type,
                            subs_file.read())
    contentstore().save(content)
    del_cached_content(content.location)
コード例 #9
0
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 = asset['asset_key']
        del_cached_content(asset_location)
        store.delete(asset_location)
コード例 #10
0
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 = asset['asset_key']
        del_cached_content(asset_location)
        store.delete(asset_location)
コード例 #11
0
    def save_subs_to_store(self, subs, subs_id):
        """Save transcripts into `StaticContent`."""
        filedata = json.dumps(subs, indent=2)
        mime_type = 'application/json'
        filename = 'subs_{0}.srt.sjson'.format(subs_id)

        content_location = StaticContent.compute_location(self.course.id, filename)
        content = StaticContent(content_location, filename, mime_type, filedata)
        contentstore().save(content)
        del_cached_content(content_location)
        return content_location
コード例 #12
0
    def save_subs_to_store(self, subs, subs_id):
        """Save transcripts into `StaticContent`."""
        filedata = json.dumps(subs, indent=2)
        mime_type = 'application/json'
        filename = 'subs_{0}.srt.sjson'.format(subs_id)

        content_location = StaticContent.compute_location(
            self.course.id, filename)
        content = StaticContent(content_location, filename, mime_type,
                                filedata)
        contentstore().save(content)
        del_cached_content(content_location)
        return content_location
コード例 #13
0
ファイル: assets.py プロジェクト: CraftAcademy/edx-platform
def _upload_asset(request, course_key):
    '''
    This method allows for POST uploading of files into the course asset
    library, which will be supported by GridFS in MongoDB.
    '''
    # Does the course actually exist?!? Get anything from it to prove its
    # existence
    try:
        modulestore().get_course(course_key)
    except ItemNotFoundError:
        # no return it as a Bad Request response
        logging.error("Could not find course: %s", course_key)
        return HttpResponseBadRequest()

    # compute a 'filename' which is similar to the location formatting, we're
    # using the 'filename' nomenclature since we're using a FileSystem paradigm
    # here. We're just imposing the Location string formatting expectations to
    # keep things a bit more consistent
    upload_file = request.FILES['file']
    filename = upload_file.name
    mime_type = upload_file.content_type
    size = get_file_size(upload_file)

    # If file is greater than a specified size, reject the upload
    # request and send a message to the user. Note that since
    # the front-end may batch large file uploads in smaller chunks,
    # we validate the file-size on the front-end in addition to
    # validating on the backend. (see cms/static/js/views/assets.js)
    max_file_size_in_bytes = settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB * 1000 ** 2
    if size > max_file_size_in_bytes:
        return JsonResponse({
            'error': _(
                'File {filename} exceeds maximum size of '
                '{size_mb} MB. Please follow the instructions here '
                'to upload a file elsewhere and link to it instead: '
                '{faq_url}'
            ).format(
                filename=filename,
                size_mb=settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB,
                faq_url=settings.MAX_ASSET_UPLOAD_FILE_SIZE_URL,
            )
        }, status=413)

    content_loc = StaticContent.compute_location(course_key, filename)

    chunked = upload_file.multiple_chunks()
    sc_partial = partial(StaticContent, content_loc, filename, mime_type)
    if chunked:
        content = sc_partial(upload_file.chunks())
        tempfile_path = upload_file.temporary_file_path()
    else:
        content = sc_partial(upload_file.read())
        tempfile_path = None

    # first let's see if a thumbnail can be created
    (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(
        content,
        tempfile_path=tempfile_path,
    )

    # delete cached thumbnail even if one couldn't be created this time (else
    # the old thumbnail will continue to show)
    del_cached_content(thumbnail_location)
    # now store thumbnail location only if we could create it
    if thumbnail_content is not None:
        content.thumbnail_location = thumbnail_location

    # then commit the content
    contentstore().save(content)
    del_cached_content(content.location)

    # readback the saved content - we need the database timestamp
    readback = contentstore().find(content.location)
    locked = getattr(content, 'locked', False)
    response_payload = {
        'asset': _get_asset_json(
            content.name,
            content.content_type,
            readback.last_modified_at,
            content.location,
            content.thumbnail_location,
            locked
        ),
        'msg': _('Upload completed')
    }

    return JsonResponse(response_payload)
コード例 #14
0
def _upload_asset(request, course_key):
    '''
    This method allows for POST uploading of files into the course asset
    library, which will be supported by GridFS in MongoDB.
    '''
    # Does the course actually exist?!? Get anything from it to prove its
    # existence
    try:
        modulestore().get_course(course_key)
    except ItemNotFoundError:
        # no return it as a Bad Request response
        logging.error("Could not find course: %s", course_key)
        return HttpResponseBadRequest()

    # compute a 'filename' which is similar to the location formatting, we're
    # using the 'filename' nomenclature since we're using a FileSystem paradigm
    # here. We're just imposing the Location string formatting expectations to
    # keep things a bit more consistent
    upload_file = request.FILES['file']
    filename = upload_file.name
    mime_type = upload_file.content_type
    size = get_file_size(upload_file)

    # If file is greater than a specified size, reject the upload
    # request and send a message to the user. Note that since
    # the front-end may batch large file uploads in smaller chunks,
    # we validate the file-size on the front-end in addition to
    # validating on the backend. (see cms/static/js/views/assets.js)
    max_file_size_in_bytes = settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB * 1000**2
    if size > max_file_size_in_bytes:
        return JsonResponse(
            {
                'error':
                _('File {filename} exceeds maximum size of '
                  '{size_mb} MB. Please follow the instructions here '
                  'to upload a file elsewhere and link to it instead: '
                  '{faq_url}').format(
                      filename=filename,
                      size_mb=settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB,
                      faq_url=settings.MAX_ASSET_UPLOAD_FILE_SIZE_URL,
                  )
            },
            status=413)

    content_loc = StaticContent.compute_location(course_key, filename)

    chunked = upload_file.multiple_chunks()
    sc_partial = partial(StaticContent, content_loc, filename, mime_type)
    if chunked:
        content = sc_partial(upload_file.chunks())
        tempfile_path = upload_file.temporary_file_path()
    else:
        content = sc_partial(upload_file.read())
        tempfile_path = None

    # first let's see if a thumbnail can be created
    (thumbnail_content,
     thumbnail_location) = contentstore().generate_thumbnail(
         content,
         tempfile_path=tempfile_path,
     )

    # delete cached thumbnail even if one couldn't be created this time (else
    # the old thumbnail will continue to show)
    del_cached_content(thumbnail_location)
    # now store thumbnail location only if we could create it
    if thumbnail_content is not None:
        content.thumbnail_location = thumbnail_location

    # then commit the content
    contentstore().save(content)
    del_cached_content(content.location)

    # readback the saved content - we need the database timestamp
    readback = contentstore().find(content.location)
    locked = getattr(content, 'locked', False)
    response_payload = {
        'asset':
        _get_asset_json(content.name, content.content_type,
                        readback.last_modified_at, content.location,
                        content.thumbnail_location, locked),
        'msg':
        _('Upload completed')
    }

    return JsonResponse(response_payload)