feat(org): platform invites, roles, org sharing (v2 phase A1-1)
- New platform_invites table (migration a1b2c3d4e5f1) + PlatformInviteRow - Owner-only endpoints in admin_users.py: issue/list/revoke platform invites - invites.py: two-kind resolution (org + platform), email-supplied accept path - auth.py /me gains needs_onboarding (manager, 0 orgs, not owner) - organizations.py: transfer-ownership, leave (last owner guard), list/revoke org invites - contracts + web UI: admin/users invite modal, accept-invite platform variant, onboarding gating - Tests: test_org_platform_invites.py (18), org-sharing.test.tsx; report under docs/plan/reports Note: (app)/settings "اشتراکگذاری سازمان" section (1.10) remains presentational work; endpoints are done and tested.
This commit is contained in:
@@ -21,7 +21,7 @@ from app.core.security import (
|
||||
verify_password,
|
||||
)
|
||||
from app.domain.audit.models import AuditAction
|
||||
from app.domain.identity.models import User
|
||||
from app.domain.identity.models import PlatformRole, User
|
||||
from app.infrastructure.repositories.identity import (
|
||||
MembershipRepository,
|
||||
OrganizationRepository,
|
||||
@@ -73,6 +73,11 @@ class TokenResponse(BaseModel):
|
||||
class MeResponse(BaseModel):
|
||||
user: UserOut
|
||||
organizations: list[OrganizationSummary]
|
||||
#: True when this account is a manager with no organization yet: they landed
|
||||
#: on the platform owner's invitation link and built nothing, so the only
|
||||
#: useful thing the UI can do is open the creation wizard. The owner is
|
||||
#: deliberately excluded — they administer the platform rather than joining it.
|
||||
needs_onboarding: bool = False
|
||||
|
||||
|
||||
def _to_user_out(user: User) -> UserOut:
|
||||
@@ -170,12 +175,16 @@ async def me(
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> MeResponse:
|
||||
orgs = await OrganizationRepository(session).list_for_user(user.id)
|
||||
needs_onboarding = (
|
||||
user.platform_role == PlatformRole.MANAGER and len(orgs) == 0 and not user.is_platform_owner
|
||||
)
|
||||
return MeResponse(
|
||||
user=_to_user_out(user),
|
||||
organizations=[
|
||||
OrganizationSummary(id=org.id, name=org.name, slug=org.slug, role=role.value)
|
||||
for org, role in orgs
|
||||
],
|
||||
needs_onboarding=needs_onboarding,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user