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)
def _upload_file(videoId, lang, location): if lang == 'en': filename = 'subs_{0}.srt.sjson'.format(videoId) else: filename = '{0}_subs_{1}.srt.sjson'.format(lang, videoId) path = os.path.join(TEST_ROOT, 'uploads/', filename) f = open(os.path.abspath(path)) mime_type = "application/json" content_location = StaticContent.compute_location( location.org, location.course, filename ) sc_partial = partial(StaticContent, content_location, filename, mime_type) content = sc_partial(f.read()) (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail( content, tempfile_path=None ) del_cached_content(thumbnail_location) if thumbnail_content is not None: content.thumbnail_location = thumbnail_location contentstore().save(content) del_cached_content(content.location)
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')
def upload_image(course_key, upload_file): filename = upload_file.name mime_type = upload_file.content_type 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) return filename
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 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, readback.last_modified_at, content.location, content.thumbnail_location, locked), 'msg': _('Upload completed') } return JsonResponse(response_payload)
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)
def upload_to_local(self): content_loc = StaticContent.compute_location(self.course_key, self.filename) mime_type = 'application/json' # Note: cribbed from common/lib/xmodule/xmodule/video_module/transcripts_utils.py save_subs_to_store() filedata = json.dumps(self.subs, indent=2) content = StaticContent(content_loc, self.filename, mime_type, filedata) contentstore().save(content) del_cached_content(content_loc)
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)
def upload_file(filename, location): path = os.path.join(TEST_ROOT, "uploads/", filename) f = open(os.path.abspath(path)) mime_type = "application/json" content_location = StaticContent.compute_location(location.course_key, filename) content = StaticContent(content_location, filename, mime_type, f.read()) contentstore().save(content) del_cached_content(content.location)
def upload_file(filename, location): path = os.path.join(TEST_ROOT, 'uploads/', filename) f = open(os.path.abspath(path)) mime_type = "application/json" content_location = StaticContent.compute_location(location.course_key, filename) content = StaticContent(content_location, filename, mime_type, f.read()) contentstore().save(content) del_cached_content(content.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)
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)
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
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) mongo_id = asset_location.to_deprecated_son() store.delete(mongo_id)
def remove_subs_from_store(subs_id, item): """ Remove from store, if transcripts content exists. """ filename = 'subs_{0}.srt.sjson'.format(subs_id) content_location = StaticContent.compute_location(item.location.org, item.location.course, filename) try: content = contentstore().find(content_location) contentstore().delete(content.get_id()) del_cached_content(content.location) log.info("Removed subs %s from store", subs_id) except NotFoundError: pass
def remove_subs_from_store(subs_id, item): """ Remove from store, if transcripts content exists. """ filename = 'subs_{0}.srt.sjson'.format(subs_id) content_location = StaticContent.compute_location( item.location.org, item.location.course, filename ) try: content = contentstore().find(content_location) contentstore().delete(content.get_id()) del_cached_content(content.location) log.info("Removed subs %s from store", subs_id) except NotFoundError: pass
def _clear_assets(location): """ Clear all assets for location. """ store = contentstore() content_location = StaticContent.compute_location( location.org, location.course, location.name ) assets, __ = store.get_all_content_for_course(content_location) for asset in assets: asset_location = Location(asset["_id"]) del_cached_content(asset_location) id = StaticContent.get_id_from_location(asset_location) store.delete(id)
def _clear_assets(location): """ Clear all assets for location. """ store = contentstore() content_location = StaticContent.compute_location(location.org, location.course, location.name) assets, __ = store.get_all_content_for_course(content_location) for asset in assets: asset_location = Location(asset["_id"]) del_cached_content(asset_location) id = StaticContent.get_id_from_location(asset_location) store.delete(id)
def remove_asset(request, org, course, name): ''' This method will perform a 'soft-delete' of an asset, which is basically to copy the asset from the main GridFS collection and into a Trashcan ''' get_location_and_verify_access(request, org, course, name) location = request.POST['location'] # make sure the location is valid try: loc = StaticContent.get_location_from_path(location) except InvalidLocationError: # return a 'Bad Request' to browser as we have a malformed Location response = HttpResponse() response.status_code = 400 return response # also make sure the item to delete actually exists try: content = contentstore().find(loc) except NotFoundError: response = HttpResponse() response.status_code = 404 return response # 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: try: thumbnail_content = contentstore().find(content.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_content.location) except: pass # OK if this is left dangling # delete the original contentstore().delete(content.get_id()) # remove from cache del_cached_content(content.location) return HttpResponse()
def store_jacket_image(course_key, img_path, filename): # set initial values content_name = asset_url = None # if image url is available then proceed if img_path: content_loc = StaticContent.compute_location(course_key, filename) mime_type = mimetypes.types_map['.' + filename.split('.')[-1]] sc_partial = partial(StaticContent, content_loc, filename, mime_type) content = None with open(img_path + filename) as file_obj: file_content = file_obj.read() if file_content: try: content = sc_partial( urllib.urlopen(img_path + filename).read()) except: pass if content: tempfile_path = None (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) content_name = content.name asset_url = StaticContent.serialize_asset_key_with_slash( content.location) # return content name and asset URL return content_name, asset_url
def update_asset(request, org, course, name, asset_id): """ restful CRUD operations for a course asset. Currently only the DELETE method is implemented. org, course, name: Attributes of the Location for the item to edit asset_id: the URL of the asset (used by Backbone as the id) """ get_location_and_verify_access(request, org, course, name) # make sure the location is valid try: loc = StaticContent.get_location_from_path(asset_id) except InvalidLocationError as err: # return a 'Bad Request' to browser as we have a malformed Location return JsonResponse({"error": err.message}, status=400) # also make sure the item to delete actually exists try: content = contentstore().find(loc) except NotFoundError: return JsonResponse(status=404) # 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: try: thumbnail_content = contentstore().find(content.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_content.location) except: logging.warning('Could not delete thumbnail: ' + content.thumbnail_location) # delete the original contentstore().delete(content.get_id()) # remove from cache del_cached_content(content.location) return JsonResponse()
def _upload_file(file, location): filename = 'subs_{}.srt.sjson'.format(_get_subs_id(file.name)) mime_type = file.content_type content_location = StaticContent.compute_location(location.org, location.course, filename) sc_partial = partial(StaticContent, content_location, filename, mime_type) content = sc_partial(file.read()) (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail( content, tempfile_path=None) del_cached_content(thumbnail_location) if thumbnail_content is not None: content.thumbnail_location = thumbnail_location contentstore().save(content) del_cached_content(content.location)
def save_subs_to_store(subs, subs_id, item): """ Save transcripts into `StaticContent`. Args: `subs_id`: str, subtitles id `item`: video module instance Returns: location of saved subtitles. """ filedata = json.dumps(subs, indent=2) mime_type = 'application/json' filename = 'subs_{0}.srt.sjson'.format(subs_id) content_location = StaticContent.compute_location( item.location.org, item.location.course, filename ) content = StaticContent(content_location, filename, mime_type, filedata) contentstore().save(content) del_cached_content(content_location) return content_location
def save_subs_to_store(subs, subs_id, item): """ Save transcripts into `StaticContent`. Args: `subs_id`: str, subtitles id `item`: video module instance Returns: location of saved subtitles. """ filedata = json.dumps(subs, indent=2) mime_type = 'application/json' filename = 'subs_{0}.srt.sjson'.format(subs_id) content_location = StaticContent.compute_location(item.location.org, item.location.course, filename) content = StaticContent(content_location, filename, mime_type, filedata) contentstore().save(content) del_cached_content(content_location) return content_location
def update_asset(request, org, course, name, asset_id): """ restful CRUD operations for a course asset. Currently only DELETE, POST, and PUT methods are implemented. org, course, name: Attributes of the Location for the item to edit asset_id: the URL of the asset (used by Backbone as the id) """ def get_asset_location(asset_id): """ Helper method to get the location (and verify it is valid). """ try: return StaticContent.get_location_from_path(asset_id) except InvalidLocationError as err: # return a 'Bad Request' to browser as we have a malformed Location return JsonResponse({"error": err.message}, status=400) get_location_and_verify_access(request, org, course, name) if request.method == 'DELETE': loc = get_asset_location(asset_id) # Make sure the item to delete actually exists. try: content = contentstore().find(loc) except NotFoundError: return JsonResponse(status=404) # 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: try: thumbnail_content = contentstore().find( content.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_content.location) except: logging.warning('Could not delete thumbnail: ' + content.thumbnail_location) # delete the original contentstore().delete(content.get_id()) # remove from cache del_cached_content(content.location) return JsonResponse() elif request.method in ('PUT', 'POST'): # We don't support creation of new assets through this # method-- just changing the locked state. modified_asset = json.loads(request.body) asset_id = modified_asset['url'] location = get_asset_location(asset_id) contentstore().set_attr(location, '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(location) return JsonResponse(modified_asset, status=201)
def _update_asset(request, location, asset_id): """ restful CRUD operations for a course asset. Currently only DELETE, POST, and PUT methods are implemented. asset_id: the URL of the asset (used by Backbone as the id) """ def get_asset_location(asset_id): """ Helper method to get the location (and verify it is valid). """ try: return StaticContent.get_location_from_path(asset_id) except InvalidLocationError as err: # return a 'Bad Request' to browser as we have a malformed Location return JsonResponse({"error": err.message}, status=400) if request.method == 'DELETE': loc = get_asset_location(asset_id) # Make sure the item to delete actually exists. try: content = contentstore().find(loc) except NotFoundError: return JsonResponse(status=404) # 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: try: thumbnail_content = contentstore().find(content.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_content.location) except: logging.warning('Could not delete thumbnail: ' + content.thumbnail_location) # delete the original contentstore().delete(content.get_id()) # remove from cache del_cached_content(content.location) return JsonResponse() elif request.method in ('PUT', 'POST'): if 'file' in request.FILES: return _upload_asset(request, location) else: # Update existing asset try: modified_asset = json.loads(request.body) except ValueError: return HttpResponseBadRequest() asset_id = modified_asset['url'] asset_location = get_asset_location(asset_id) contentstore().set_attr(asset_location, '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_location) return JsonResponse(modified_asset, status=201)
def _upload_file(file, location): filename = 'subs_{}.srt.sjson'.format(_get_subs_id(file.name)) mime_type = file.content_type content_location = StaticContent.compute_location( location.org, location.course, filename ) sc_partial = partial(StaticContent, content_location, filename, mime_type) content = sc_partial(file.read()) (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail( content, tempfile_path=None ) del_cached_content(thumbnail_location) if thumbnail_content is not None: content.thumbnail_location = thumbnail_location contentstore().save(content) del_cached_content(content.location)
def _update_asset(request, location, asset_id): """ restful CRUD operations for a course asset. Currently only DELETE, POST, and PUT methods are implemented. asset_id: the URL of the asset (used by Backbone as the id) """ def get_asset_location(asset_id): """ Helper method to get the location (and verify it is valid). """ try: return StaticContent.get_location_from_path(asset_id) except InvalidLocationError as err: # return a 'Bad Request' to browser as we have a malformed Location return JsonResponse({"error": err.message}, status=400) if request.method == 'DELETE': loc = get_asset_location(asset_id) # Make sure the item to delete actually exists. try: content = contentstore().find(loc) except NotFoundError: return JsonResponse(status=404) # 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: try: thumbnail_content = contentstore().find(content.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_content.location) except: logging.warning('Could not delete thumbnail: %s', content.thumbnail_location) # delete the original contentstore().delete(content.get_id()) # remove from cache del_cached_content(content.location) return JsonResponse() elif request.method in ('PUT', 'POST'): if 'file' in request.FILES: return _upload_asset(request, location) else: # Update existing asset try: modified_asset = json.loads(request.body) except ValueError: return HttpResponseBadRequest() asset_id = modified_asset['url'] asset_location = get_asset_location(asset_id) contentstore().set_attr(asset_location, '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_location) return JsonResponse(modified_asset, status=201)
def update_asset(request, org, course, name, asset_id): """ restful CRUD operations for a course asset. Currently only DELETE, POST, and PUT methods are implemented. org, course, name: Attributes of the Location for the item to edit asset_id: the URL of the asset (used by Backbone as the id) """ def get_asset_location(asset_id): """ Helper method to get the location (and verify it is valid). """ try: return StaticContent.get_location_from_path(asset_id) except InvalidLocationError as err: # return a 'Bad Request' to browser as we have a malformed Location return JsonResponse({"error": err.message}, status=400) get_location_and_verify_access(request, org, course, name) if request.method == 'DELETE': loc = get_asset_location(asset_id) # Make sure the item to delete actually exists. try: content = contentstore().find(loc) except NotFoundError: return JsonResponse(status=404) # 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: try: thumbnail_content = contentstore().find(content.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_content.location) except: logging.warning('Could not delete thumbnail: ' + content.thumbnail_location) # delete the original contentstore().delete(content.get_id()) # remove from cache del_cached_content(content.location) return JsonResponse() elif request.method in ('PUT', 'POST'): # We don't support creation of new assets through this # method-- just changing the locked state. modified_asset = json.loads(request.body) asset_id = modified_asset['url'] location = get_asset_location(asset_id) contentstore().set_attr(location, '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(location) return JsonResponse(modified_asset, status=201)
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': # Make sure the item to delete actually exists. try: content = contentstore().find(asset_key) except NotFoundError: return JsonResponse(status=404) # 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: 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) return JsonResponse() 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)
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': # Make sure the item to delete actually exists. try: content = contentstore().find(asset_key) except NotFoundError: return JsonResponse(status=404) # 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: 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) return JsonResponse() 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)
def _upload_asset(request, location): ''' This method allows for POST uploading of files into the course asset library, which will be supported by GridFS in MongoDB. ''' old_location = loc_mapper().translate_locator_to_location(location) # Does the course actually exist?!? Get anything from it to prove its # existence try: modulestore().get_item(old_location) except: # no return it as a Bad Request response logging.error("Could not find course: %s", old_location) return HttpResponseBadRequest() # get all filename course_reference = StaticContent.compute_location(old_location.org, old_location.course, old_location.name) filename_arr = [up_f["displayname"] for up_f in contentstore().get_all_content_for_course(course_reference, start=0, maxresults=-1, sort=None)[0]] or [] # 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 def acquire_purename_and_suffix(f_n): fn_sp = f_n.split(".") return ('.'.join(fn_sp[0:-1]), fn_sp[-1]) if filename in filename_arr: # filter same suffix filename pure_filename, file_suffix = acquire_purename_and_suffix(filename) pattern_str = "(" + pure_filename.replace("(", "\(").replace(")", "\)") + ")(" + "\()(\d+)(\))" pattern = re.compile(pattern_str) start_copy = 0 for f in filename_arr: f_n, f_s = acquire_purename_and_suffix(f) if f_s != file_suffix: continue match_obj = pattern.search(f_n) if match_obj: start_copy = int(match_obj.groups()[2]) if int(match_obj.groups()[2]) > start_copy else start_copy filename = pure_filename + "(" + str(start_copy + 1) + ")." + file_suffix mime_type = upload_file.content_type content_loc = StaticContent.compute_location(old_location.org, old_location.course, 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, readback.last_modified_at, content.location, content.thumbnail_location, locked), 'msg': _('Upload completed') } return JsonResponse(response_payload)
def _upload_asset(request, location): ''' This method allows for POST uploading of files into the course asset library, which will be supported by GridFS in MongoDB. ''' old_location = loc_mapper().translate_locator_to_location(location) # Does the course actually exist?!? Get anything from it to prove its # existence try: modulestore().get_item(old_location) except: # no return it as a Bad Request response logging.error("Could not find course: %s", old_location) return HttpResponseBadRequest() # get all filename course_reference = StaticContent.compute_location(old_location.org, old_location.course, old_location.name) filename_arr = [ up_f["displayname"] for up_f in contentstore().get_all_content_for_course( course_reference, start=0, maxresults=-1, sort=None)[0] ] or [] # 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 def acquire_purename_and_suffix(f_n): fn_sp = f_n.split(".") return ('.'.join(fn_sp[0:-1]), fn_sp[-1]) if filename in filename_arr: # filter same suffix filename pure_filename, file_suffix = acquire_purename_and_suffix(filename) pattern_str = "(" + pure_filename.replace("(", "\(").replace( ")", "\)") + ")(" + "\()(\d+)(\))" pattern = re.compile(pattern_str) start_copy = 0 for f in filename_arr: f_n, f_s = acquire_purename_and_suffix(f) if f_s != file_suffix: continue match_obj = pattern.search(f_n) if match_obj: start_copy = int(match_obj.groups()[2]) if int( match_obj.groups()[2]) > start_copy else start_copy filename = pure_filename + "(" + str(start_copy + 1) + ")." + file_suffix mime_type = upload_file.content_type content_loc = StaticContent.compute_location(old_location.org, old_location.course, 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, readback.last_modified_at, content.location, content.thumbnail_location, locked), 'msg': _('Upload completed') } return JsonResponse(response_payload)
def upload_asset(request, org, course, coursename): ''' This method allows for POST uploading of files into the course asset library, which will be supported by GridFS in MongoDB. ''' # construct a location from the passed in path location = get_location_and_verify_access(request, org, course, coursename) # Does the course actually exist?!? Get anything from it to prove its # existence try: modulestore().get_item(location) except: # no return it as a Bad Request response logging.error('Could not find course' + location) return HttpResponseBadRequest() if 'file' not in request.FILES: 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 content_loc = StaticContent.compute_location(org, course, 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, readback.last_modified_at, content.location, content.thumbnail_location, locked), 'msg': _('Upload completed') } return JsonResponse(response_payload)
def upload_asset(request, org, course, coursename): ''' cdodge: this method allows for POST uploading of files into the course asset library, which will be supported by GridFS in MongoDB. ''' if request.method != 'POST': # (cdodge) @todo: Is there a way to do a - say - 'raise Http400'? return HttpResponseBadRequest() # construct a location from the passed in path location = get_location_and_verify_access(request, org, course, coursename) # Does the course actually exist?!? Get anything from it to prove its existance try: modulestore().get_item(location) except: # no return it as a Bad Request response logging.error('Could not find course' + location) return HttpResponseBadRequest() if 'file' not in request.FILES: 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 filename = request.FILES['file'].name mime_type = request.FILES['file'].content_type filedata = request.FILES['file'].read() content_loc = StaticContent.compute_location(org, course, filename) content = StaticContent(content_loc, filename, mime_type, filedata) # first let's see if a thumbnail can be created (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(content) # 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) response_payload = { 'displayname': content.name, 'uploadDate': get_default_time_display(readback.last_modified_at), 'url': StaticContent.get_url_path_from_location(content.location), 'thumb_url': StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_content is not None else None, 'msg': 'Upload completed' } response = HttpResponse(json.dumps(response_payload)) response['asset_url'] = StaticContent.get_url_path_from_location( content.location) return response
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)
def upload_asset(request, org, course, coursename): ''' This method allows for POST uploading of files into the course asset library, which will be supported by GridFS in MongoDB. ''' # construct a location from the passed in path location = get_location_and_verify_access(request, org, course, coursename) # Does the course actually exist?!? Get anything from it to prove its # existence try: modulestore().get_item(location) except: # no return it as a Bad Request response logging.error('Could not find course' + location) return HttpResponseBadRequest() if 'file' not in request.FILES: 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 content_loc = StaticContent.compute_location(org, course, 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 thumbnail_content = None thumbnail_location = 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) response_payload = { 'displayname': content.name, 'uploadDate': get_default_time_display(readback.last_modified_at), 'url': StaticContent.get_url_path_from_location(content.location), 'portable_url': StaticContent.get_static_path_from_location(content.location), 'thumb_url': StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_content is not None else None, 'msg': 'Upload completed' } response = JsonResponse(response_payload) return response
def upload_asset(request, org, course, coursename): """ cdodge: this method allows for POST uploading of files into the course asset library, which will be supported by GridFS in MongoDB. """ if request.method != "POST": # (cdodge) @todo: Is there a way to do a - say - 'raise Http400'? return HttpResponseBadRequest() # construct a location from the passed in path location = get_location_and_verify_access(request, org, course, coursename) # Does the course actually exist?!? Get anything from it to prove its existance try: modulestore().get_item(location) except: # no return it as a Bad Request response logging.error("Could not find course" + location) 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 filename = request.FILES["file"].name mime_type = request.FILES["file"].content_type filedata = request.FILES["file"].read() content_loc = StaticContent.compute_location(org, course, filename) content = StaticContent(content_loc, filename, mime_type, filedata) # first let's see if a thumbnail can be created (thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(content) # 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) response_payload = { "displayname": content.name, "uploadDate": get_default_time_display(readback.last_modified_at.timetuple()), "url": StaticContent.get_url_path_from_location(content.location), "thumb_url": StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_content is not None else None, "msg": "Upload completed", } response = HttpResponse(json.dumps(response_payload)) response["asset_url"] = StaticContent.get_url_path_from_location(content.location) return response
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)