Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add support for any type in value field instead of only string #525

Merged
merged 11 commits into from
Sep 24, 2024
Merged
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [0.24.3] - 2024-09-24

- Adds support for form field related improvements by making fields accept any type of values
- Adds support for optional fields to properly optional

## [0.24.2] - 2024-09-03
- Makes optional input form fields truly optional instead of just being able to accept `""`.

Expand Down
4 changes: 3 additions & 1 deletion supertokens_python/recipe/emailpassword/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ async def validate_form_or_throw_error(
input_field: Union[None, FormField] = find_first_occurrence_in_list(
lambda x: x.id == field.id, inputs
)
is_invalid_value = input_field is None or input_field.value == ""
is_invalid_value = input_field is None or (
isinstance(input_field.value, str) and input_field.value == ""
)
deepjyoti30-st marked this conversation as resolved.
Show resolved Hide resolved
if not field.optional and is_invalid_value:
validation_errors.append(ErrorFormField(field.id, "Field is not optional"))
continue
Expand Down
7 changes: 4 additions & 3 deletions supertokens_python/recipe/emailpassword/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import annotations
from typing import Awaitable, Callable, List, TypeVar, Union

from typing import Any, Awaitable, Callable, List, TypeVar, Union

from supertokens_python.ingredients.emaildelivery import EmailDeliveryIngredient
from supertokens_python.ingredients.emaildelivery.types import (
Expand Down Expand Up @@ -53,9 +54,9 @@ def __init__(self, id: str, error: str): # pylint: disable=redefined-builtin


class FormField:
def __init__(self, id: str, value: str): # pylint: disable=redefined-builtin
def __init__(self, id: str, value: Any): # pylint: disable=redefined-builtin
self.id: str = id
self.value: str = value
self.value: Any = value


class InputFormField:
Expand Down
19 changes: 10 additions & 9 deletions supertokens_python/recipe/emailpassword/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
from __future__ import annotations

from re import fullmatch
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union, Dict
from supertokens_python.framework import BaseRequest
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union

from supertokens_python.framework import BaseRequest
from supertokens_python.ingredients.emaildelivery.types import (
EmailDeliveryConfig,
EmailDeliveryConfigWithService,
Expand All @@ -26,17 +26,14 @@
)

from .interfaces import APIInterface, RecipeInterface
from .types import InputFormField, NormalisedFormField, EmailTemplateVars
from .types import EmailTemplateVars, InputFormField, NormalisedFormField

if TYPE_CHECKING:
from supertokens_python.supertokens import AppInfo

from supertokens_python.utils import get_filtered_list

from .constants import (
FORM_FIELD_EMAIL_ID,
FORM_FIELD_PASSWORD_ID,
)
from .constants import FORM_FIELD_EMAIL_ID, FORM_FIELD_PASSWORD_ID


async def default_validator(_: str, __: str) -> Union[str, None]:
Expand Down Expand Up @@ -261,10 +258,14 @@ def validate_and_normalise_user_input(
email_delivery: Union[EmailDeliveryConfig[EmailTemplateVars], None] = None,
) -> EmailPasswordConfig:

if sign_up_feature is not None and not isinstance(sign_up_feature, InputSignUpFeature): # type: ignore
# type: ignore
deepjyoti30-st marked this conversation as resolved.
Show resolved Hide resolved
if sign_up_feature is not None and not isinstance(
sign_up_feature, InputSignUpFeature
):
raise ValueError("sign_up_feature must be of type InputSignUpFeature or None")

if override is not None and not isinstance(override, InputOverrideConfig): # type: ignore
# type: ignore
if override is not None and not isinstance(override, InputOverrideConfig):
raise ValueError("override must be of type InputOverrideConfig or None")

if override is None:
Expand Down
42 changes: 42 additions & 0 deletions tests/emailpassword/test_signin.py
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,48 @@ async def test_optional_custom_field_without_input(driver_config_client: TestCli
assert dict_response["status"] == "OK"


@mark.asyncio
async def test_non_optional_custom_field_with_boolean_value(
driver_config_client: TestClient,
):
init(
supertokens_config=SupertokensConfig("http://localhost:3567"),
app_info=InputAppInfo(
app_name="SuperTokens Demo",
api_domain="http://api.supertokens.io",
website_domain="http://supertokens.io",
api_base_path="/auth",
),
framework="fastapi",
recipe_list=[
emailpassword.init(
sign_up_feature=emailpassword.InputSignUpFeature(
form_fields=[
emailpassword.InputFormField("autoVerify", optional=False)
]
)
),
session.init(get_token_transfer_method=lambda _, __, ___: "cookie"),
],
)
start_st()

response_1 = driver_config_client.post(
url="/auth/signup",
headers={"Content-Type": "application/json"},
json={
"formFields": [
{"id": "email", "value": "[email protected]"},
{"id": "password", "value": "validpassword123"},
{"id": "autoVerify", "value": False},
]
},
)
assert response_1.status_code == 200
dict_response = json.loads(response_1.text)
assert dict_response["status"] == "OK"


@mark.asyncio
async def test_too_many_fields(driver_config_client: TestClient):
init(
Expand Down
Loading