fix: storage and directories bug

This commit is contained in:
tao.chen
2026-08-12 20:18:29 +08:00
parent 0bcdbb1068
commit b1ceaeb173
5 changed files with 44 additions and 8 deletions
+19 -4
View File
@@ -16,6 +16,7 @@ from common.db.models import (
)
from common.ids import new_ulid
from common.storage.schemas import ServerObjectRequest
from common.storage import build_storage_uri
from fastapi import (
APIRouter,
BackgroundTasks,
@@ -89,6 +90,15 @@ def safe_directory_name(value: str) -> str:
return name
# Version/run artifacts are not part of the user's workspace directory tree.
TREE_EXCLUDED_USAGE_TYPES = (
"version_artifact",
"snapshot",
"run_log",
"run_result",
)
def user_relative_path(context: RequestContext, child_path: str = "") -> str:
base = f"users/{context.user.username}"
normalized = normalize_user_path(child_path)
@@ -464,7 +474,7 @@ async def create_script_record(
bucket_name=bucket_name,
object_key=object_key,
object_key_hash=hashlib.sha256(object_key.encode("utf-8")).digest(),
storage_uri=f"s3://{bucket_name}/{object_key}",
storage_uri=build_storage_uri(bucket_name, object_key),
file_name=name,
file_extension=PurePosixPath(jupyter_name).suffix.lower() or None,
mime_type=mime_type,
@@ -625,6 +635,7 @@ async def get_workspace_tree(
StorageObjects.object_status == "available",
StorageObjects.is_deleted == 0,
StorageObjects.relative_path.like(like_prefix),
StorageObjects.usage_type.notin_(TREE_EXCLUDED_USAGE_TYPES),
)
)
).all()
@@ -691,18 +702,20 @@ async def list_workspace_directories(
rows = (
await session.execute(
select(StorageObjects.relative_path, StorageObjects.object_type).where(
select(StorageObjects.relative_path).where(
StorageObjects.workspace_id == context.workspace.workspace_id,
StorageObjects.object_status == "available",
StorageObjects.is_deleted == 0,
StorageObjects.relative_path.like(f"{descendant_prefix}%"),
~StorageObjects.relative_path.like(f"{descendant_prefix}%/%"),
StorageObjects.object_type == "directory",
StorageObjects.usage_type.notin_(TREE_EXCLUDED_USAGE_TYPES),
)
)
).all()
directories: dict[str, dict[str, Any]] = {}
for relative, _object_type in rows:
for (relative,) in rows:
if not relative or not relative.startswith(descendant_prefix):
continue
suffix = relative[len(descendant_prefix) :]
@@ -720,7 +733,8 @@ async def list_workspace_directories(
)
for directory in directories.values():
child_prefix = f"{target_prefix}/{directory['path']}/"
# directory['path'] is already workspace-relative and includes the parent segment.
child_prefix = f"{scoped_prefix}/{directory['path']}/"
has_children = await session.scalar(
select(StorageObjects.storage_object_id).where(
StorageObjects.workspace_id == context.workspace.workspace_id,
@@ -728,6 +742,7 @@ async def list_workspace_directories(
StorageObjects.is_deleted == 0,
StorageObjects.relative_path.like(f"{child_prefix}%"),
~StorageObjects.relative_path.like(f"{child_prefix}%/%"),
StorageObjects.usage_type.notin_(TREE_EXCLUDED_USAGE_TYPES),
).limit(1)
)
directory["has_children"] = has_children is not None
+3 -2
View File
@@ -47,6 +47,7 @@ from common.storage.schemas import (
DownloadUrlRequest,
ServerObjectRequest,
)
from common.storage import build_storage_uri
# ── shared low-level helpers (module-private) ────────────────────────────
@@ -90,7 +91,7 @@ def _build_storage_object(
bucket_name=upload.bucket_name,
object_key=upload.object_key,
object_key_hash=upload.object_key_hash,
storage_uri=f"s3://{upload.bucket_name}/{upload.object_key}",
storage_uri=build_storage_uri(upload.bucket_name, upload.object_key),
file_name=safe_name,
file_extension=PurePosixPath(safe_name).suffix.lower() or None,
mime_type=content_type,
@@ -519,4 +520,4 @@ async def soft_delete_object(
"trash_key": item.trash_key,
"trash_bucket": settings.s3_trash_bucket,
}
}
}
+2 -2
View File
@@ -19,7 +19,7 @@ from common.db.models import (
Workspaces,
)
from common.ids import new_ulid
from common.storage import actual_bucket_name
from common.storage import actual_bucket_name, build_storage_uri
from common.storage.schemas import (
CreateUploadRequest,
DownloadUrlRequest,
@@ -350,7 +350,7 @@ async def upload_bytes_to_session(
bucket_name=upload.bucket_name,
object_key=upload.object_key,
object_key_hash=upload.object_key_hash,
storage_uri=f"s3://{upload.bucket_name}/{upload.object_key}",
storage_uri=build_storage_uri(upload.bucket_name, upload.object_key),
file_name=file_name,
file_extension=PurePosixPath(file_name).suffix.lower() or None,
mime_type=upload.content_type,