refactor: delete table

This commit is contained in:
tao.chen
2026-07-31 13:21:15 +08:00
parent f288c90d37
commit 28069f516b
9 changed files with 510 additions and 1074 deletions
+60 -60
View File
@@ -21,7 +21,6 @@ from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from common.db.models import (
EditSessions,
Scripts,
StorageObjects,
Versions,
@@ -227,24 +226,31 @@ async def get_script_row(
return script, storage_object
async def require_no_active_edit_session(
session: AsyncSession,
storage_object_ids: list[str],
def require_script_modify_access(
script: Scripts,
*,
user_id: str,
is_admin: bool,
) -> None:
if not storage_object_ids:
"""Enforce the V3.1 §4 access rules for write operations on a script.
Rules:
* admin: always allowed
* owner: always allowed
* non-owner: allowed iff ``is_locked`` is False
Reads (``list`` / ``get``) intentionally do not call this helper — the
design contract is "everyone in the workspace can see the script
list, but only the owner (or admin) can mutate when locked".
"""
if is_admin or script.owner_user_id == user_id:
return
active_session = await session.scalar(
select(EditSessions).where(
EditSessions.storage_object_id.in_(storage_object_ids),
EditSessions.session_status == "active",
EditSessions.expires_at > datetime.now(UTC).replace(tzinfo=None),
)
if not script.is_locked:
return
raise HTTPException(
status.HTTP_403_FORBIDDEN,
"script is locked; only the owner (or an administrator) may modify it",
)
if active_session is not None:
raise HTTPException(
status.HTTP_409_CONFLICT,
"file is being edited; end the editing session before deletion",
)
async def create_script_record(
@@ -542,10 +548,6 @@ async def delete_workspace_directory(
)
)
).all()
await require_no_active_edit_session(
session,
[script.current_object_id for script, _storage in rows],
)
for script, _storage in rows:
await request.app.state.storage_client.delete_object(
script.current_object_id
@@ -624,14 +626,11 @@ async def update_script(
session,
for_update=True,
)
if (
script.owner_user_id != context.user.user_id
and not context.is_admin
):
raise HTTPException(
status.HTTP_403_FORBIDDEN,
"script can only be changed by its owner or an administrator",
)
require_script_modify_access(
script,
user_id=context.user.user_id,
is_admin=context.is_admin,
)
content = validate_script_content(payload.content, script.script_type)
if not storage_object.relative_path:
raise HTTPException(
@@ -677,17 +676,10 @@ async def delete_script(
session,
for_update=True,
)
if (
script.owner_user_id != context.user.user_id
and not context.is_admin
):
raise HTTPException(
status.HTTP_403_FORBIDDEN,
"script can only be deleted by its owner or an administrator",
)
await require_no_active_edit_session(
session,
[script.current_object_id],
require_script_modify_access(
script,
user_id=context.user.user_id,
is_admin=context.is_admin,
)
await request.app.state.storage_client.delete_object(
script.current_object_id
@@ -722,14 +714,11 @@ async def publish_version(
session,
for_update=True,
)
if (
script.owner_user_id != context.user.user_id
and not context.is_admin
):
raise HTTPException(
status.HTTP_403_FORBIDDEN,
"script can only be published by its owner or an administrator",
)
require_script_modify_access(
script,
user_id=context.user.user_id,
is_admin=context.is_admin,
)
if (
payload.source_object_id
and payload.source_object_id != script.current_object_id
@@ -867,20 +856,31 @@ async def delete_version(
context: RequestContext = Depends(request_context),
session: AsyncSession = Depends(database_session),
) -> dict[str, Any]:
version = await session.get(Versions, versions_id)
if (
version is None
or version.workspace_id != context.workspace.workspace_id
):
raise HTTPException(status.HTTP_404_NOT_FOUND, "稳定版本不存在")
if (
version.created_by != context.user.user_id
and not context.is_admin
):
raise HTTPException(
status.HTTP_403_FORBIDDEN,
"仅稳定版本发布者或管理员可以删除",
# Join to Scripts so the lock + owner check rides on the script record,
# not on whoever happened to publish this specific version. Lock state
# is a property of the script as a whole (architecture V3.1 §4), not of
# any one version of it.
row = (
await session.execute(
select(Versions, Scripts)
.join(
Scripts,
Scripts.script_id == Versions.script_id,
)
.where(
Versions.versions_id == versions_id,
Versions.workspace_id == context.workspace.workspace_id,
)
)
).one_or_none()
if row is None:
raise HTTPException(status.HTTP_404_NOT_FOUND, "稳定版本不存在")
version, script = row
require_script_modify_access(
script,
user_id=context.user.user_id,
is_admin=context.is_admin,
)
version.schedule_hidden_at = datetime.now(UTC).replace(tzinfo=None)
await session.flush()