I'm working with OpenEdX, it has a plugin system, called XBlocks, that in this case allows importing content created by third party "studio apps." This content can be uploaded as a zip file. it is then processed by the following code:
@XBlock.handler
def studio_submit(self, request, _suffix):
self.display_name = request.params["display_name"]
self.width = request.params["width"]
self.height = request.params["height"]
self.has_score = request.params["has_score"]
self.weight = request.params["weight"]
self.icon_class = "problem" if self.has_score == "True" else "video"
response = {"result": "success", "errors": []}
if not hasattr(request.params["file"], "file"):
# File not uploaded
return self.json_response(response)
package_file = request.params["file"].file
self.update_package_meta(package_file)
# First, save scorm file in the storage for mobile clients
if default_storage.exists(self.package_path):
logger.info('Removing previously uploaded "%s"', self.package_path)
default_storage.delete(self.package_path)
default_storage.save(self.package_path, File(package_file))
logger.info('Scorm "%s" file stored at "%s"', package_file, self.package_path)
# Then, extract zip file
if default_storage.exists(self.extract_folder_base_path):
logger.info(
'Removing previously unzipped "%s"', self.extract_folder_base_path
)
recursive_delete(self.extract_folder_base_path)
with zipfile.ZipFile(package_file, "r") as scorm_zipfile:
for zipinfo in scorm_zipfile.infolist():
default_storage.save(
os.path.join(self.extract_folder_path, zipinfo.filename),
scorm_zipfile.open(zipinfo.filename),
)
try:
self.update_package_fields()
except ScormError as e:
response["errors"].append(e.args[0])
return self.json_response(response)
where the code
default_storage.save(
os.path.join(self.extract_folder_path, zipinfo.filename),
scorm_zipfile.open(zipinfo.filename),
)
is the origin of the following (Django) error trace:
cms_1 | File "/openedx/venv/lib/python3.5/site-packages/openedxscorm/scormxblock.py", line 193, in studio_submit
cms_1 | scorm_zipfile.open(zipinfo.filename),
cms_1 | File "/openedx/venv/lib/python3.5/site-packages/django/core/files/storage.py", line 52, in save
cms_1 | return self._save(name, content)
cms_1 | File "/openedx/venv/lib/python3.5/site-packages/django/core/files/storage.py", line 249, in _save
cms_1 | raise IOError("%s exists and is not a directory." % directory)
cms_1 | OSError: /openedx/media/scorm/c154229b568d45128e1098b530267a35/a346b1db27aaa89b89b31e1c3e2a1af04482abad/assets exists and is not a directory.
I posted the issue on github too
exception FileExistsError Raised when trying to create a file or directory which already exists. Corresponds to errno EEXIST.
I don't really understand what is going on. It's based on a hairball of javascript in layered docker containers, so I can't readily hack&print for extra info.
The only thing I found was that some of the folders in the zip file are written to the docker volume as files instead of directories at the moment the error is thrown. This may however be expected and these files might be rewritten as or changed to directories later (?) on Linux (?).
The error lists the assets
folder
root@93f0d2b9667f:/openedx/media/scorm/5e085cbc04e24b3b911802f7cba44296/92b12100be7651c812a1d29a041153db5ba89239# ls -la
total 84
drwxr-xr-x 2 root root 4096 Aug 2 22:17 .
drwxr-xr-x 3 root root 4096 Aug 2 22:17 ..
-rw-r--r-- 1 root root 4398 Aug 2 22:17 adlcp_rootv1p2.xsd
-rw-r--r-- 1 root root 0 Aug 2 22:17 assets
-rw-r--r-- 1 root root 0 Aug 2 22:17 course
-rw-r--r-- 1 root root 14560 Aug 2 22:17 imscp_rootv1p1p2.xsd
-rw-r--r-- 1 root root 1847 Aug 2 22:17 imsmanifest.xml
-rw-r--r-- 1 root root 22196 Aug 2 22:17 imsmd_rootv1p2p1.xsd
-rw-r--r-- 1 root root 1213 Aug 2 22:17 ims_xml.xsd
-rw-r--r-- 1 root root 1662 Aug 2 22:17 index.html
-rw-r--r-- 1 root root 0 Aug 2 22:17 libraries
-rw-r--r-- 1 root root 1127 Aug 2 22:17 log_output.html
-rw-r--r-- 1 root root 481 Aug 2 22:17 main.html
-rw-r--r-- 1 root root 759 Aug 2 22:17 offline_API_wrapper.js
-rw-r--r-- 1 root root 0 Aug 2 22:17 player
-rw-r--r-- 1 root root 1032 Aug 2 22:17 popup.html
root@93f0d2b9667f:/openedx/media/scorm/5e085cbc04e24b3b911802f7cba44296/92b12100be7651c812a1d29a041153db5ba89239# cd assets
bash: cd: assets: Not a directory