refactor(app): use soft delete for app shares via is_active flag

This commit is contained in:
wxy
2026-03-13 17:02:29 +08:00
parent aab54ca1a8
commit c7cc0cd922
2 changed files with 43 additions and 26 deletions

View File

@@ -1,6 +1,6 @@
import datetime import datetime
import uuid import uuid
from sqlalchemy import Column, DateTime, ForeignKey, String from sqlalchemy import Boolean, Column, DateTime, ForeignKey, String
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from app.db import Base from app.db import Base
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
@@ -19,6 +19,7 @@ class AppShare(Base):
target_workspace_id = Column(UUID(as_uuid=True), ForeignKey('workspaces.id'), nullable=False, comment="目标工作空间ID") target_workspace_id = Column(UUID(as_uuid=True), ForeignKey('workspaces.id'), nullable=False, comment="目标工作空间ID")
shared_by = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False, comment="分享者用户ID") shared_by = Column(UUID(as_uuid=True), ForeignKey('users.id'), nullable=False, comment="分享者用户ID")
permission = Column(String, default="readonly", nullable=False, comment="权限模式: readonly | editable") permission = Column(String, default="readonly", nullable=False, comment="权限模式: readonly | editable")
is_active = Column(Boolean, default=True, nullable=False, comment="是否有效False 表示逻辑删除")
created_at = Column(DateTime, default=datetime.datetime.now) created_at = Column(DateTime, default=datetime.datetime.now)
updated_at = Column(DateTime, default=datetime.datetime.now) updated_at = Column(DateTime, default=datetime.datetime.now)

View File

@@ -102,7 +102,8 @@ class AppService:
# 2. 检查是否是共享给本工作空间的应用 # 2. 检查是否是共享给本工作空间的应用
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app.id, AppShare.source_app_id == app.id,
AppShare.target_workspace_id == workspace_id AppShare.target_workspace_id == workspace_id,
AppShare.is_active.is_(True)
) )
share = self.db.scalars(stmt).first() share = self.db.scalars(stmt).first()
@@ -140,7 +141,8 @@ class AppService:
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app.id, AppShare.source_app_id == app.id,
AppShare.target_workspace_id == workspace_id AppShare.target_workspace_id == workspace_id,
AppShare.is_active.is_(True)
) )
share = self.db.scalars(stmt).first() share = self.db.scalars(stmt).first()
return share.permission if share else None return share.permission if share else None
@@ -509,7 +511,8 @@ class AppService:
from app.models import AppShare from app.models import AppShare
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app.id, AppShare.source_app_id == app.id,
AppShare.target_workspace_id == current_workspace_id AppShare.target_workspace_id == current_workspace_id,
AppShare.is_active.is_(True)
) )
share = self.db.scalars(stmt).first() share = self.db.scalars(stmt).first()
if share: if share:
@@ -933,20 +936,15 @@ class AppService:
# 只返回共享给本工作空间的应用,不含自有应用 # 只返回共享给本工作空间的应用,不含自有应用
shared_app_ids_stmt = ( shared_app_ids_stmt = (
select(AppShare.source_app_id) select(AppShare.source_app_id)
.where(AppShare.target_workspace_id == workspace_id) .where(AppShare.target_workspace_id == workspace_id, AppShare.is_active.is_(True))
) )
stmt = select(App).where(App.id.in_(shared_app_ids_stmt)) stmt = select(App).where(App.id.in_(shared_app_ids_stmt))
elif include_shared: elif include_shared:
# 查询本工作空间的应用 + 分享给本工作空间的应用 # 查询本工作空间的应用 + 分享给本工作空间的应用
# 使用 OR 条件workspace_id = current OR app_id IN (shared apps)
# 获取分享给本工作空间的应用ID列表
shared_app_ids_stmt = ( shared_app_ids_stmt = (
select(AppShare.source_app_id) select(AppShare.source_app_id)
.where(AppShare.target_workspace_id == workspace_id) .where(AppShare.target_workspace_id == workspace_id, AppShare.is_active.is_(True))
) )
# 构建主查询:本工作空间的应用 OR 分享的应用
stmt = select(App).where( stmt = select(App).where(
or_( or_(
App.workspace_id == workspace_id, App.workspace_id == workspace_id,
@@ -1801,7 +1799,8 @@ class AppService:
# 检查是否已经分享过 # 检查是否已经分享过
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app_id, AppShare.source_app_id == app_id,
AppShare.target_workspace_id == target_ws_id AppShare.target_workspace_id == target_ws_id,
AppShare.is_active.is_(True)
) )
existing_share = self.db.scalars(stmt).first() existing_share = self.db.scalars(stmt).first()
@@ -1880,7 +1879,8 @@ class AppService:
# 2. 查找分享记录 # 2. 查找分享记录
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app_id, AppShare.source_app_id == app_id,
AppShare.target_workspace_id == target_workspace_id AppShare.target_workspace_id == target_workspace_id,
AppShare.is_active.is_(True)
) )
share = self.db.scalars(stmt).first() share = self.db.scalars(stmt).first()
@@ -1894,8 +1894,8 @@ class AppService:
f"app_id={app_id}, target_workspace_id={target_workspace_id}" f"app_id={app_id}, target_workspace_id={target_workspace_id}"
) )
# 3. 删除分享记录 # 3. 逻辑删除分享记录
self.db.delete(share) share.is_active = False
self.db.commit() self.db.commit()
logger.info( logger.info(
@@ -1925,16 +1925,21 @@ class AppService:
extra={"target_workspace_id": str(target_workspace_id), "workspace_id": str(workspace_id)} extra={"target_workspace_id": str(target_workspace_id), "workspace_id": str(workspace_id)}
) )
# Query IDs first to get a reliable count, avoiding rowcount driver inconsistencies # Query active records first for reliable count
id_stmt = select(AppShare.id).where( id_stmt = select(AppShare.id).where(
AppShare.source_workspace_id == workspace_id, AppShare.source_workspace_id == workspace_id,
AppShare.target_workspace_id == target_workspace_id AppShare.target_workspace_id == target_workspace_id,
AppShare.is_active.is_(True)
) )
ids = list(self.db.scalars(id_stmt).all()) ids = list(self.db.scalars(id_stmt).all())
count = len(ids) count = len(ids)
if ids: if ids:
self.db.execute(delete(AppShare).where(AppShare.id.in_(ids))) # Soft delete: mark as inactive
from sqlalchemy import update as sa_update
self.db.execute(
sa_update(AppShare).where(AppShare.id.in_(ids)).values(is_active=False)
)
self.db.commit() self.db.commit()
logger.info("已取消分享记录数", extra={"count": count}) logger.info("已取消分享记录数", extra={"count": count})
@@ -1969,7 +1974,8 @@ class AppService:
# 查询分享记录 # 查询分享记录
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app_id AppShare.source_app_id == app_id,
AppShare.is_active.is_(True)
).order_by(AppShare.created_at.desc()) ).order_by(AppShare.created_at.desc())
shares = list(self.db.scalars(stmt).all()) shares = list(self.db.scalars(stmt).all())
@@ -2007,7 +2013,8 @@ class AppService:
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app_id, AppShare.source_app_id == app_id,
AppShare.target_workspace_id == workspace_id AppShare.target_workspace_id == workspace_id,
AppShare.is_active.is_(True)
) )
share = self.db.scalars(stmt).first() share = self.db.scalars(stmt).first()
@@ -2017,7 +2024,8 @@ class AppService:
f"app_id={app_id}, workspace_id={workspace_id}" f"app_id={app_id}, workspace_id={workspace_id}"
) )
self.db.delete(share) # Soft delete
share.is_active = False
self.db.commit() self.db.commit()
logger.info( logger.info(
@@ -2047,16 +2055,20 @@ class AppService:
extra={"source_workspace_id": str(source_workspace_id), "workspace_id": str(workspace_id)} extra={"source_workspace_id": str(source_workspace_id), "workspace_id": str(workspace_id)}
) )
# Query IDs first to get a reliable count, avoiding rowcount driver inconsistencies # Query active records for reliable count, then soft delete
id_stmt = select(AppShare.id).where( id_stmt = select(AppShare.id).where(
AppShare.source_workspace_id == source_workspace_id, AppShare.source_workspace_id == source_workspace_id,
AppShare.target_workspace_id == workspace_id AppShare.target_workspace_id == workspace_id,
AppShare.is_active.is_(True)
) )
ids = list(self.db.scalars(id_stmt).all()) ids = list(self.db.scalars(id_stmt).all())
count = len(ids) count = len(ids)
if ids: if ids:
self.db.execute(delete(AppShare).where(AppShare.id.in_(ids))) from sqlalchemy import update as sa_update
self.db.execute(
sa_update(AppShare).where(AppShare.id.in_(ids)).values(is_active=False)
)
self.db.commit() self.db.commit()
logger.info("已移除共享记录数", extra={"count": count}) logger.info("已移除共享记录数", extra={"count": count})
@@ -2076,7 +2088,10 @@ class AppService:
stmt = ( stmt = (
select(AppShare) select(AppShare)
.where(AppShare.source_workspace_id == workspace_id) .where(
AppShare.source_workspace_id == workspace_id,
AppShare.is_active.is_(True)
)
.order_by(AppShare.created_at.desc()) .order_by(AppShare.created_at.desc())
) )
return list(self.db.scalars(stmt).all()) return list(self.db.scalars(stmt).all())
@@ -2109,7 +2124,8 @@ class AppService:
stmt = select(AppShare).where( stmt = select(AppShare).where(
AppShare.source_app_id == app_id, AppShare.source_app_id == app_id,
AppShare.target_workspace_id == target_workspace_id AppShare.target_workspace_id == target_workspace_id,
AppShare.is_active.is_(True)
) )
share = self.db.scalars(stmt).first() share = self.db.scalars(stmt).first()