async def get_folder_by_path(sid: str, folder): user = asset_state.get_user(sid) folder = folder.strip("/") target_folder = Asset.get_root_folder(user) id_path = [] if folder: for path in folder.split("/"): try: target_folder = target_folder.get_child(path) id_path.append(target_folder.id) except Asset.DoesNotExist: return await get_folder_by_path(sid, "/") await sio.emit( "Folder.Set", { "folder": target_folder.as_dict(children=True), "path": id_path }, room=sid, namespace=ASSET_NS, )
async def handle_paa_file(upload_data: UploadData, data: bytes, sid: str): with tempfile.TemporaryDirectory() as tmpdir: with tarfile.open(fileobj=io.BytesIO(data), mode="r:bz2") as tar: files = tarfile.TarInfo("files") files.type = tarfile.DIRTYPE # We need to explicitly list our members for security reasons # this is upload data so people could upload malicious stuff that breaks out of the path etc tar.extractall( path=tmpdir, members=get_safe_members(tar.getmembers(), tmpdir) ) tmp_path = Path(tmpdir) for asset in os.listdir(tmp_path / "files"): if not (ASSETS_DIR / asset).exists(): shutil.move(str(tmp_path / "files" / asset), str(ASSETS_DIR / asset)) with open(tmp_path / "data") as json_data: raw_assets: List[AssetDict] = json.load(json_data) user = asset_state.get_user(sid) parent_map: Dict[int, int] = defaultdict(lambda: upload_data["directory"]) for raw_asset in raw_assets: new_asset = Asset.create( name=raw_asset["name"], file_hash=raw_asset["file_hash"], owner=user, parent=parent_map[raw_asset["parent"]], options=raw_asset["options"], ) parent_map[raw_asset["id"]] = new_asset.id await sio.emit( "Asset.Import.Finish", upload_data["name"], room=sid, namespace=ASSET_NS )
async def assetmgmt_upload(sid: str, upload_data: UploadData): uuid = upload_data["uuid"] if uuid not in asset_state.pending_file_upload_cache: asset_state.pending_file_upload_cache[uuid] = {} asset_state.pending_file_upload_cache[uuid][upload_data["slice"]] = upload_data if len(asset_state.pending_file_upload_cache[uuid]) != upload_data["totalSlices"]: # wait for the rest of the slices return # All slices are present data = b"" for slice_ in range(upload_data["totalSlices"]): data += asset_state.pending_file_upload_cache[uuid][slice_]["data"] del asset_state.pending_file_upload_cache[upload_data["uuid"]] file_name = upload_data["name"] if file_name.endswith(".paa"): await handle_paa_file(upload_data, data, sid) elif file_name.endswith(".dd2vtt"): await handle_ddraft_file(upload_data, data, sid) else: await handle_regular_file(upload_data, data, sid) user = asset_state.get_user(sid) await update_live_game(user)
async def create_folder(sid: str, data): user = asset_state.get_user(sid) parent = data.get("parent", None) if parent is None: parent = Asset.get_root_folder(user) asset = Asset.create(name=data["name"], owner=user, parent=parent) await sio.emit("Folder.Create", asset.as_dict(), room=sid, namespace=ASSET_NS)
async def assetmgmt_rename(sid: str, data): user = asset_state.get_user(sid) asset = Asset.get_by_id(data["asset"]) if asset.owner != user: logger.warning(f"{user.name} attempted to rename a file it doesn't own.") return asset.name = data["name"] asset.save()
async def move_inode(sid: str, data): user = asset_state.get_user(sid) target = data.get("target", None) if target is None: target = Asset.get_root_folder(user) asset = Asset[data["inode"]] if asset.owner != user: logger.warning(f"{user.name} attempted to move files it doesn't own.") return asset.parent = target asset.save()
async def assetmgmt_rm(sid: str, data): user = asset_state.get_user(sid) asset = Asset.get_by_id(data) if asset.owner != user: logger.warning(f"{user.name} attempted to remove a file it doesn't own.") return asset.delete_instance(recursive=True, delete_nullable=True) if asset.file_hash is not None and (ASSETS_DIR / asset.file_hash).exists(): if Asset.select().where(Asset.file_hash == asset.file_hash).count() == 0: logger.info( f"No asset maps to file {asset.file_hash}, removing from server" ) (ASSETS_DIR / asset.file_hash).unlink()
async def get_folder(sid: str, folder=None): user = asset_state.get_user(sid) if folder is None: folder = Asset.get_root_folder(user) else: folder = Asset[folder] if folder.owner != user: raise web.HTTPForbidden await sio.emit( "Folder.Set", {"folder": folder.as_dict(children=True)}, room=sid, namespace=ASSET_NS, )
async def handle_regular_file(upload_data: UploadData, data: bytes, sid: str): sh = hashlib.sha1(data) hashname = sh.hexdigest() if not (ASSETS_DIR / hashname).exists(): with open(ASSETS_DIR / hashname, "wb") as f: f.write(data) user = asset_state.get_user(sid) asset = Asset.create( name=upload_data["name"], file_hash=hashname, owner=user, parent=upload_data["directory"], ) await sio.emit("Asset.Upload.Finish", asset.as_dict(), room=sid, namespace=ASSET_NS)
async def assetmgmt_upload(sid: str, file_data): uuid = file_data["uuid"] if uuid not in asset_state.pending_file_upload_cache: asset_state.pending_file_upload_cache[uuid] = {} asset_state.pending_file_upload_cache[uuid][file_data["slice"]] = file_data if len(asset_state.pending_file_upload_cache[uuid] ) != file_data["totalSlices"]: # wait for the rest of the slices return # All slices are present data = b"" for slice_ in range(file_data["totalSlices"]): data += asset_state.pending_file_upload_cache[uuid][slice_]["data"] sh = hashlib.sha1(data) hashname = sh.hexdigest() if not (ASSETS_DIR / hashname).exists(): with open(ASSETS_DIR / hashname, "wb") as f: f.write(data) del asset_state.pending_file_upload_cache[uuid] user = asset_state.get_user(sid) asset = Asset.create( name=file_data["name"], file_hash=hashname, owner=user, parent=file_data["directory"], ) await sio.emit("Asset.Upload.Finish", asset.as_dict(), room=sid, namespace=ASSET_NS)
async def handle_ddraft_file(upload_data: UploadData, data: bytes, sid: str): ddraft_file: DDraftData = json.loads(data) image = base64.b64decode(ddraft_file["image"]) sh = hashlib.sha1(image) hashname = sh.hexdigest() if not (ASSETS_DIR / hashname).exists(): with open(ASSETS_DIR / hashname, "wb") as f: f.write(image) template = { "version": "0", "shape": "assetrect", "templates": { "default": { "options": json.dumps([[f"ddraft_{k}", v] for k, v in ddraft_file.items() if k != "image"]) } }, } user = asset_state.get_user(sid) asset = Asset.create( name=upload_data["name"], file_hash=hashname, owner=user, parent=upload_data["directory"], options=json.dumps(template), ) await sio.emit("Asset.Upload.Finish", asset.as_dict(), room=sid, namespace=ASSET_NS)