Coverage for polar/user/endpoints.py: 83%
36 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 16:17 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-12-05 16:17 +0000
1from fastapi import Depends 1a
3from polar.auth.dependencies import Authenticator, WebUserRead, WebUserWrite 1a
4from polar.auth.models import AuthSubject 1a
5from polar.customer_portal.endpoints.downloadables import router as downloadables_router 1a
6from polar.customer_portal.endpoints.license_keys import router as license_keys_router 1a
7from polar.customer_portal.endpoints.order import router as order_router 1a
8from polar.customer_portal.endpoints.subscription import router as subscription_router 1a
9from polar.models import User 1a
10from polar.models.user import OAuthPlatform 1a
11from polar.openapi import APITag 1a
12from polar.postgres import AsyncSession, get_db_session 1a
13from polar.routing import APIRouter 1a
14from polar.user.oauth_service import oauth_account_service 1a
15from polar.user.service import user as user_service 1a
17from .schemas import ( 1a
18 UserDeletionResponse,
19 UserIdentityVerification,
20 UserRead,
21 UserScopes,
22)
24router = APIRouter(prefix="/users", tags=["users", APITag.private]) 1a
26# Include customer portal endpoints for backwards compatibility
27router.include_router(order_router, deprecated=True, include_in_schema=False) 1a
28router.include_router(subscription_router, deprecated=True, include_in_schema=False) 1a
29router.include_router(downloadables_router, deprecated=True, include_in_schema=False) 1a
30router.include_router(license_keys_router, deprecated=True, include_in_schema=False) 1a
33@router.get("/me", response_model=UserRead) 1a
34async def get_authenticated(auth_subject: WebUserRead) -> User: 1a
35 return auth_subject.subject
38@router.get("/me/scopes", response_model=UserScopes) 1a
39async def scopes( 1ab
40 auth_subject: AuthSubject[User] = Depends(Authenticator(allowed_subjects={User})),
41) -> UserScopes:
42 return UserScopes(scopes=list(auth_subject.scopes))
45@router.post("/me/identity-verification", response_model=UserIdentityVerification) 1a
46async def create_identity_verification( 1a
47 auth_subject: WebUserWrite,
48 session: AsyncSession = Depends(get_db_session),
49) -> UserIdentityVerification:
50 return await user_service.create_identity_verification(
51 session, user=auth_subject.subject
52 )
55@router.delete( 1a
56 "/me",
57 response_model=UserDeletionResponse,
58 responses={
59 200: {"description": "Deletion result"},
60 },
61)
62async def delete_authenticated_user( 1a
63 auth_subject: WebUserWrite,
64 session: AsyncSession = Depends(get_db_session),
65) -> UserDeletionResponse:
66 """
67 Delete the authenticated user account.
69 A user can only be deleted if all organizations they are members of have been
70 deleted first. If the user has active organizations, the response will include
71 the list of organizations that must be deleted before the user account can be
72 removed.
74 When deleted:
75 - User's email is anonymized
76 - User's avatar and metadata are cleared
77 - User's OAuth accounts are deleted (cascade)
78 - User's Account (payout account) is deleted if present
79 """
80 return await user_service.request_deletion(session, auth_subject.subject)
83@router.delete( 1a
84 "/me/oauth-accounts/{platform}",
85 status_code=204,
86 responses={
87 404: {"description": "OAuth account not found"},
88 400: {"description": "Cannot disconnect last authentication method"},
89 },
90)
91async def disconnect_oauth_account( 1a
92 platform: OAuthPlatform,
93 auth_subject: WebUserWrite,
94 session: AsyncSession = Depends(get_db_session),
95) -> None:
96 """
97 Disconnect an OAuth account (GitHub or Google) from the authenticated user.
99 This allows users to unlink their OAuth provider while keeping their Polar account.
100 They can still authenticate using other methods (email magic link or other OAuth providers).
102 Note: You cannot disconnect your last authentication method if your email is not verified.
103 """
104 user = auth_subject.subject
105 await oauth_account_service.disconnect_platform(session, user, platform)