style: normalize python formatting gates
This commit is contained in:
@@ -1,53 +1,54 @@
|
||||
"""Workspace 相关 Use Cases"""
|
||||
from packages.application.workspace.create_workspace_use_case import (
|
||||
CreateWorkspaceUseCase,
|
||||
CreateWorkspaceRequest,
|
||||
CreateWorkspaceResponse,
|
||||
)
|
||||
from packages.application.workspace.invite_member_use_case import (
|
||||
InviteMemberUseCase,
|
||||
InviteMemberRequest,
|
||||
InviteMemberResponse,
|
||||
)
|
||||
|
||||
from packages.application.workspace.accept_invitation_use_case import (
|
||||
AcceptInvitationUseCase,
|
||||
AcceptInvitationRequest,
|
||||
AcceptInvitationResponse,
|
||||
DeclineInvitationUseCase,
|
||||
AcceptInvitationUseCase,
|
||||
DeclineInvitationRequest,
|
||||
DeclineInvitationUseCase,
|
||||
)
|
||||
from packages.application.workspace.remove_member_use_case import (
|
||||
RemoveMemberUseCase,
|
||||
RemoveMemberRequest,
|
||||
LeaveWorkspaceUseCase,
|
||||
LeaveWorkspaceRequest,
|
||||
from packages.application.workspace.create_workspace_use_case import (
|
||||
CreateWorkspaceRequest,
|
||||
CreateWorkspaceResponse,
|
||||
CreateWorkspaceUseCase,
|
||||
)
|
||||
from packages.application.workspace.update_member_role_use_case import (
|
||||
UpdateMemberRoleUseCase,
|
||||
UpdateMemberRoleRequest,
|
||||
UpdateMemberRoleResponse,
|
||||
)
|
||||
from packages.application.workspace.list_workspaces_use_case import (
|
||||
ListWorkspacesUseCase,
|
||||
ListWorkspacesRequest,
|
||||
ListWorkspacesResponse,
|
||||
GetWorkspaceDetailUseCase,
|
||||
GetWorkspaceDetailRequest,
|
||||
WorkspaceInfo,
|
||||
WorkspaceDetailInfo,
|
||||
from packages.application.workspace.invite_member_use_case import (
|
||||
InviteMemberRequest,
|
||||
InviteMemberResponse,
|
||||
InviteMemberUseCase,
|
||||
)
|
||||
from packages.application.workspace.list_members_use_case import (
|
||||
ListMembersUseCase,
|
||||
ListMembersRequest,
|
||||
ListMembersResponse,
|
||||
ListMembersUseCase,
|
||||
MemberInfo,
|
||||
)
|
||||
from packages.application.workspace.list_workspaces_use_case import (
|
||||
GetWorkspaceDetailRequest,
|
||||
GetWorkspaceDetailUseCase,
|
||||
ListWorkspacesRequest,
|
||||
ListWorkspacesResponse,
|
||||
ListWorkspacesUseCase,
|
||||
WorkspaceDetailInfo,
|
||||
WorkspaceInfo,
|
||||
)
|
||||
from packages.application.workspace.remove_member_use_case import (
|
||||
LeaveWorkspaceRequest,
|
||||
LeaveWorkspaceUseCase,
|
||||
RemoveMemberRequest,
|
||||
RemoveMemberUseCase,
|
||||
)
|
||||
from packages.application.workspace.subscription_use_case import (
|
||||
UpgradeSubscriptionUseCase,
|
||||
CancelSubscriptionRequest,
|
||||
CancelSubscriptionUseCase,
|
||||
UpgradeSubscriptionRequest,
|
||||
UpgradeSubscriptionResponse,
|
||||
CancelSubscriptionUseCase,
|
||||
CancelSubscriptionRequest,
|
||||
UpgradeSubscriptionUseCase,
|
||||
)
|
||||
from packages.application.workspace.update_member_role_use_case import (
|
||||
UpdateMemberRoleRequest,
|
||||
UpdateMemberRoleResponse,
|
||||
UpdateMemberRoleUseCase,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
"""
|
||||
接受/拒绝邀请 Use Case
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from packages.domain.entities import (
|
||||
WorkspaceMember,
|
||||
InvitationStatus,
|
||||
)
|
||||
from packages.domain.entities import InvitationStatus, WorkspaceMember
|
||||
|
||||
|
||||
class AcceptInvitationRequest:
|
||||
"""接受邀请请求"""
|
||||
|
||||
|
||||
def __init__(self, invitation_token: str, user_id: str):
|
||||
self.invitation_token = invitation_token
|
||||
self.user_id = user_id
|
||||
@@ -21,7 +19,7 @@ class AcceptInvitationRequest:
|
||||
|
||||
class AcceptInvitationResponse:
|
||||
"""接受邀请响应"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -35,7 +33,7 @@ class AcceptInvitationResponse:
|
||||
|
||||
class AcceptInvitationUseCase:
|
||||
"""接受邀请用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -47,14 +45,14 @@ class AcceptInvitationUseCase:
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
self.workspace_invitation_repository = workspace_invitation_repository
|
||||
self.user_repository = user_repository
|
||||
|
||||
|
||||
def execute(self, request: AcceptInvitationRequest) -> tuple[Optional[AcceptInvitationResponse], Optional[str]]:
|
||||
"""
|
||||
执行接受邀请
|
||||
|
||||
|
||||
Args:
|
||||
request: 接受请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -62,40 +60,40 @@ class AcceptInvitationUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.invitation_token:
|
||||
return None, "Invitation token is required"
|
||||
|
||||
|
||||
if not request.user_id:
|
||||
return None, "User ID is required"
|
||||
|
||||
|
||||
# 2. 查找邀请
|
||||
invitation = self.workspace_invitation_repository.find_by_token(request.invitation_token)
|
||||
if not invitation:
|
||||
return None, "Invalid invitation token"
|
||||
|
||||
|
||||
# 3. 检查邀请状态
|
||||
if invitation.status != InvitationStatus.PENDING:
|
||||
return None, f"Invitation has already been {invitation.status}"
|
||||
|
||||
|
||||
# 4. 检查是否过期
|
||||
if invitation.expires_at and datetime.now(timezone.utc) > invitation.expires_at:
|
||||
# 更新状态为过期
|
||||
invitation.status = InvitationStatus.EXPIRED
|
||||
self.workspace_invitation_repository.save(invitation)
|
||||
return None, "Invitation has expired"
|
||||
|
||||
|
||||
# 5. 验证用户存在
|
||||
user = self.user_repository.find_by_id(request.user_id)
|
||||
if not user:
|
||||
return None, "User not found"
|
||||
|
||||
|
||||
# 6. 验证用户邮箱匹配
|
||||
if user.email.lower() != invitation.invitee_email.lower():
|
||||
return None, "This invitation is for a different email address"
|
||||
|
||||
|
||||
# 7. 验证 Workspace 存在
|
||||
workspace = self.workspace_repository.find_by_id(invitation.workspace_id)
|
||||
if not workspace:
|
||||
return None, "Workspace not found"
|
||||
|
||||
|
||||
# 8. 检查用户是否已经是成员
|
||||
existing_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
invitation.workspace_id,
|
||||
@@ -106,13 +104,16 @@ class AcceptInvitationUseCase:
|
||||
invitation.status = InvitationStatus.ACCEPTED
|
||||
invitation.accepted_at = datetime.now(timezone.utc)
|
||||
self.workspace_invitation_repository.save(invitation)
|
||||
|
||||
return AcceptInvitationResponse(
|
||||
workspace_id=workspace.id,
|
||||
workspace_name=workspace.name,
|
||||
role=existing_member.role,
|
||||
), None
|
||||
|
||||
|
||||
return (
|
||||
AcceptInvitationResponse(
|
||||
workspace_id=workspace.id,
|
||||
workspace_name=workspace.name,
|
||||
role=existing_member.role,
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
# 9. 创建成员记录
|
||||
member = WorkspaceMember(
|
||||
id=uuid4().hex,
|
||||
@@ -122,45 +123,48 @@ class AcceptInvitationUseCase:
|
||||
invited_by=invitation.inviter_user_id,
|
||||
joined_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
self.workspace_member_repository.save(member)
|
||||
|
||||
|
||||
# 10. 更新邀请状态
|
||||
invitation.status = InvitationStatus.ACCEPTED
|
||||
invitation.accepted_at = datetime.now(timezone.utc)
|
||||
self.workspace_invitation_repository.save(invitation)
|
||||
|
||||
|
||||
# 11. 返回响应
|
||||
return AcceptInvitationResponse(
|
||||
workspace_id=workspace.id,
|
||||
workspace_name=workspace.name,
|
||||
role=member.role,
|
||||
), None
|
||||
|
||||
return (
|
||||
AcceptInvitationResponse(
|
||||
workspace_id=workspace.id,
|
||||
workspace_name=workspace.name,
|
||||
role=member.role,
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to accept invitation: {str(e)}"
|
||||
|
||||
|
||||
class DeclineInvitationRequest:
|
||||
"""拒绝邀请请求"""
|
||||
|
||||
|
||||
def __init__(self, invitation_token: str):
|
||||
self.invitation_token = invitation_token
|
||||
|
||||
|
||||
class DeclineInvitationUseCase:
|
||||
"""拒绝邀请用例"""
|
||||
|
||||
|
||||
def __init__(self, workspace_invitation_repository):
|
||||
self.workspace_invitation_repository = workspace_invitation_repository
|
||||
|
||||
|
||||
def execute(self, request: DeclineInvitationRequest) -> tuple[bool, Optional[str]]:
|
||||
"""
|
||||
执行拒绝邀请
|
||||
|
||||
|
||||
Args:
|
||||
request: 拒绝请求
|
||||
|
||||
|
||||
Returns:
|
||||
(是否成功, 错误信息)
|
||||
"""
|
||||
@@ -168,21 +172,21 @@ class DeclineInvitationUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.invitation_token:
|
||||
return False, "Invitation token is required"
|
||||
|
||||
|
||||
# 2. 查找邀请
|
||||
invitation = self.workspace_invitation_repository.find_by_token(request.invitation_token)
|
||||
if not invitation:
|
||||
return False, "Invalid invitation token"
|
||||
|
||||
|
||||
# 3. 检查邀请状态
|
||||
if invitation.status != InvitationStatus.PENDING:
|
||||
return False, f"Invitation has already been {invitation.status}"
|
||||
|
||||
|
||||
# 4. 更新状态为已拒绝
|
||||
invitation.status = InvitationStatus.DECLINED
|
||||
self.workspace_invitation_repository.save(invitation)
|
||||
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Failed to decline invitation: {str(e)}"
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
"""
|
||||
创建 Workspace Use Case
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
from uuid import uuid4
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from packages.domain.entities import Workspace, WorkspaceMember, WorkspaceMemberRole
|
||||
|
||||
|
||||
class CreateWorkspaceRequest:
|
||||
"""创建工作空间请求"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
@@ -24,7 +25,7 @@ class CreateWorkspaceRequest:
|
||||
|
||||
class CreateWorkspaceResponse:
|
||||
"""创建工作空间响应"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -42,14 +43,14 @@ class CreateWorkspaceResponse:
|
||||
|
||||
class CreateWorkspaceUseCase:
|
||||
"""创建工作空间用例"""
|
||||
|
||||
|
||||
# 订阅计划配额配置
|
||||
PLAN_QUOTAS = {
|
||||
"free": {"max_projects": 3, "max_storage_gb": 10},
|
||||
"pro": {"max_projects": 999999, "max_storage_gb": 100}, # 999999 表示无限
|
||||
"enterprise": {"max_projects": 999999, "max_storage_gb": 1000},
|
||||
}
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -59,14 +60,14 @@ class CreateWorkspaceUseCase:
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
self.user_repository = user_repository
|
||||
|
||||
|
||||
def execute(self, request: CreateWorkspaceRequest) -> tuple[Optional[CreateWorkspaceResponse], Optional[str]]:
|
||||
"""
|
||||
执行创建工作空间
|
||||
|
||||
|
||||
Args:
|
||||
request: 创建请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -74,25 +75,25 @@ class CreateWorkspaceUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.name:
|
||||
return None, "Workspace name is required"
|
||||
|
||||
|
||||
if len(request.name) > 100:
|
||||
return None, "Workspace name is too long (max 100 characters)"
|
||||
|
||||
|
||||
if not request.owner_user_id:
|
||||
return None, "Owner user ID is required"
|
||||
|
||||
|
||||
# 2. 验证用户存在
|
||||
owner = self.user_repository.find_by_id(request.owner_user_id)
|
||||
if not owner:
|
||||
return None, "Owner user not found"
|
||||
|
||||
|
||||
# 3. 验证订阅计划
|
||||
if request.subscription_plan not in self.PLAN_QUOTAS:
|
||||
return None, f"Invalid subscription plan: {request.subscription_plan}"
|
||||
|
||||
|
||||
# 4. 获取配额
|
||||
quota = self.PLAN_QUOTAS[request.subscription_plan]
|
||||
|
||||
|
||||
# 5. 创建 Workspace
|
||||
workspace = Workspace(
|
||||
id=uuid4().hex,
|
||||
@@ -105,10 +106,10 @@ class CreateWorkspaceUseCase:
|
||||
used_storage_gb=0.0,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
# 6. 保存 Workspace
|
||||
self.workspace_repository.save(workspace)
|
||||
|
||||
|
||||
# 7. 创建 Owner 成员记录
|
||||
owner_member = WorkspaceMember(
|
||||
id=uuid4().hex,
|
||||
@@ -118,17 +119,20 @@ class CreateWorkspaceUseCase:
|
||||
invited_by=None, # Owner 不需要邀请
|
||||
joined_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
self.workspace_member_repository.save(owner_member)
|
||||
|
||||
|
||||
# 8. 返回响应
|
||||
return CreateWorkspaceResponse(
|
||||
workspace_id=workspace.id,
|
||||
name=workspace.name,
|
||||
subscription_plan=workspace.subscription_plan,
|
||||
max_projects=workspace.max_projects,
|
||||
max_storage_gb=workspace.max_storage_gb,
|
||||
), None
|
||||
|
||||
return (
|
||||
CreateWorkspaceResponse(
|
||||
workspace_id=workspace.id,
|
||||
name=workspace.name,
|
||||
subscription_plan=workspace.subscription_plan,
|
||||
max_projects=workspace.max_projects,
|
||||
max_storage_gb=workspace.max_storage_gb,
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to create workspace: {str(e)}"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
邀请成员到 Workspace Use Case
|
||||
"""
|
||||
|
||||
import secrets
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional
|
||||
@@ -8,15 +9,15 @@ from uuid import uuid4
|
||||
|
||||
from packages.adapters.smtp import get_email_service
|
||||
from packages.domain.entities import (
|
||||
InvitationStatus,
|
||||
WorkspaceInvitation,
|
||||
WorkspaceMemberRole,
|
||||
InvitationStatus,
|
||||
)
|
||||
|
||||
|
||||
class InviteMemberRequest:
|
||||
"""邀请成员请求"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -32,7 +33,7 @@ class InviteMemberRequest:
|
||||
|
||||
class InviteMemberResponse:
|
||||
"""邀请成员响应"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
invitation_id: str,
|
||||
@@ -48,13 +49,13 @@ class InviteMemberResponse:
|
||||
|
||||
class InviteMemberUseCase:
|
||||
"""邀请成员用例"""
|
||||
|
||||
|
||||
VALID_ROLES = [
|
||||
WorkspaceMemberRole.ADMIN,
|
||||
WorkspaceMemberRole.MEMBER,
|
||||
WorkspaceMemberRole.VIEWER,
|
||||
]
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -72,14 +73,14 @@ class InviteMemberUseCase:
|
||||
self.base_url = base_url
|
||||
self.invitation_expire_days = invitation_expire_days
|
||||
self.email_service = email_service or get_email_service()
|
||||
|
||||
|
||||
def execute(self, request: InviteMemberRequest) -> tuple[Optional[InviteMemberResponse], Optional[str]]:
|
||||
"""
|
||||
执行邀请成员
|
||||
|
||||
|
||||
Args:
|
||||
request: 邀请请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -87,25 +88,25 @@ class InviteMemberUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return None, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.inviter_user_id:
|
||||
return None, "Inviter user ID is required"
|
||||
|
||||
|
||||
if not request.invitee_email:
|
||||
return None, "Invitee email is required"
|
||||
|
||||
|
||||
if not request.role:
|
||||
return None, "Role is required"
|
||||
|
||||
|
||||
# 2. 验证角色(不能邀请 owner)
|
||||
if request.role not in self.VALID_ROLES:
|
||||
return None, f"Invalid role: {request.role}. Cannot invite as owner."
|
||||
|
||||
|
||||
# 3. 验证 Workspace 存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return None, "Workspace not found"
|
||||
|
||||
|
||||
# 4. 验证邀请人是成员且有权限(owner 或 admin)
|
||||
inviter_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -113,10 +114,13 @@ class InviteMemberUseCase:
|
||||
)
|
||||
if not inviter_member:
|
||||
return None, "You are not a member of this workspace"
|
||||
|
||||
if inviter_member.role not in [WorkspaceMemberRole.OWNER, WorkspaceMemberRole.ADMIN]:
|
||||
|
||||
if inviter_member.role not in [
|
||||
WorkspaceMemberRole.OWNER,
|
||||
WorkspaceMemberRole.ADMIN,
|
||||
]:
|
||||
return None, "Only owners and admins can invite members"
|
||||
|
||||
|
||||
# 5. 检查被邀请人是否已经是成员
|
||||
invitee_user = self.user_repository.find_by_email(request.invitee_email)
|
||||
if invitee_user:
|
||||
@@ -126,7 +130,7 @@ class InviteMemberUseCase:
|
||||
)
|
||||
if existing_member:
|
||||
return None, "User is already a member of this workspace"
|
||||
|
||||
|
||||
# 6. 检查是否已有待处理的邀请
|
||||
existing_invitation = self.workspace_invitation_repository.find_pending_by_workspace_and_email(
|
||||
request.workspace_id,
|
||||
@@ -134,11 +138,11 @@ class InviteMemberUseCase:
|
||||
)
|
||||
if existing_invitation:
|
||||
return None, "An invitation has already been sent to this email"
|
||||
|
||||
|
||||
# 7. 生成邀请令牌
|
||||
invitation_token = secrets.token_urlsafe(32)
|
||||
expires_at = datetime.now(timezone.utc) + timedelta(days=self.invitation_expire_days)
|
||||
|
||||
|
||||
# 8. 创建邀请记录
|
||||
invitation = WorkspaceInvitation(
|
||||
id=uuid4().hex,
|
||||
@@ -151,17 +155,17 @@ class InviteMemberUseCase:
|
||||
expires_at=expires_at,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
# 9. 保存邀请
|
||||
self.workspace_invitation_repository.save(invitation)
|
||||
|
||||
|
||||
# 10. 发送邀请邮件
|
||||
invitation_url = f"{self.base_url}/invitations/{invitation_token}/accept"
|
||||
|
||||
|
||||
try:
|
||||
inviter = self.user_repository.find_by_id(request.inviter_user_id)
|
||||
inviter_name = inviter.display_name if inviter else "Someone"
|
||||
|
||||
|
||||
success, error = self.email_service.send_workspace_invitation_email(
|
||||
to_email=request.invitee_email,
|
||||
inviter_name=inviter_name,
|
||||
@@ -169,19 +173,22 @@ class InviteMemberUseCase:
|
||||
role=request.role,
|
||||
invitation_url=invitation_url,
|
||||
)
|
||||
|
||||
|
||||
if not success:
|
||||
print(f"Failed to send invitation email: {error}")
|
||||
except Exception as e:
|
||||
print(f"Email service error: {e}")
|
||||
|
||||
|
||||
# 11. 返回响应
|
||||
return InviteMemberResponse(
|
||||
invitation_id=invitation.id,
|
||||
invitee_email=invitation.invitee_email,
|
||||
role=invitation.role,
|
||||
expires_at=invitation.expires_at,
|
||||
), None
|
||||
|
||||
return (
|
||||
InviteMemberResponse(
|
||||
invitation_id=invitation.id,
|
||||
invitee_email=invitation.invitee_email,
|
||||
role=invitation.role,
|
||||
expires_at=invitation.expires_at,
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to invite member: {str(e)}"
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
"""
|
||||
获取成员列表 Use Case
|
||||
"""
|
||||
from typing import Optional, List
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class MemberInfo:
|
||||
"""成员信息"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
member_id: str,
|
||||
@@ -31,7 +32,7 @@ class MemberInfo:
|
||||
|
||||
class ListMembersRequest:
|
||||
"""获取成员列表请求"""
|
||||
|
||||
|
||||
def __init__(self, workspace_id: str, requester_user_id: str):
|
||||
self.workspace_id = workspace_id
|
||||
self.requester_user_id = requester_user_id
|
||||
@@ -39,14 +40,14 @@ class ListMembersRequest:
|
||||
|
||||
class ListMembersResponse:
|
||||
"""获取成员列表响应"""
|
||||
|
||||
|
||||
def __init__(self, members: List[MemberInfo]):
|
||||
self.members = members
|
||||
|
||||
|
||||
class ListMembersUseCase:
|
||||
"""获取成员列表用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -56,14 +57,14 @@ class ListMembersUseCase:
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
self.user_repository = user_repository
|
||||
|
||||
|
||||
def execute(self, request: ListMembersRequest) -> tuple[Optional[ListMembersResponse], Optional[str]]:
|
||||
"""
|
||||
执行获取成员列表
|
||||
|
||||
|
||||
Args:
|
||||
request: 请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -71,15 +72,15 @@ class ListMembersUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return None, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.requester_user_id:
|
||||
return None, "Requester user ID is required"
|
||||
|
||||
|
||||
# 2. 验证工作空间存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return None, "Workspace not found"
|
||||
|
||||
|
||||
# 3. 验证请求者是成员(只有成员才能查看成员列表)
|
||||
requester_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -87,17 +88,17 @@ class ListMembersUseCase:
|
||||
)
|
||||
if not requester_member:
|
||||
return None, "You are not a member of this workspace"
|
||||
|
||||
|
||||
# 4. 获取所有成员
|
||||
members = self.workspace_member_repository.find_by_workspace(request.workspace_id)
|
||||
|
||||
|
||||
# 5. 获取每个成员的用户信息
|
||||
member_infos = []
|
||||
for member in members:
|
||||
user = self.user_repository.find_by_id(member.user_id)
|
||||
if not user:
|
||||
continue # 跳过不存在的用户
|
||||
|
||||
|
||||
member_info = MemberInfo(
|
||||
member_id=member.id,
|
||||
user_id=user.id,
|
||||
@@ -109,9 +110,9 @@ class ListMembersUseCase:
|
||||
joined_at=member.joined_at,
|
||||
)
|
||||
member_infos.append(member_info)
|
||||
|
||||
|
||||
# 6. 返回响应
|
||||
return ListMembersResponse(members=member_infos), None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to list members: {str(e)}"
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
"""
|
||||
获取工作空间列表和详情 Use Case
|
||||
"""
|
||||
from typing import Optional, List
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class WorkspaceInfo:
|
||||
"""工作空间信息"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -37,21 +38,21 @@ class WorkspaceInfo:
|
||||
|
||||
class ListWorkspacesRequest:
|
||||
"""获取工作空间列表请求"""
|
||||
|
||||
|
||||
def __init__(self, user_id: str):
|
||||
self.user_id = user_id
|
||||
|
||||
|
||||
class ListWorkspacesResponse:
|
||||
"""获取工作空间列表响应"""
|
||||
|
||||
|
||||
def __init__(self, workspaces: List[WorkspaceInfo]):
|
||||
self.workspaces = workspaces
|
||||
|
||||
|
||||
class ListWorkspacesUseCase:
|
||||
"""获取工作空间列表用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -59,14 +60,14 @@ class ListWorkspacesUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
|
||||
def execute(self, request: ListWorkspacesRequest) -> tuple[Optional[ListWorkspacesResponse], Optional[str]]:
|
||||
"""
|
||||
执行获取工作空间列表
|
||||
|
||||
|
||||
Args:
|
||||
request: 请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -74,20 +75,20 @@ class ListWorkspacesUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.user_id:
|
||||
return None, "User ID is required"
|
||||
|
||||
|
||||
# 2. 获取用户所有的成员记录
|
||||
memberships = self.workspace_member_repository.find_by_user(request.user_id)
|
||||
|
||||
|
||||
# 3. 获取每个工作空间的信息
|
||||
workspace_infos = []
|
||||
for membership in memberships:
|
||||
workspace = self.workspace_repository.find_by_id(membership.workspace_id)
|
||||
if not workspace:
|
||||
continue
|
||||
|
||||
|
||||
# 获取成员数量
|
||||
member_count = self.workspace_member_repository.count_by_workspace(membership.workspace_id)
|
||||
|
||||
|
||||
workspace_info = WorkspaceInfo(
|
||||
workspace_id=workspace.id,
|
||||
name=workspace.name,
|
||||
@@ -102,17 +103,17 @@ class ListWorkspacesUseCase:
|
||||
created_at=workspace.created_at,
|
||||
)
|
||||
workspace_infos.append(workspace_info)
|
||||
|
||||
|
||||
# 4. 返回响应
|
||||
return ListWorkspacesResponse(workspaces=workspace_infos), None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to list workspaces: {str(e)}"
|
||||
|
||||
|
||||
class GetWorkspaceDetailRequest:
|
||||
"""获取工作空间详情请求"""
|
||||
|
||||
|
||||
def __init__(self, workspace_id: str, user_id: str):
|
||||
self.workspace_id = workspace_id
|
||||
self.user_id = user_id
|
||||
@@ -120,7 +121,7 @@ class GetWorkspaceDetailRequest:
|
||||
|
||||
class WorkspaceDetailInfo:
|
||||
"""工作空间详情信息"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -152,7 +153,7 @@ class WorkspaceDetailInfo:
|
||||
|
||||
class GetWorkspaceDetailUseCase:
|
||||
"""获取工作空间详情用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -160,14 +161,14 @@ class GetWorkspaceDetailUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
|
||||
def execute(self, request: GetWorkspaceDetailRequest) -> tuple[Optional[WorkspaceDetailInfo], Optional[str]]:
|
||||
"""
|
||||
执行获取工作空间详情
|
||||
|
||||
|
||||
Args:
|
||||
request: 请求
|
||||
|
||||
|
||||
Returns:
|
||||
(详情信息, 错误信息)
|
||||
"""
|
||||
@@ -175,15 +176,15 @@ class GetWorkspaceDetailUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return None, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.user_id:
|
||||
return None, "User ID is required"
|
||||
|
||||
|
||||
# 2. 验证工作空间存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return None, "Workspace not found"
|
||||
|
||||
|
||||
# 3. 验证用户是成员
|
||||
membership = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -191,10 +192,10 @@ class GetWorkspaceDetailUseCase:
|
||||
)
|
||||
if not membership:
|
||||
return None, "You are not a member of this workspace"
|
||||
|
||||
|
||||
# 4. 获取成员数量
|
||||
member_count = self.workspace_member_repository.count_by_workspace(request.workspace_id)
|
||||
|
||||
|
||||
# 5. 构建详情信息
|
||||
detail_info = WorkspaceDetailInfo(
|
||||
workspace_id=workspace.id,
|
||||
@@ -210,8 +211,8 @@ class GetWorkspaceDetailUseCase:
|
||||
user_role=membership.role,
|
||||
created_at=workspace.created_at,
|
||||
)
|
||||
|
||||
|
||||
return detail_info, None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to get workspace detail: {str(e)}"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
移除成员 Use Case
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from packages.domain.entities import WorkspaceMemberRole
|
||||
@@ -8,7 +9,7 @@ from packages.domain.entities import WorkspaceMemberRole
|
||||
|
||||
class RemoveMemberRequest:
|
||||
"""移除成员请求"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -22,7 +23,7 @@ class RemoveMemberRequest:
|
||||
|
||||
class RemoveMemberUseCase:
|
||||
"""移除成员用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -30,14 +31,14 @@ class RemoveMemberUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
|
||||
def execute(self, request: RemoveMemberRequest) -> tuple[bool, Optional[str]]:
|
||||
"""
|
||||
执行移除成员
|
||||
|
||||
|
||||
Args:
|
||||
request: 移除请求
|
||||
|
||||
|
||||
Returns:
|
||||
(是否成功, 错误信息)
|
||||
"""
|
||||
@@ -45,18 +46,18 @@ class RemoveMemberUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return False, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.requester_user_id:
|
||||
return False, "Requester user ID is required"
|
||||
|
||||
|
||||
if not request.target_user_id:
|
||||
return False, "Target user ID is required"
|
||||
|
||||
|
||||
# 2. 验证 Workspace 存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return False, "Workspace not found"
|
||||
|
||||
|
||||
# 3. 验证请求者是成员且有权限
|
||||
requester_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -64,10 +65,13 @@ class RemoveMemberUseCase:
|
||||
)
|
||||
if not requester_member:
|
||||
return False, "You are not a member of this workspace"
|
||||
|
||||
if requester_member.role not in [WorkspaceMemberRole.OWNER, WorkspaceMemberRole.ADMIN]:
|
||||
|
||||
if requester_member.role not in [
|
||||
WorkspaceMemberRole.OWNER,
|
||||
WorkspaceMemberRole.ADMIN,
|
||||
]:
|
||||
return False, "Only owners and admins can remove members"
|
||||
|
||||
|
||||
# 4. 验证目标成员存在
|
||||
target_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -75,34 +79,33 @@ class RemoveMemberUseCase:
|
||||
)
|
||||
if not target_member:
|
||||
return False, "Target user is not a member of this workspace"
|
||||
|
||||
|
||||
# 5. 不能移除自己(应该用离开 workspace 的功能)
|
||||
if request.requester_user_id == request.target_user_id:
|
||||
return False, "Cannot remove yourself. Use leave workspace instead."
|
||||
|
||||
|
||||
# 6. 不能移除 owner
|
||||
if target_member.role == WorkspaceMemberRole.OWNER:
|
||||
return False, "Cannot remove the workspace owner"
|
||||
|
||||
|
||||
# 7. Admin 不能移除另一个 Admin(只有 owner 可以)
|
||||
if (requester_member.role == WorkspaceMemberRole.ADMIN and
|
||||
target_member.role == WorkspaceMemberRole.ADMIN):
|
||||
if requester_member.role == WorkspaceMemberRole.ADMIN and target_member.role == WorkspaceMemberRole.ADMIN:
|
||||
return False, "Admins cannot remove other admins"
|
||||
|
||||
|
||||
# 8. 删除成员记录
|
||||
success = self.workspace_member_repository.delete(target_member.id)
|
||||
if not success:
|
||||
return False, "Failed to remove member"
|
||||
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Failed to remove member: {str(e)}"
|
||||
|
||||
|
||||
class LeaveWorkspaceRequest:
|
||||
"""离开 Workspace 请求"""
|
||||
|
||||
|
||||
def __init__(self, workspace_id: str, user_id: str):
|
||||
self.workspace_id = workspace_id
|
||||
self.user_id = user_id
|
||||
@@ -110,7 +113,7 @@ class LeaveWorkspaceRequest:
|
||||
|
||||
class LeaveWorkspaceUseCase:
|
||||
"""离开 Workspace 用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -118,14 +121,14 @@ class LeaveWorkspaceUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
|
||||
def execute(self, request: LeaveWorkspaceRequest) -> tuple[bool, Optional[str]]:
|
||||
"""
|
||||
执行离开 Workspace
|
||||
|
||||
|
||||
Args:
|
||||
request: 离开请求
|
||||
|
||||
|
||||
Returns:
|
||||
(是否成功, 错误信息)
|
||||
"""
|
||||
@@ -133,15 +136,15 @@ class LeaveWorkspaceUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return False, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.user_id:
|
||||
return False, "User ID is required"
|
||||
|
||||
|
||||
# 2. 验证 Workspace 存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return False, "Workspace not found"
|
||||
|
||||
|
||||
# 3. 验证用户是成员
|
||||
member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -149,17 +152,20 @@ class LeaveWorkspaceUseCase:
|
||||
)
|
||||
if not member:
|
||||
return False, "You are not a member of this workspace"
|
||||
|
||||
|
||||
# 4. Owner 不能离开(需要先转移 ownership 或删除 workspace)
|
||||
if member.role == WorkspaceMemberRole.OWNER:
|
||||
return False, "Owner cannot leave workspace. Transfer ownership or delete workspace first."
|
||||
|
||||
return (
|
||||
False,
|
||||
"Owner cannot leave workspace. Transfer ownership or delete workspace first.",
|
||||
)
|
||||
|
||||
# 5. 删除成员记录
|
||||
success = self.workspace_member_repository.delete(member.id)
|
||||
if not success:
|
||||
return False, "Failed to leave workspace"
|
||||
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Failed to leave workspace: {str(e)}"
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
"""
|
||||
Subscription 管理 Use Case
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional
|
||||
|
||||
from packages.domain.entities import WorkspaceMemberRole
|
||||
|
||||
|
||||
class UpgradeSubscriptionRequest:
|
||||
"""升级订阅请求"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -23,7 +24,7 @@ class UpgradeSubscriptionRequest:
|
||||
|
||||
class UpgradeSubscriptionResponse:
|
||||
"""升级订阅响应"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -41,21 +42,21 @@ class UpgradeSubscriptionResponse:
|
||||
|
||||
class UpgradeSubscriptionUseCase:
|
||||
"""升级订阅用例"""
|
||||
|
||||
|
||||
# 订阅计划配额
|
||||
PLAN_QUOTAS = {
|
||||
"free": {"max_projects": 3, "max_storage_gb": 10, "price": 0},
|
||||
"pro": {"max_projects": 999999, "max_storage_gb": 100, "price": 99},
|
||||
"enterprise": {"max_projects": 999999, "max_storage_gb": 1000, "price": 999},
|
||||
}
|
||||
|
||||
|
||||
# 计划等级
|
||||
PLAN_LEVELS = {
|
||||
"free": 0,
|
||||
"pro": 1,
|
||||
"enterprise": 2,
|
||||
}
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -63,14 +64,16 @@ class UpgradeSubscriptionUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
def execute(self, request: UpgradeSubscriptionRequest) -> tuple[Optional[UpgradeSubscriptionResponse], Optional[str]]:
|
||||
|
||||
def execute(
|
||||
self, request: UpgradeSubscriptionRequest
|
||||
) -> tuple[Optional[UpgradeSubscriptionResponse], Optional[str]]:
|
||||
"""
|
||||
执行升级订阅
|
||||
|
||||
|
||||
Args:
|
||||
request: 升级请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -78,22 +81,22 @@ class UpgradeSubscriptionUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return None, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.requester_user_id:
|
||||
return None, "Requester user ID is required"
|
||||
|
||||
|
||||
if not request.new_plan:
|
||||
return None, "New plan is required"
|
||||
|
||||
|
||||
# 2. 验证新计划有效
|
||||
if request.new_plan not in self.PLAN_QUOTAS:
|
||||
return None, f"Invalid plan: {request.new_plan}"
|
||||
|
||||
|
||||
# 3. 验证工作空间存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return None, "Workspace not found"
|
||||
|
||||
|
||||
# 4. 验证权限(只有 Owner 可以管理订阅)
|
||||
member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -101,50 +104,56 @@ class UpgradeSubscriptionUseCase:
|
||||
)
|
||||
if not member:
|
||||
return None, "You are not a member of this workspace"
|
||||
|
||||
|
||||
if member.role != WorkspaceMemberRole.OWNER:
|
||||
return None, "Only workspace owner can manage subscription"
|
||||
|
||||
|
||||
# 5. 检查是否是升级(不能降级到免费计划,需要用取消订阅)
|
||||
current_level = self.PLAN_LEVELS.get(workspace.subscription_plan, 0)
|
||||
new_level = self.PLAN_LEVELS.get(request.new_plan, 0)
|
||||
|
||||
|
||||
if new_level < current_level:
|
||||
return None, "Cannot downgrade plan. Use cancel subscription to return to free plan."
|
||||
|
||||
return (
|
||||
None,
|
||||
"Cannot downgrade plan. Use cancel subscription to return to free plan.",
|
||||
)
|
||||
|
||||
if new_level == current_level:
|
||||
return None, f"Workspace is already on {request.new_plan} plan"
|
||||
|
||||
|
||||
# 6. 更新订阅
|
||||
old_plan = workspace.subscription_plan
|
||||
quota = self.PLAN_QUOTAS[request.new_plan]
|
||||
|
||||
|
||||
workspace.subscription_plan = request.new_plan
|
||||
workspace.subscription_status = "active"
|
||||
workspace.max_projects = quota["max_projects"]
|
||||
workspace.max_storage_gb = quota["max_storage_gb"]
|
||||
|
||||
|
||||
# 设置过期时间(假设按月订阅)
|
||||
workspace.subscription_expires_at = datetime.now(timezone.utc) + timedelta(days=30)
|
||||
|
||||
|
||||
self.workspace_repository.save(workspace)
|
||||
|
||||
|
||||
# 7. 返回响应
|
||||
return UpgradeSubscriptionResponse(
|
||||
workspace_id=workspace.id,
|
||||
old_plan=old_plan,
|
||||
new_plan=workspace.subscription_plan,
|
||||
max_projects=workspace.max_projects,
|
||||
max_storage_gb=workspace.max_storage_gb,
|
||||
), None
|
||||
|
||||
return (
|
||||
UpgradeSubscriptionResponse(
|
||||
workspace_id=workspace.id,
|
||||
old_plan=old_plan,
|
||||
new_plan=workspace.subscription_plan,
|
||||
max_projects=workspace.max_projects,
|
||||
max_storage_gb=workspace.max_storage_gb,
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to upgrade subscription: {str(e)}"
|
||||
|
||||
|
||||
class CancelSubscriptionRequest:
|
||||
"""取消订阅请求"""
|
||||
|
||||
|
||||
def __init__(self, workspace_id: str, requester_user_id: str):
|
||||
self.workspace_id = workspace_id
|
||||
self.requester_user_id = requester_user_id
|
||||
@@ -152,7 +161,7 @@ class CancelSubscriptionRequest:
|
||||
|
||||
class CancelSubscriptionUseCase:
|
||||
"""取消订阅用例"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -160,14 +169,14 @@ class CancelSubscriptionUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
|
||||
def execute(self, request: CancelSubscriptionRequest) -> tuple[bool, Optional[str]]:
|
||||
"""
|
||||
执行取消订阅
|
||||
|
||||
|
||||
Args:
|
||||
request: 取消请求
|
||||
|
||||
|
||||
Returns:
|
||||
(是否成功, 错误信息)
|
||||
"""
|
||||
@@ -175,15 +184,15 @@ class CancelSubscriptionUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return False, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.requester_user_id:
|
||||
return False, "Requester user ID is required"
|
||||
|
||||
|
||||
# 2. 验证工作空间存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return False, "Workspace not found"
|
||||
|
||||
|
||||
# 3. 验证权限(只有 Owner 可以管理订阅)
|
||||
member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -191,24 +200,24 @@ class CancelSubscriptionUseCase:
|
||||
)
|
||||
if not member:
|
||||
return False, "You are not a member of this workspace"
|
||||
|
||||
|
||||
if member.role != WorkspaceMemberRole.OWNER:
|
||||
return False, "Only workspace owner can manage subscription"
|
||||
|
||||
|
||||
# 4. 检查当前计划
|
||||
if workspace.subscription_plan == "free":
|
||||
return False, "Workspace is already on free plan"
|
||||
|
||||
|
||||
# 5. 降级到 free 计划
|
||||
workspace.subscription_plan = "free"
|
||||
workspace.subscription_status = "active"
|
||||
workspace.subscription_expires_at = None
|
||||
workspace.max_projects = 3
|
||||
workspace.max_storage_gb = 10
|
||||
|
||||
|
||||
self.workspace_repository.save(workspace)
|
||||
|
||||
|
||||
return True, None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return False, f"Failed to cancel subscription: {str(e)}"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
修改成员角色 Use Case
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from packages.domain.entities import WorkspaceMemberRole
|
||||
@@ -8,7 +9,7 @@ from packages.domain.entities import WorkspaceMemberRole
|
||||
|
||||
class UpdateMemberRoleRequest:
|
||||
"""修改成员角色请求"""
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_id: str,
|
||||
@@ -24,7 +25,7 @@ class UpdateMemberRoleRequest:
|
||||
|
||||
class UpdateMemberRoleResponse:
|
||||
"""修改成员角色响应"""
|
||||
|
||||
|
||||
def __init__(self, user_id: str, old_role: str, new_role: str):
|
||||
self.user_id = user_id
|
||||
self.old_role = old_role
|
||||
@@ -33,13 +34,13 @@ class UpdateMemberRoleResponse:
|
||||
|
||||
class UpdateMemberRoleUseCase:
|
||||
"""修改成员角色用例"""
|
||||
|
||||
|
||||
VALID_ROLES = [
|
||||
WorkspaceMemberRole.ADMIN,
|
||||
WorkspaceMemberRole.MEMBER,
|
||||
WorkspaceMemberRole.VIEWER,
|
||||
]
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
workspace_repository,
|
||||
@@ -47,14 +48,14 @@ class UpdateMemberRoleUseCase:
|
||||
):
|
||||
self.workspace_repository = workspace_repository
|
||||
self.workspace_member_repository = workspace_member_repository
|
||||
|
||||
|
||||
def execute(self, request: UpdateMemberRoleRequest) -> tuple[Optional[UpdateMemberRoleResponse], Optional[str]]:
|
||||
"""
|
||||
执行修改成员角色
|
||||
|
||||
|
||||
Args:
|
||||
request: 修改请求
|
||||
|
||||
|
||||
Returns:
|
||||
(响应, 错误信息)
|
||||
"""
|
||||
@@ -62,25 +63,28 @@ class UpdateMemberRoleUseCase:
|
||||
# 1. 验证输入
|
||||
if not request.workspace_id:
|
||||
return None, "Workspace ID is required"
|
||||
|
||||
|
||||
if not request.requester_user_id:
|
||||
return None, "Requester user ID is required"
|
||||
|
||||
|
||||
if not request.target_user_id:
|
||||
return None, "Target user ID is required"
|
||||
|
||||
|
||||
if not request.new_role:
|
||||
return None, "New role is required"
|
||||
|
||||
|
||||
# 2. 验证新角色(不能修改为 owner)
|
||||
if request.new_role not in self.VALID_ROLES:
|
||||
return None, f"Invalid role: {request.new_role}. Cannot change to owner."
|
||||
|
||||
return (
|
||||
None,
|
||||
f"Invalid role: {request.new_role}. Cannot change to owner.",
|
||||
)
|
||||
|
||||
# 3. 验证 Workspace 存在
|
||||
workspace = self.workspace_repository.find_by_id(request.workspace_id)
|
||||
if not workspace:
|
||||
return None, "Workspace not found"
|
||||
|
||||
|
||||
# 4. 验证请求者是成员且有权限(只有 owner 和 admin 可以修改角色)
|
||||
requester_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -88,10 +92,13 @@ class UpdateMemberRoleUseCase:
|
||||
)
|
||||
if not requester_member:
|
||||
return None, "You are not a member of this workspace"
|
||||
|
||||
if requester_member.role not in [WorkspaceMemberRole.OWNER, WorkspaceMemberRole.ADMIN]:
|
||||
|
||||
if requester_member.role not in [
|
||||
WorkspaceMemberRole.OWNER,
|
||||
WorkspaceMemberRole.ADMIN,
|
||||
]:
|
||||
return None, "Only owners and admins can change member roles"
|
||||
|
||||
|
||||
# 5. 验证目标成员存在
|
||||
target_member = self.workspace_member_repository.find_by_workspace_and_user(
|
||||
request.workspace_id,
|
||||
@@ -99,35 +106,37 @@ class UpdateMemberRoleUseCase:
|
||||
)
|
||||
if not target_member:
|
||||
return None, "Target user is not a member of this workspace"
|
||||
|
||||
|
||||
# 6. 不能修改自己的角色
|
||||
if request.requester_user_id == request.target_user_id:
|
||||
return None, "Cannot change your own role"
|
||||
|
||||
|
||||
# 7. 不能修改 owner 的角色
|
||||
if target_member.role == WorkspaceMemberRole.OWNER:
|
||||
return None, "Cannot change the owner's role"
|
||||
|
||||
|
||||
# 8. Admin 不能修改另一个 Admin 的角色(只有 owner 可以)
|
||||
if (requester_member.role == WorkspaceMemberRole.ADMIN and
|
||||
target_member.role == WorkspaceMemberRole.ADMIN):
|
||||
if requester_member.role == WorkspaceMemberRole.ADMIN and target_member.role == WorkspaceMemberRole.ADMIN:
|
||||
return None, "Admins cannot change other admins' roles"
|
||||
|
||||
|
||||
# 9. 检查角色是否相同
|
||||
if target_member.role == request.new_role:
|
||||
return None, f"User already has the {request.new_role} role"
|
||||
|
||||
|
||||
# 10. 更新角色
|
||||
old_role = target_member.role
|
||||
target_member.role = request.new_role
|
||||
self.workspace_member_repository.save(target_member)
|
||||
|
||||
|
||||
# 11. 返回响应
|
||||
return UpdateMemberRoleResponse(
|
||||
user_id=request.target_user_id,
|
||||
old_role=old_role,
|
||||
new_role=request.new_role,
|
||||
), None
|
||||
|
||||
return (
|
||||
UpdateMemberRoleResponse(
|
||||
user_id=request.target_user_id,
|
||||
old_role=old_role,
|
||||
new_role=request.new_role,
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return None, f"Failed to update member role: {str(e)}"
|
||||
|
||||
Reference in New Issue
Block a user