|
13 | 13 | # under the License. |
14 | 14 | from __future__ import annotations |
15 | 15 |
|
16 | | -import re |
17 | 16 | from os import environ |
18 | 17 | from typing import TYPE_CHECKING, Awaitable, Callable, List, Optional, Union, Dict, Any |
19 | 18 |
|
20 | 19 | from supertokens_python.normalised_url_path import NormalisedURLPath |
21 | | -from supertokens_python.recipe_module import APIHandled, RecipeModule, ApiIdWithTenantId |
| 20 | +from supertokens_python.recipe_module import APIHandled, RecipeModule |
22 | 21 |
|
23 | 22 | from .api import ( |
24 | 23 | api_key_protector, |
|
47 | 46 | from .exceptions import SuperTokensDashboardError |
48 | 47 | from .interfaces import APIInterface, APIOptions |
49 | 48 | from .recipe_implementation import RecipeImplementation |
50 | | -from ..multitenancy.constants import DEFAULT_TENANT_ID |
51 | 49 |
|
52 | 50 | if TYPE_CHECKING: |
53 | 51 | from supertokens_python.framework.request import BaseRequest |
|
56 | 54 | from supertokens_python.types import APIResponse |
57 | 55 |
|
58 | 56 | from supertokens_python.exceptions import SuperTokensError, raise_general_exception |
59 | | -from supertokens_python.recipe.multitenancy.recipe import MultitenancyRecipe |
| 57 | +from supertokens_python.recipe.dashboard.utils import get_api_path_with_dashboard_base |
60 | 58 |
|
61 | 59 | from .constants import ( |
62 | 60 | DASHBOARD_ANALYTICS_API, |
|
77 | 75 | ) |
78 | 76 | from .utils import ( |
79 | 77 | InputOverrideConfig, |
80 | | - get_api_if_matched, |
81 | | - is_api_path, |
82 | 78 | validate_and_normalise_user_input, |
83 | 79 | ) |
84 | 80 |
|
@@ -119,14 +115,140 @@ def is_error_from_this_recipe_based_on_instance(self, err: Exception) -> bool: |
119 | 115 | ) |
120 | 116 |
|
121 | 117 | def get_apis_handled(self) -> List[APIHandled]: |
122 | | - # Normally this array is used by the SDK to decide whether the recipe |
123 | | - # handles a specific API path and method and then returns the ID. |
124 | | - |
125 | | - # However, for the dashboard recipe this logic is fully custom and handled inside the |
126 | | - # `return_api_id_if_can_handle_request` method of this class. Since this array is never |
127 | | - # used for this recipe, we simply return an empty array. |
128 | | - |
129 | | - return [] |
| 118 | + return [ |
| 119 | + APIHandled( |
| 120 | + NormalisedURLPath(get_api_path_with_dashboard_base("/")), |
| 121 | + "get", |
| 122 | + DASHBOARD_API, |
| 123 | + False, |
| 124 | + ), |
| 125 | + APIHandled( |
| 126 | + NormalisedURLPath( |
| 127 | + get_api_path_with_dashboard_base(EMAIL_PASSWORD_SIGN_IN) |
| 128 | + ), |
| 129 | + "post", |
| 130 | + EMAIL_PASSWORD_SIGN_IN, |
| 131 | + False, |
| 132 | + ), |
| 133 | + APIHandled( |
| 134 | + NormalisedURLPath(get_api_path_with_dashboard_base(VALIDATE_KEY_API)), |
| 135 | + "post", |
| 136 | + VALIDATE_KEY_API, |
| 137 | + False, |
| 138 | + ), |
| 139 | + APIHandled( |
| 140 | + NormalisedURLPath( |
| 141 | + get_api_path_with_dashboard_base(EMAIL_PASSSWORD_SIGNOUT) |
| 142 | + ), |
| 143 | + "post", |
| 144 | + EMAIL_PASSSWORD_SIGNOUT, |
| 145 | + False, |
| 146 | + ), |
| 147 | + APIHandled( |
| 148 | + NormalisedURLPath(get_api_path_with_dashboard_base(USERS_LIST_GET_API)), |
| 149 | + "get", |
| 150 | + USERS_LIST_GET_API, |
| 151 | + False, |
| 152 | + ), |
| 153 | + APIHandled( |
| 154 | + NormalisedURLPath(get_api_path_with_dashboard_base(USERS_COUNT_API)), |
| 155 | + "get", |
| 156 | + USERS_COUNT_API, |
| 157 | + False, |
| 158 | + ), |
| 159 | + APIHandled( |
| 160 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_API)), |
| 161 | + "get", |
| 162 | + USER_API, |
| 163 | + False, |
| 164 | + ), |
| 165 | + APIHandled( |
| 166 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_API)), |
| 167 | + "post", |
| 168 | + USER_API, |
| 169 | + False, |
| 170 | + ), |
| 171 | + APIHandled( |
| 172 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_API)), |
| 173 | + "put", |
| 174 | + USER_API, |
| 175 | + False, |
| 176 | + ), |
| 177 | + APIHandled( |
| 178 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_API)), |
| 179 | + "delete", |
| 180 | + USER_API, |
| 181 | + False, |
| 182 | + ), |
| 183 | + APIHandled( |
| 184 | + NormalisedURLPath( |
| 185 | + get_api_path_with_dashboard_base(USER_EMAIL_VERIFY_API) |
| 186 | + ), |
| 187 | + "get", |
| 188 | + USER_EMAIL_VERIFY_API, |
| 189 | + False, |
| 190 | + ), |
| 191 | + APIHandled( |
| 192 | + NormalisedURLPath( |
| 193 | + get_api_path_with_dashboard_base(USER_EMAIL_VERIFY_API) |
| 194 | + ), |
| 195 | + "put", |
| 196 | + USER_EMAIL_VERIFY_API, |
| 197 | + False, |
| 198 | + ), |
| 199 | + APIHandled( |
| 200 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_METADATA_API)), |
| 201 | + "get", |
| 202 | + USER_METADATA_API, |
| 203 | + False, |
| 204 | + ), |
| 205 | + APIHandled( |
| 206 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_METADATA_API)), |
| 207 | + "put", |
| 208 | + USER_METADATA_API, |
| 209 | + False, |
| 210 | + ), |
| 211 | + APIHandled( |
| 212 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_SESSION_API)), |
| 213 | + "get", |
| 214 | + USER_SESSION_API, |
| 215 | + False, |
| 216 | + ), |
| 217 | + APIHandled( |
| 218 | + NormalisedURLPath(get_api_path_with_dashboard_base(USER_PASSWORD_API)), |
| 219 | + "put", |
| 220 | + USER_PASSWORD_API, |
| 221 | + False, |
| 222 | + ), |
| 223 | + APIHandled( |
| 224 | + NormalisedURLPath( |
| 225 | + get_api_path_with_dashboard_base(USER_EMAIL_VERIFY_API) |
| 226 | + ), |
| 227 | + "post", |
| 228 | + USER_EMAIL_VERIFY_API, |
| 229 | + False, |
| 230 | + ), |
| 231 | + APIHandled( |
| 232 | + NormalisedURLPath(get_api_path_with_dashboard_base(SEARCH_TAGS_API)), |
| 233 | + "get", |
| 234 | + SEARCH_TAGS_API, |
| 235 | + False, |
| 236 | + ), |
| 237 | + APIHandled( |
| 238 | + NormalisedURLPath( |
| 239 | + get_api_path_with_dashboard_base(DASHBOARD_ANALYTICS_API) |
| 240 | + ), |
| 241 | + "post", |
| 242 | + DASHBOARD_ANALYTICS_API, |
| 243 | + False, |
| 244 | + ), |
| 245 | + APIHandled( |
| 246 | + NormalisedURLPath(get_api_path_with_dashboard_base(TENANTS_LIST_API)), |
| 247 | + "get", |
| 248 | + TENANTS_LIST_API, |
| 249 | + False, |
| 250 | + ), |
| 251 | + ] |
130 | 252 |
|
131 | 253 | async def handle_api_request( |
132 | 254 | self, |
@@ -261,70 +383,3 @@ def reset(): |
261 | 383 | ): |
262 | 384 | raise_general_exception("calling testing function in non testing env") |
263 | 385 | DashboardRecipe.__instance = None |
264 | | - |
265 | | - async def return_api_id_if_can_handle_request( |
266 | | - self, path: NormalisedURLPath, method: str, user_context: Dict[str, Any] |
267 | | - ) -> Union[ApiIdWithTenantId, None]: |
268 | | - dashboard_bundle_path = self.app_info.api_base_path.append( |
269 | | - NormalisedURLPath(DASHBOARD_API) |
270 | | - ) |
271 | | - |
272 | | - base_path_str = self.app_info.api_base_path.get_as_string_dangerous() |
273 | | - path_str = path.get_as_string_dangerous() |
274 | | - regex = rf"^{base_path_str}(?:/([a-zA-Z0-9-]+))?(/.*)$" |
275 | | - # some examples against for above regex: |
276 | | - # books => match = None |
277 | | - # public/books => match = None |
278 | | - # /books => match.group(1) = None, match.group(2) = /dashboard |
279 | | - # /public/books => match.group(1) = 'public', match.group(2) = '/books' |
280 | | - # /public/book/1 => match.group(1) = 'public', match.group(2) = '/book/1' |
281 | | - |
282 | | - match = re.match(regex, path_str) |
283 | | - match_group_1 = match.group(1) if match is not None else None |
284 | | - match_group_2 = match.group(2) if match is not None else None |
285 | | - |
286 | | - tenant_id: str = DEFAULT_TENANT_ID |
287 | | - remaining_path: Optional[NormalisedURLPath] = None |
288 | | - |
289 | | - if ( |
290 | | - match is not None |
291 | | - and isinstance(match_group_1, str) |
292 | | - and isinstance(match_group_2, str) |
293 | | - ): |
294 | | - tenant_id = match_group_1 |
295 | | - remaining_path = NormalisedURLPath(match_group_2) |
296 | | - |
297 | | - mt_recipe = MultitenancyRecipe.get_instance() |
298 | | - |
299 | | - if is_api_path(path, self.app_info.api_base_path) or ( |
300 | | - remaining_path is not None |
301 | | - and is_api_path( |
302 | | - path, |
303 | | - self.app_info.api_base_path.append(NormalisedURLPath(f"/{tenant_id}")), |
304 | | - ) |
305 | | - ): |
306 | | - # check remainingPath first as path that contains tenantId might match as well |
307 | | - # since getApiIdIfMatched uses endsWith to match |
308 | | - if remaining_path is not None: |
309 | | - id_ = get_api_if_matched(remaining_path, method) |
310 | | - if id_ is not None: |
311 | | - final_tenant_id = ( |
312 | | - await mt_recipe.recipe_implementation.get_tenant_id( |
313 | | - DEFAULT_TENANT_ID if tenant_id is None else tenant_id, |
314 | | - user_context, |
315 | | - ) |
316 | | - ) |
317 | | - return ApiIdWithTenantId(id_, final_tenant_id) |
318 | | - |
319 | | - id_ = get_api_if_matched(path, method) |
320 | | - if id_ is not None: |
321 | | - final_tenant_id = await mt_recipe.recipe_implementation.get_tenant_id( |
322 | | - DEFAULT_TENANT_ID, user_context |
323 | | - ) |
324 | | - return ApiIdWithTenantId(id_, final_tenant_id) |
325 | | - |
326 | | - if path.startswith(dashboard_bundle_path): |
327 | | - return ApiIdWithTenantId(DASHBOARD_API, DEFAULT_TENANT_ID) |
328 | | - |
329 | | - # tenantId is not supported for bundlePath, so not matching for it |
330 | | - return None |
|
0 commit comments