1616from typing import TYPE_CHECKING , Optional , Dict , Any , Union , List
1717from supertokens_python .recipe .multitenancy .interfaces import (
1818 AssociateUserToTenantOkResult ,
19- AssociateUserToTenantUnknownUserIdErrorResult ,
20- AssociateUserToTenantEmailAlreadyExistsErrorResult ,
21- AssociateUserToTenantPhoneNumberAlreadyExistsErrorResult ,
22- AssociateUserToTenantThirdPartyUserAlreadyExistsErrorResult ,
19+ AssociateUserToTenantUnknownUserIdError ,
20+ AssociateUserToTenantEmailAlreadyExistsError ,
21+ AssociateUserToTenantPhoneNumberAlreadyExistsError ,
22+ AssociateUserToTenantThirdPartyUserAlreadyExistsError ,
2323 DisassociateUserFromTenantOkResult ,
2424)
2525
4747from .constants import DEFAULT_TENANT_ID
4848
4949
50+ def parse_tenant_config (tenant : Dict [str , Any ]) -> TenantConfigResponse :
51+ from supertokens_python .recipe .thirdparty .provider import (
52+ UserInfoMap ,
53+ UserFields ,
54+ ProviderClientConfig ,
55+ )
56+
57+ providers : List [ProviderConfig ] = []
58+ for p in tenant ["thirdParty" ]["providers" ]:
59+ user_info_map : Optional [UserInfoMap ] = None
60+ if "userInfoMap" in p :
61+ map_from_payload = p ["userInfoMap" ].get ("fromIdTokenPayload" , {})
62+ map_from_api = p ["userInfoMap" ].get ("fromUserInfoAPI" , {})
63+ user_info_map = UserInfoMap (
64+ UserFields (
65+ map_from_payload .get ("userId" ),
66+ map_from_payload .get ("email" ),
67+ map_from_payload .get ("emailVerified" ),
68+ ),
69+ UserFields (
70+ map_from_api .get ("userId" ),
71+ map_from_api .get ("email" ),
72+ map_from_api .get ("emailVerified" ),
73+ ),
74+ )
75+
76+ providers .append (
77+ ProviderConfig (
78+ third_party_id = p ["thirdPartyId" ],
79+ name = p ["name" ],
80+ clients = [
81+ ProviderClientConfig (
82+ client_id = c ["clientId" ],
83+ client_secret = c ["clientSecret" ],
84+ client_type = c ["clientType" ],
85+ scope = c ["scope" ],
86+ force_pkce = c ["forcePkce" ],
87+ additional_config = c ["additionalConfig" ],
88+ )
89+ for c in p ["clients" ]
90+ ],
91+ authorization_endpoint = p ["authorizationEndpoint" ],
92+ authorization_endpoint_query_params = p [
93+ "authorizationEndpointQueryParams"
94+ ],
95+ token_endpoint = p ["tokenEndpoint" ],
96+ token_endpoint_body_params = p ["tokenEndpointBodyParams" ],
97+ user_info_endpoint = p ["userInfoEndpoint" ],
98+ user_info_endpoint_query_params = p ["userInfoEndpointQueryParams" ],
99+ user_info_endpoint_headers = p ["userInfoEndpointHeaders" ],
100+ jwks_uri = p ["jwksUri" ],
101+ oidc_discovery_endpoint = p ["oidcDiscoveryEndpoint" ],
102+ user_info_map = user_info_map ,
103+ require_email = p ["requireEmail" ],
104+ validate_id_token_payload = p ["validateIdTokenPayload" ],
105+ generate_fake_email = p ["generateFakeEmail" ],
106+ )
107+ )
108+
109+ return TenantConfigResponse (
110+ emailpassword = EmailPasswordConfig (tenant ["emailPassword" ]["enabled" ]),
111+ passwordless = PasswordlessConfig (tenant ["passwordless" ]["enabled" ]),
112+ third_party = ThirdPartyConfig (
113+ tenant ["thirdParty" ]["enabled" ],
114+ providers ,
115+ ),
116+ core_config = tenant ["coreConfig" ],
117+ )
118+
119+
50120class RecipeImplementation (RecipeInterface ):
51121 def __init__ (self , querier : Querier , config : MultitenancyConfig ):
52122 super ().__init__ ()
@@ -89,93 +159,24 @@ async def delete_tenant(
89159 async def get_tenant (
90160 self , tenant_id : Optional [str ], user_context : Dict [str , Any ]
91161 ) -> GetTenantOkResult :
92- from supertokens_python .recipe .thirdparty .provider import (
93- ProviderConfig ,
94- UserInfoMap ,
95- UserFields ,
96- ProviderClientConfig ,
97- )
98-
99162 res = await self .querier .send_get_request (
100163 NormalisedURLPath (
101164 f"{ tenant_id or DEFAULT_TENANT_ID } /recipe/multitenancy/tenant"
102165 ),
103166 )
104167
105- providers : List [ProviderConfig ] = []
106- for p in res ["thirdParty" ]["providers" ]:
107- user_info_map : Optional [UserInfoMap ] = None
108- if "userInfoMap" in p :
109- map_from_payload = p ["userInfoMap" ].get ("fromIdTokenPayload" , {})
110- map_from_api = p ["userInfoMap" ].get ("fromUserInfoAPI" , {})
111- user_info_map = UserInfoMap (
112- UserFields (
113- map_from_payload .get ("userId" ),
114- map_from_payload .get ("email" ),
115- map_from_payload .get ("emailVerified" ),
116- ),
117- UserFields (
118- map_from_api .get ("userId" ),
119- map_from_api .get ("email" ),
120- map_from_api .get ("emailVerified" ),
121- ),
122- )
123-
124- providers .append (
125- ProviderConfig (
126- third_party_id = p ["thirdPartyId" ],
127- name = p ["name" ],
128- clients = [
129- ProviderClientConfig (
130- client_id = c ["clientId" ],
131- client_secret = c .get ("clientSecret" ),
132- client_type = c .get ("clientType" ),
133- scope = c .get ("scope" ),
134- force_pkce = c .get ("forcePkce" ),
135- additional_config = c .get ("additionalConfig" ),
136- )
137- for c in p ["clients" ]
138- ],
139- authorization_endpoint = p .get ("authorizationEndpoint" ),
140- authorization_endpoint_query_params = p .get (
141- "authorizationEndpointQueryParams"
142- ),
143- token_endpoint = p .get ("tokenEndpoint" ),
144- token_endpoint_body_params = p .get ("tokenEndpointBodyParams" ),
145- user_info_endpoint = p .get ("userInfoEndpoint" ),
146- user_info_endpoint_query_params = p .get (
147- "userInfoEndpointQueryParams"
148- ),
149- user_info_endpoint_headers = p .get ("userInfoEndpointHeaders" ),
150- jwks_uri = p .get ("jwksUri" ),
151- oidc_discovery_endpoint = p .get ("oidcDiscoveryEndpoint" ),
152- user_info_map = user_info_map ,
153- require_email = p .get ("requireEmail" ),
154- validate_id_token_payload = None ,
155- generate_fake_email = None ,
156- )
157- )
168+ tenant_config = parse_tenant_config (res )
158169
159170 return GetTenantOkResult (
160- emailpassword = EmailPasswordConfig (res ["emailPassword" ]["enabled" ]),
161- passwordless = PasswordlessConfig (res ["passwordless" ]["enabled" ]),
162- third_party = ThirdPartyConfig (
163- res ["thirdParty" ]["enabled" ],
164- providers ,
165- ),
166- core_config = res ["coreConfig" ],
171+ emailpassword = tenant_config .emailpassword ,
172+ passwordless = tenant_config .passwordless ,
173+ third_party = tenant_config .third_party ,
174+ core_config = tenant_config .core_config ,
167175 )
168176
169177 async def list_all_tenants (
170178 self , user_context : Dict [str , Any ]
171179 ) -> ListAllTenantsOkResult :
172- from supertokens_python .recipe .thirdparty .provider import (
173- ProviderConfig ,
174- ProviderClientConfig ,
175- UserFields ,
176- UserInfoMap ,
177- )
178-
179180 response = await self .querier .send_get_request (
180181 NormalisedURLPath ("/recipe/multitenancy/tenant/list" ),
181182 {},
@@ -184,73 +185,7 @@ async def list_all_tenants(
184185 tenant_configs : List [TenantConfigResponse ] = []
185186
186187 for tenant in response ["tenants" ]:
187- providers : List [ProviderConfig ] = []
188- for p in tenant ["thirdParty" ]["providers" ]:
189- user_info_map : Optional [UserInfoMap ] = None
190- if "userInfoMap" in p :
191- map_from_payload = p ["userInfoMap" ].get ("fromIdTokenPayload" , {})
192- map_from_api = p ["userInfoMap" ].get ("fromUserInfoAPI" , {})
193- user_info_map = UserInfoMap (
194- UserFields (
195- map_from_payload .get ("userId" ),
196- map_from_payload .get ("email" ),
197- map_from_payload .get ("emailVerified" ),
198- ),
199- UserFields (
200- map_from_api .get ("userId" ),
201- map_from_api .get ("email" ),
202- map_from_api .get ("emailVerified" ),
203- ),
204- )
205-
206- providers .append (
207- ProviderConfig (
208- third_party_id = p ["thirdPartyId" ],
209- name = p ["name" ],
210- clients = [
211- ProviderClientConfig (
212- client_id = c ["clientId" ],
213- client_secret = c ["clientSecret" ],
214- client_type = c ["clientType" ],
215- scope = c ["scope" ],
216- force_pkce = c ["forcePkce" ],
217- additional_config = c ["additionalConfig" ],
218- )
219- for c in p ["clients" ]
220- ],
221- authorization_endpoint = p ["authorizationEndpoint" ],
222- authorization_endpoint_query_params = p [
223- "authorizationEndpointQueryParams"
224- ],
225- token_endpoint = p ["tokenEndpoint" ],
226- token_endpoint_body_params = p ["tokenEndpointBodyParams" ],
227- user_info_endpoint = p ["userInfoEndpoint" ],
228- user_info_endpoint_query_params = p [
229- "userInfoEndpointQueryParams"
230- ],
231- user_info_endpoint_headers = p ["userInfoEndpointHeaders" ],
232- jwks_uri = p ["jwksUri" ],
233- oidc_discovery_endpoint = p ["oidcDiscoveryEndpoint" ],
234- user_info_map = user_info_map ,
235- require_email = p ["requireEmail" ],
236- validate_id_token_payload = p ["validateIdTokenPayload" ],
237- generate_fake_email = p ["generateFakeEmail" ],
238- )
239- )
240-
241- tenant_configs .append (
242- TenantConfigResponse (
243- emailpassword = EmailPasswordConfig (
244- tenant ["emailPassword" ]["enabled" ]
245- ),
246- passwordless = PasswordlessConfig (tenant ["passwordless" ]["enabled" ]),
247- third_party = ThirdPartyConfig (
248- tenant ["thirdParty" ]["enabled" ],
249- providers ,
250- ),
251- core_config = tenant ["coreConfig" ],
252- )
253- )
188+ tenant_configs .append (parse_tenant_config (tenant ))
254189
255190 return ListAllTenantsOkResult (
256191 tenants = tenant_configs ,
@@ -300,12 +235,12 @@ async def associate_user_to_tenant(
300235 self , tenant_id : str | None , user_id : str , user_context : Dict [str , Any ]
301236 ) -> Union [
302237 AssociateUserToTenantOkResult ,
303- AssociateUserToTenantUnknownUserIdErrorResult ,
304- AssociateUserToTenantEmailAlreadyExistsErrorResult ,
305- AssociateUserToTenantPhoneNumberAlreadyExistsErrorResult ,
306- AssociateUserToTenantThirdPartyUserAlreadyExistsErrorResult ,
238+ AssociateUserToTenantUnknownUserIdError ,
239+ AssociateUserToTenantEmailAlreadyExistsError ,
240+ AssociateUserToTenantPhoneNumberAlreadyExistsError ,
241+ AssociateUserToTenantThirdPartyUserAlreadyExistsError ,
307242 ]:
308- response = await self .querier .send_post_request (
243+ response : Dict [ str , Any ] = await self .querier .send_post_request (
309244 NormalisedURLPath (
310245 f"{ tenant_id or DEFAULT_TENANT_ID } /recipe/multitenancy/tenant/user"
311246 ),
@@ -314,9 +249,26 @@ async def associate_user_to_tenant(
314249 },
315250 )
316251
317- return AssociateUserToTenantOkResult (
318- was_already_associated = response ["wasAlreadyAssociated" ],
319- )
252+ if response ["status" ] == "OK" :
253+ return AssociateUserToTenantOkResult (
254+ was_already_associated = response ["wasAlreadyAssociated" ],
255+ )
256+ if response ["status" ] == AssociateUserToTenantUnknownUserIdError .status :
257+ return AssociateUserToTenantUnknownUserIdError ()
258+ if response ["status" ] == AssociateUserToTenantEmailAlreadyExistsError .status :
259+ return AssociateUserToTenantEmailAlreadyExistsError ()
260+ if (
261+ response ["status" ]
262+ == AssociateUserToTenantPhoneNumberAlreadyExistsError .status
263+ ):
264+ return AssociateUserToTenantPhoneNumberAlreadyExistsError ()
265+ if (
266+ response ["status" ]
267+ == AssociateUserToTenantThirdPartyUserAlreadyExistsError .status
268+ ):
269+ return AssociateUserToTenantThirdPartyUserAlreadyExistsError ()
270+
271+ raise Exception ("Should never come here" )
320272
321273 async def dissociate_user_from_tenant (
322274 self , tenant_id : str | None , user_id : str , user_context : Dict [str , Any ]
0 commit comments