feat(api): return 403 when attempting to remove last owner
Handle edge case where removing a member would leave an organization without any owners. Service layer raises ValueError for this scenario, which the API endpoint catches and converts to a forbidden response with actionable error message about transferring ownership.
This commit is contained in:
@@ -56,7 +56,10 @@ def add_organization_member(org_id):
|
||||
@full_access_required
|
||||
def remove_organization_member(org_id, user_id):
|
||||
org = OrganizationService.get_organization_by_id(org_id)
|
||||
OrganizationService.remove_member(org=org, user_id=user_id, remover_id=g.current_user.id)
|
||||
try:
|
||||
OrganizationService.remove_member(org=org, user_id=user_id, remover_id=g.current_user.id)
|
||||
except ValueError as e:
|
||||
return api_response(success=False, message=str(e), status=403, error_type="OWNER_PROTECTION")
|
||||
return api_response(message="Member removed successfully")
|
||||
|
||||
|
||||
|
||||
@@ -379,6 +379,15 @@ class OrganizationService:
|
||||
logger.debug(f"[Org] Member removal: org_id={org.id}, user_id={user_id}, found={member is not None}")
|
||||
|
||||
if member:
|
||||
if member.role == OrganizationRole.OWNER:
|
||||
owner_count = OrganizationMember.query.filter(
|
||||
OrganizationMember.organization_id == org.id,
|
||||
OrganizationMember.role == OrganizationRole.OWNER,
|
||||
OrganizationMember.deleted_at.is_(None),
|
||||
OrganizationMember.user_id != user_id,
|
||||
).count()
|
||||
if owner_count < 1:
|
||||
raise ValueError("Cannot remove the only owner from an organization. Transfer ownership first.")
|
||||
member.delete(soft=True)
|
||||
|
||||
# Log member removal
|
||||
|
||||
Reference in New Issue
Block a user