Skip to content

Commit 90846ef

Browse files
authored
Merge pull request #382 from supertokens/feat/dashboard-mt
feat: Add multitenancy for dashboard recipe
2 parents fee89fb + c7f87ac commit 90846ef

29 files changed

+221
-52
lines changed

supertokens_python/recipe/dashboard/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from .users_count_get import handle_users_count_get_api
3232
from .users_get import handle_users_get_api
3333
from .validate_key import handle_validate_key_api
34+
from .list_tenants import handle_list_tenants_api
3435

3536
__all__ = [
3637
"handle_dashboard_api",
@@ -53,4 +54,5 @@
5354
"handle_emailpassword_signout_api",
5455
"handle_get_tags",
5556
"handle_analytics_post",
57+
"handle_list_tenants_api",
5658
]

supertokens_python/recipe/dashboard/api/analytics.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@
3535

3636

3737
async def handle_analytics_post(
38-
_: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any]
38+
_: APIInterface,
39+
_tenant_id: str,
40+
api_options: APIOptions,
41+
_user_context: Dict[str, Any],
3942
) -> AnalyticsResponse:
4043
if not Supertokens.get_instance().telemetry:
4144
return AnalyticsResponse()

supertokens_python/recipe/dashboard/api/api_key_protector.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232

3333
async def api_key_protector(
3434
api_implementation: APIInterface,
35+
tenant_id: str,
3536
api_options: APIOptions,
3637
api_function: Callable[
37-
[APIInterface, APIOptions, Dict[str, Any]], Awaitable[APIResponse]
38+
[APIInterface, str, APIOptions, Dict[str, Any]], Awaitable[APIResponse]
3839
],
3940
user_context: Dict[str, Any],
4041
) -> Optional[BaseResponse]:
@@ -47,5 +48,7 @@ async def api_key_protector(
4748
"Unauthorised access", 401, api_options.response
4849
)
4950

50-
response = await api_function(api_implementation, api_options, user_context)
51+
response = await api_function(
52+
api_implementation, tenant_id, api_options, user_context
53+
)
5154
return send_200_response(response.to_json(), api_options.response)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved.
2+
#
3+
# This software is licensed under the Apache License, Version 2.0 (the
4+
# "License") as published by the Apache Software Foundation.
5+
#
6+
# You may not use this file except in compliance with the License. You may
7+
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from __future__ import annotations
16+
17+
from typing import TYPE_CHECKING, Any, Dict
18+
19+
if TYPE_CHECKING:
20+
from supertokens_python.recipe.dashboard.interfaces import (
21+
APIOptions,
22+
APIInterface,
23+
)
24+
from supertokens_python.types import APIResponse
25+
26+
from supertokens_python.recipe.multitenancy.asyncio import list_all_tenants
27+
from supertokens_python.recipe.dashboard.interfaces import (
28+
DashboardListTenantsGetResponse,
29+
)
30+
31+
32+
async def handle_list_tenants_api(
33+
_api_implementation: APIInterface,
34+
_tenant_id: str,
35+
_api_options: APIOptions,
36+
user_context: Dict[str, Any],
37+
) -> APIResponse:
38+
tenants = await list_all_tenants(user_context)
39+
return DashboardListTenantsGetResponse(tenants.tenants)

supertokens_python/recipe/dashboard/api/search/getTags.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525

2626
async def handle_get_tags(
27-
_: APIInterface, __: APIOptions, _user_context: Dict[str, Any]
27+
_: APIInterface, _tenant_id: str, __: APIOptions, _user_context: Dict[str, Any]
2828
) -> SearchTagsOK:
2929
response = await Querier.get_instance().send_get_request(
3030
NormalisedURLPath("/user/search/tags")

supertokens_python/recipe/dashboard/api/signout.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626

2727

2828
async def handle_emailpassword_signout_api(
29-
_: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any]
29+
_: APIInterface,
30+
_tenant_id: str,
31+
api_options: APIOptions,
32+
_user_context: Dict[str, Any],
3033
) -> SignOutOK:
3134
if api_options.config.auth_mode == "api-key":
3235
return SignOutOK()

supertokens_python/recipe/dashboard/api/userdetails/user_delete.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66

77

88
async def handle_user_delete(
9-
_api_interface: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any]
9+
_api_interface: APIInterface,
10+
_tenant_id: str,
11+
api_options: APIOptions,
12+
_user_context: Dict[str, Any],
1013
) -> UserDeleteAPIResponse:
1114
user_id = api_options.request.get_query_param("userId")
1215

supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212

1313

1414
async def handle_user_email_verify_get(
15-
_api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any]
15+
_api_interface: APIInterface,
16+
_tenant_id: str,
17+
api_options: APIOptions,
18+
user_context: Dict[str, Any],
1619
) -> Union[UserEmailVerifyGetAPIResponse, FeatureNotEnabledError]:
1720
req = api_options.request
1821
user_id = req.get_query_param("userId")

supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919

2020

2121
async def handle_user_email_verify_put(
22-
_api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any]
22+
_api_interface: APIInterface,
23+
tenant_id: str,
24+
api_options: APIOptions,
25+
user_context: Dict[str, Any],
2326
) -> UserEmailVerifyPutAPIResponse:
2427
request_body: Dict[str, Any] = await api_options.request.json() # type: ignore
2528
user_id = request_body.get("userId")
@@ -37,7 +40,7 @@ async def handle_user_email_verify_put(
3740

3841
if verified:
3942
token_response = await create_email_verification_token(
40-
user_id, user_context=user_context
43+
user_id, tenant_id=tenant_id, user_context=user_context
4144
)
4245

4346
if isinstance(
@@ -46,7 +49,7 @@ async def handle_user_email_verify_put(
4649
return UserEmailVerifyPutAPIResponse()
4750

4851
verify_response = await verify_email_using_token(
49-
token_response.token, user_context=user_context
52+
token_response.token, tenant_id, user_context=user_context
5053
)
5154

5255
if isinstance(verify_response, VerifyEmailUsingTokenInvalidTokenError):

supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828

2929

3030
async def handle_email_verify_token_post(
31-
_api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any]
31+
_api_interface: APIInterface,
32+
tenant_id: str,
33+
api_options: APIOptions,
34+
user_context: Dict[str, Any],
3235
) -> Union[
3336
UserEmailVerifyTokenPostAPIOkResponse,
3437
UserEmailVerifyTokenPostAPIEmailAlreadyVerifiedErrorResponse,
@@ -49,7 +52,7 @@ async def handle_email_verify_token_post(
4952
raise Exception("Should not come here")
5053

5154
email_verification_token = await create_email_verification_token(
52-
user_id, user_context=user_context
55+
user_id, tenant_id=tenant_id, user_context=user_context
5356
)
5457

5558
if isinstance(
@@ -59,8 +62,6 @@ async def handle_email_verify_token_post(
5962

6063
assert isinstance(email_verification_token, CreateEmailVerificationTokenOkResult)
6164

62-
# TODO: Pass tenant id
63-
tenant_id = "pass-tenant-id"
6465
email_verify_link = get_email_verify_link(
6566
api_options.app_info, email_verification_token.token, user_id, tenant_id
6667
)

0 commit comments

Comments
 (0)