update: update storage struct
This commit is contained in:
@@ -395,9 +395,14 @@ async def create_script_record(
|
||||
# the legacy flow no longer applies. We still do a Scripts-only
|
||||
# conflict check on the user-supplied name so two scripts cannot
|
||||
# claim the same display name within the same workspace.
|
||||
user_id = context.user.user_id
|
||||
script_id = new_ulid()
|
||||
jupyter_name = _jupyter_path(script_type, script_id)
|
||||
nested_jupyter_name = f"{parent_ulid}/{jupyter_name}" if parent_ulid else jupyter_name
|
||||
jupyter_basename = _jupyter_path(script_type, script_id)
|
||||
# Jupyter path inside workspace root: {user_id}/{parent_or_self}/{basename}
|
||||
if parent_ulid:
|
||||
jupyter_path = f"{user_id}/{parent_ulid}/{jupyter_basename}"
|
||||
else:
|
||||
jupyter_path = f"{user_id}/{jupyter_basename}"
|
||||
name_clash = await session.scalar(
|
||||
select(Scripts.script_id).where(
|
||||
Scripts.workspace_id == context.workspace.workspace_id,
|
||||
@@ -421,7 +426,7 @@ async def create_script_record(
|
||||
size_bytes = len(content)
|
||||
if parent_ulid:
|
||||
try:
|
||||
await runtime_client.ensure_directory(workspace_id, parent_ulid)
|
||||
await runtime_client.ensure_directory(workspace_id, f"{user_id}/{parent_ulid}")
|
||||
except RuntimeClientError as exc:
|
||||
raise HTTPException(
|
||||
status_code=exc.status_code,
|
||||
@@ -434,15 +439,15 @@ async def create_script_record(
|
||||
logger.debug(notebook)
|
||||
jupyter_resp = await runtime_client.create_notebook(
|
||||
workspace_id,
|
||||
name=nested_jupyter_name,
|
||||
name=jupyter_path,
|
||||
cells=notebook.get("cells"),
|
||||
)
|
||||
else:
|
||||
jupyter_resp = await runtime_client.upload_file(
|
||||
workspace_id,
|
||||
name=nested_jupyter_name,
|
||||
name=jupyter_path,
|
||||
content=content.decode("utf-8"),
|
||||
content_type=(mimetypes.guess_type(jupyter_name)[0] or "text/plain"),
|
||||
content_type=(mimetypes.guess_type(jupyter_basename)[0] or "text/plain"),
|
||||
)
|
||||
logger.debug(jupyter_resp)
|
||||
except RuntimeClientError as exc:
|
||||
@@ -458,12 +463,12 @@ async def create_script_record(
|
||||
# file is queryable as a workspace file from the user's POV; the
|
||||
# storage_uri points at where the replicated bytes will land.
|
||||
object_id = new_ulid()
|
||||
object_key = f"{workspace_id}/{nested_jupyter_name}"
|
||||
object_key = f"{workspace_id}/{jupyter_path}"
|
||||
bucket_name = settings.s3_workspace_bucket
|
||||
relative_path = user_relative_path(
|
||||
context, f"{parent}/{jupyter_name}" if parent else jupyter_name
|
||||
context, f"{parent}/{jupyter_basename}" if parent else jupyter_basename
|
||||
)
|
||||
mime_type = mimetypes.guess_type(jupyter_name)[0]
|
||||
mime_type = mimetypes.guess_type(jupyter_basename)[0]
|
||||
storage_object = StorageObjects(
|
||||
storage_object_id=object_id,
|
||||
workspace_id=context.workspace.workspace_id,
|
||||
@@ -476,7 +481,7 @@ async def create_script_record(
|
||||
object_key_hash=hashlib.sha256(object_key.encode("utf-8")).digest(),
|
||||
storage_uri=build_storage_uri(bucket_name, object_key),
|
||||
file_name=name,
|
||||
file_extension=PurePosixPath(jupyter_name).suffix.lower() or None,
|
||||
file_extension=PurePosixPath(jupyter_basename).suffix.lower() or None,
|
||||
mime_type=mime_type,
|
||||
size_bytes=size_bytes,
|
||||
content_hash=content_hash,
|
||||
@@ -507,13 +512,13 @@ async def create_script_record(
|
||||
# Best-effort compensating cleanup: remove the Jupyter file we
|
||||
# just created so a failed flush does not leave an orphan on disk.
|
||||
try:
|
||||
await runtime_client.delete_file(workspace_id, name=nested_jupyter_name)
|
||||
await runtime_client.delete_file(workspace_id, name=jupyter_path)
|
||||
except RuntimeClientError as cleanup_exc:
|
||||
if cleanup_exc.status_code == 404:
|
||||
pass
|
||||
else:
|
||||
logger.warning(
|
||||
f"failed to clean up Jupyter file {nested_jupyter_name} "
|
||||
f"failed to clean up Jupyter file {jupyter_path} "
|
||||
f"after DB flush error: {cleanup_exc.status_code} {cleanup_exc.detail}"
|
||||
)
|
||||
raise
|
||||
@@ -813,13 +818,17 @@ async def create_workspace_directory(
|
||||
# the on-disk directory name match. Create the directory in Jupyter
|
||||
# before persisting the DB row; if persistence fails we clean up.
|
||||
dir_id = new_ulid()
|
||||
jupyter_path = f"{parent_ulid}/{dir_id}" if parent_ulid else dir_id
|
||||
user_id = context.user.user_id
|
||||
if parent_ulid:
|
||||
jupyter_path = f"{user_id}/{parent_ulid}/{dir_id}"
|
||||
else:
|
||||
jupyter_path = f"{user_id}/{dir_id}"
|
||||
runtime_client = request.app.state.runtime_client
|
||||
workspace_id = context.workspace.workspace_id
|
||||
|
||||
if parent_ulid:
|
||||
try:
|
||||
await runtime_client.ensure_directory(workspace_id, parent_ulid)
|
||||
await runtime_client.ensure_directory(workspace_id, f"{user_id}/{parent_ulid}")
|
||||
except RuntimeClientError as exc:
|
||||
raise HTTPException(
|
||||
status_code=exc.status_code,
|
||||
@@ -962,7 +971,7 @@ async def delete_workspace_directory(
|
||||
else:
|
||||
try:
|
||||
await runtime_client.delete_directory(
|
||||
workspace_id, name=descendant.storage_object_id
|
||||
workspace_id, name=f"{descendant.owner_user_id}/{descendant.storage_object_id}"
|
||||
)
|
||||
except RuntimeClientError as exc:
|
||||
if exc.status_code != 404:
|
||||
@@ -976,7 +985,7 @@ async def delete_workspace_directory(
|
||||
descendant.deleted_at = datetime.now(UTC).replace(tzinfo=None)
|
||||
|
||||
try:
|
||||
await runtime_client.delete_directory(workspace_id, name=target_ulid)
|
||||
await runtime_client.delete_directory(workspace_id, name=f"{context.user.user_id}/{target_ulid}")
|
||||
except RuntimeClientError as exc:
|
||||
if exc.status_code != 404:
|
||||
logger.warning(
|
||||
@@ -1044,26 +1053,25 @@ async def get_script_content(
|
||||
适用于被锁定的脚本,非所有者只能查看内容,不能编辑。
|
||||
该接口不检查锁状态,调用方需自行判断权限。
|
||||
"""
|
||||
script = await session.scalar(
|
||||
select(Scripts)
|
||||
.where(
|
||||
Scripts.script_id == script_id,
|
||||
Scripts.workspace_id == context.workspace.workspace_id,
|
||||
Scripts.status == "active",
|
||||
)
|
||||
script, storage_object = await get_script_row(
|
||||
script_id,
|
||||
context,
|
||||
session,
|
||||
allow_missing_storage_object=True,
|
||||
)
|
||||
if script is None:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, "script not found")
|
||||
|
||||
# 获取 Jupyter 路径
|
||||
jupyter_name = _jupyter_path(script.script_type, script.script_id)
|
||||
workspace_id = context.workspace.workspace_id
|
||||
jupyter_path = _derive_jupyter_path(
|
||||
storage_object, workspace_id, script.script_type, script.script_id
|
||||
)
|
||||
|
||||
# 从 Jupyter 读取内容
|
||||
runtime_client = request.app.state.runtime_client
|
||||
try:
|
||||
content_data = await runtime_client.get_file(
|
||||
context.workspace.workspace_id,
|
||||
name=jupyter_name,
|
||||
workspace_id,
|
||||
name=jupyter_path,
|
||||
)
|
||||
except RuntimeClientError as exc:
|
||||
raise HTTPException(
|
||||
|
||||
@@ -171,7 +171,7 @@ async def create_upload_record(
|
||||
# Jupyter selects its editor from this suffix, so an extensionless
|
||||
# object would make notebooks look like generic JSON/text files.
|
||||
file_extension = PurePosixPath(_safe_file_name(payload.file_name)).suffix.lower()
|
||||
object_key = f"{payload.workspace_id}/{new_ulid()}{file_extension}"
|
||||
object_key = f"{payload.workspace_id}/{payload.user_id}/{new_ulid()}{file_extension}"
|
||||
upload = UploadSessions(
|
||||
upload_id=new_ulid(),
|
||||
workspace_id=payload.workspace_id,
|
||||
|
||||
@@ -190,7 +190,7 @@ async def create_upload_record(
|
||||
# Jupyter selects its editor from this suffix, so an extensionless
|
||||
# object would make notebooks look like generic JSON/text files.
|
||||
file_extension = PurePosixPath(safe_file_name(payload.file_name)).suffix.lower()
|
||||
object_key = f"{payload.workspace_id}/{upload_id}{file_extension}"
|
||||
object_key = f"{payload.workspace_id}/{payload.user_id}/{upload_id}{file_extension}"
|
||||
upload = UploadSessions(
|
||||
upload_id=upload_id,
|
||||
workspace_id=payload.workspace_id,
|
||||
|
||||
Reference in New Issue
Block a user