Skip to content

Commit dfb5442

Browse files
authored
Merge pull request #297 from supertokens/dashboard-search
feat: search apis for dashboard
2 parents eebbc0f + 4f66123 commit dfb5442

File tree

14 files changed

+84
-3
lines changed

14 files changed

+84
-3
lines changed

supertokens_python/framework/django/django_request.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import annotations
1515

1616
import json
17-
from typing import TYPE_CHECKING, Any, Union
17+
from typing import TYPE_CHECKING, Any, Dict, Union
1818
from urllib.parse import parse_qsl
1919

2020
from supertokens_python.framework.request import BaseRequest
@@ -35,6 +35,9 @@ def get_query_param(
3535
) -> Union[str, None]:
3636
return self.request.GET.get(key, default)
3737

38+
def get_query_params(self) -> Dict[str, Any]:
39+
return self.request.GET.dict()
40+
3841
async def json(self) -> Union[Any, None]:
3942
try:
4043
body = json.loads(self.request.body)

supertokens_python/framework/fastapi/fastapi_request.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# under the License.
1414
from __future__ import annotations
1515

16-
from typing import TYPE_CHECKING, Any, Union
16+
from typing import TYPE_CHECKING, Any, Dict, Union
1717
from urllib.parse import parse_qsl
1818

1919
from supertokens_python.framework.request import BaseRequest
@@ -35,6 +35,9 @@ def get_query_param(
3535
) -> Union[str, None]:
3636
return self.request.query_params.get(key, default)
3737

38+
def get_query_params(self) -> Dict[str, Any]:
39+
return dict(self.request.query_params.items()) # type: ignore
40+
3841
async def json(self) -> Union[Any, None]:
3942
try:
4043
return await self.request.json()

supertokens_python/framework/flask/flask_request.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ def __init__(self, req: Request):
3131
def get_query_param(self, key: str, default: Union[str, None] = None):
3232
return self.request.args.get(key, default)
3333

34+
def get_query_params(self) -> Dict[str, Any]:
35+
return self.request.args.to_dict()
36+
3437
async def json(self) -> Union[Any, None]:
3538
try:
3639
return self.request.get_json()

supertokens_python/framework/request.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ def get_query_param(
3131
) -> Union[str, None]:
3232
pass
3333

34+
@abstractmethod
35+
def get_query_params(self) -> Dict[str, Any]:
36+
pass
37+
3438
@abstractmethod
3539
async def json(self) -> Union[Any, None]:
3640
pass

supertokens_python/recipe/dashboard/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# under the License.
1414
from .api_key_protector import api_key_protector
1515
from .dashboard import handle_dashboard_api
16+
from .search.getTags import handle_get_tags
1617
from .signin import handle_emailpassword_signin_api
1718
from .signout import handle_emailpassword_signout_api
1819
from .userdetails.user_delete import handle_user_delete
@@ -49,4 +50,5 @@
4950
"handle_email_verify_token_post",
5051
"handle_emailpassword_signin_api",
5152
"handle_emailpassword_signout_api",
53+
"handle_get_tags",
5254
]

supertokens_python/recipe/dashboard/api/implementation.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from supertokens_python import Supertokens
2121
from supertokens_python.normalised_url_domain import NormalisedURLDomain
2222
from supertokens_python.normalised_url_path import NormalisedURLPath
23+
from supertokens_python.querier import Querier
24+
from supertokens_python.utils import is_version_gte
2325

2426
from ..constants import DASHBOARD_API
2527
from ..interfaces import APIInterface
@@ -54,6 +56,14 @@ async def dashboard_get(
5456
NormalisedURLPath(DASHBOARD_API)
5557
).get_as_string_dangerous()
5658

59+
is_search_enabled: bool = False
60+
querier = Querier.get_instance(options.recipe_id)
61+
cdiVersion = await querier.get_api_version()
62+
if not cdiVersion:
63+
return ""
64+
if is_version_gte(cdiVersion, "2.20"):
65+
is_search_enabled = True
66+
5767
return Template(
5868
dedent(
5969
"""
@@ -65,6 +75,7 @@ async def dashboard_get(
6575
window.dashboardAppPath = "${dashboardPath}"
6676
window.connectionURI = "${connectionURI}"
6777
window.authMode = "${authMode}"
78+
window.isSearchEnabled = "${isSearchEnabled}"
6879
</script>
6980
<script defer src="${bundleDomain}/static/js/bundle.js"></script></head>
7081
<link href="${bundleDomain}/static/css/main.css" rel="stylesheet" type="text/css">
@@ -82,6 +93,7 @@ async def dashboard_get(
8293
dashboardPath=dashboard_path,
8394
connectionURI=connection_uri,
8495
authMode=auth_mode,
96+
isSearchEnabled=is_search_enabled,
8597
)
8698

8799
self.dashboard_get = dashboard_get

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

Whitespace-only changes.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright (c) 2021, 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+
from __future__ import annotations
15+
16+
from typing import TYPE_CHECKING
17+
18+
if TYPE_CHECKING:
19+
from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions
20+
21+
from supertokens_python.normalised_url_path import NormalisedURLPath
22+
from supertokens_python.querier import Querier
23+
from supertokens_python.recipe.dashboard.interfaces import SearchTagsOK
24+
25+
26+
async def handle_get_tags(_: APIInterface, __: APIOptions) -> SearchTagsOK:
27+
response = await Querier.get_instance().send_get_request(
28+
NormalisedURLPath("/user/search/tags")
29+
)
30+
return SearchTagsOK(tags=response["tags"])

supertokens_python/recipe/dashboard/api/users_get.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ async def handle_users_get_api(
5555
time_joined_order=time_joined_order, # type: ignore
5656
pagination_token=pagination_token,
5757
include_recipe_ids=None,
58+
query=api_options.request.get_query_params(),
5859
)
5960

6061
# user metadata bulk fetch with batches:

supertokens_python/recipe/dashboard/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
USER_EMAIL_VERIFY_TOKEN_API = "/api/user/email/verify/token"
1111
EMAIL_PASSWORD_SIGN_IN = "/api/signin"
1212
EMAIL_PASSSWORD_SIGNOUT = "/api/signout"
13+
SEARCH_TAGS_API = "/api/search/tags"

supertokens_python/recipe/dashboard/interfaces.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,14 @@ class SignOutOK(APIResponse):
293293

294294
def to_json(self):
295295
return {"status": self.status}
296+
297+
298+
class SearchTagsOK(APIResponse):
299+
status: str = "OK"
300+
tags: List[str]
301+
302+
def __init__(self, tags: List[str]) -> None:
303+
self.tags = tags
304+
305+
def to_json(self):
306+
return {"status": self.status, "tags": self.tags}

supertokens_python/recipe/dashboard/recipe.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
handle_email_verify_token_post,
2626
handle_emailpassword_signin_api,
2727
handle_emailpassword_signout_api,
28+
handle_get_tags,
2829
handle_metadata_get,
2930
handle_metadata_put,
3031
handle_sessions_get,
@@ -56,6 +57,7 @@
5657
DASHBOARD_API,
5758
EMAIL_PASSSWORD_SIGNOUT,
5859
EMAIL_PASSWORD_SIGN_IN,
60+
SEARCH_TAGS_API,
5961
USER_API,
6062
USER_EMAIL_VERIFY_API,
6163
USER_EMAIL_VERIFY_TOKEN_API,
@@ -181,6 +183,8 @@ async def handle_api_request(
181183
api_function = handle_email_verify_token_post
182184
elif request_id == EMAIL_PASSSWORD_SIGNOUT:
183185
api_function = handle_emailpassword_signout_api
186+
elif request_id == SEARCH_TAGS_API:
187+
api_function = handle_get_tags
184188

185189
if api_function is not None:
186190
return await api_key_protector(

supertokens_python/recipe/dashboard/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
DASHBOARD_API,
5252
EMAIL_PASSSWORD_SIGNOUT,
5353
EMAIL_PASSWORD_SIGN_IN,
54+
SEARCH_TAGS_API,
5455
USER_API,
5556
USER_EMAIL_VERIFY_API,
5657
USER_EMAIL_VERIFY_TOKEN_API,
@@ -237,6 +238,8 @@ def get_api_if_matched(path: NormalisedURLPath, method: str) -> Optional[str]:
237238
return EMAIL_PASSWORD_SIGN_IN
238239
if path_str.endswith(EMAIL_PASSSWORD_SIGNOUT) and method == "post":
239240
return EMAIL_PASSSWORD_SIGNOUT
241+
if path_str.endswith(SEARCH_TAGS_API) and method == "get":
242+
return SEARCH_TAGS_API
240243

241244
return None
242245

supertokens_python/supertokens.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
from .utils import (
5050
execute_async,
5151
get_rid_from_header,
52+
get_top_level_domain_for_same_site_resolution,
5253
is_version_gte,
5354
normalise_http_method,
5455
send_non_200_response_with_message,
55-
get_top_level_domain_for_same_site_resolution,
5656
)
5757

5858
if TYPE_CHECKING:
@@ -328,6 +328,7 @@ async def get_users( # pylint: disable=no-self-use
328328
limit: Union[int, None],
329329
pagination_token: Union[str, None],
330330
include_recipe_ids: Union[None, List[str]],
331+
query: Union[Dict[str, str], None] = None,
331332
) -> UsersResponse:
332333
querier = Querier.get_instance(None)
333334
params = {"timeJoinedOrder": time_joined_order}
@@ -341,6 +342,9 @@ async def get_users( # pylint: disable=no-self-use
341342
include_recipe_ids_str = ",".join(include_recipe_ids)
342343
params = {"includeRecipeIds": include_recipe_ids_str, **params}
343344

345+
if query is not None:
346+
params = {**params, **query}
347+
344348
response = await querier.send_get_request(NormalisedURLPath(USERS), params)
345349
next_pagination_token = None
346350
if "nextPaginationToken" in response:

0 commit comments

Comments
 (0)