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:
2026-04-20 16:37:04 +09:30
parent b2c2acc84f
commit 7550940934
2 changed files with 13 additions and 1 deletions
@@ -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