Remove a member from the active organization.
(
member_id: UUID,
session: AsyncSession = SESSION_DEP,
ctx: OrganizationContext = ORG_ADMIN_DEP,
)
| 524 | |
| 525 | @router.delete("/me/members/{member_id}", response_model=OkResponse) |
| 526 | async def remove_org_member( |
| 527 | member_id: UUID, |
| 528 | session: AsyncSession = SESSION_DEP, |
| 529 | ctx: OrganizationContext = ORG_ADMIN_DEP, |
| 530 | ) -> OkResponse: |
| 531 | """Remove a member from the active organization.""" |
| 532 | member = await _require_org_member( |
| 533 | session, |
| 534 | organization_id=ctx.organization.id, |
| 535 | member_id=member_id, |
| 536 | ) |
| 537 | if member.user_id == ctx.member.user_id: |
| 538 | raise HTTPException( |
| 539 | status_code=status.HTTP_403_FORBIDDEN, |
| 540 | detail="You cannot remove yourself from the organization", |
| 541 | ) |
| 542 | if member.role == "owner" and ctx.member.role != "owner": |
| 543 | raise HTTPException( |
| 544 | status_code=status.HTTP_403_FORBIDDEN, |
| 545 | detail="Only owners can remove owners", |
| 546 | ) |
| 547 | if member.role == "owner": |
| 548 | owners = ( |
| 549 | await OrganizationMember.objects.filter_by( |
| 550 | organization_id=ctx.organization.id, |
| 551 | ) |
| 552 | .filter(col(OrganizationMember.role) == "owner") |
| 553 | .all(session) |
| 554 | ) |
| 555 | if len(owners) <= 1: |
| 556 | raise HTTPException( |
| 557 | status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, |
| 558 | detail="Organization must have at least one owner", |
| 559 | ) |
| 560 | |
| 561 | await crud.delete_where( |
| 562 | session, |
| 563 | OrganizationBoardAccess, |
| 564 | col(OrganizationBoardAccess.organization_member_id) == member.id, |
| 565 | commit=False, |
| 566 | ) |
| 567 | |
| 568 | user = await User.objects.by_id(member.user_id).first(session) |
| 569 | if user is not None and user.active_organization_id == ctx.organization.id: |
| 570 | fallback_membership = ( |
| 571 | await OrganizationMember.objects.filter( |
| 572 | col(OrganizationMember.user_id) == user.id, |
| 573 | col(OrganizationMember.organization_id) != ctx.organization.id, |
| 574 | ) |
| 575 | .order_by(col(OrganizationMember.created_at).asc()) |
| 576 | .first(session) |
| 577 | ) |
| 578 | if isinstance(fallback_membership, UUID): |
| 579 | user.active_organization_id = fallback_membership |
| 580 | else: |
| 581 | user.active_organization_id = ( |
| 582 | fallback_membership.organization_id if fallback_membership is not None else None |
| 583 | ) |
nothing calls this directly
no test coverage detected