refactor: delete table
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user