-
Notifications
You must be signed in to change notification settings - Fork 32
🎨 web-api: patch userName at least 4 chars ⚠️
#7389
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
Merged
pcrespov
merged 8 commits into
ITISFoundation:master
from
pcrespov:is33/limit-username-lenght
Mar 19, 2025
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
5b56377
adds min lengh in patch
pcrespov a647ae7
splits tests
pcrespov 2acae90
split tests
pcrespov 814e4b1
OAS
pcrespov b33cb8e
services/webserver api version: 0.61.1 → 0.61.2
pcrespov 416a13c
autogenerate username > 4
pcrespov 8384a3d
improves tests for coverage
pcrespov dfda292
fixes mypy
pcrespov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
packages/models-library/tests/test_api_schemas_webserver_users.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # pylint: disable=redefined-outer-name | ||
| # pylint: disable=too-many-arguments | ||
| # pylint: disable=unused-argument | ||
| # pylint: disable=unused-variable | ||
|
|
||
| from copy import deepcopy | ||
|
|
||
| import pytest | ||
| from common_library.users_enums import UserRole | ||
| from models_library.api_schemas_webserver.users import ( | ||
| MyProfileGet, | ||
| MyProfilePatch, | ||
| ) | ||
| from pydantic import ValidationError | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("user_role", [u.name for u in UserRole]) | ||
| def test_profile_get_role(user_role: str): | ||
| for example in MyProfileGet.model_json_schema()["examples"]: | ||
| data = deepcopy(example) | ||
| data["role"] = user_role | ||
| m1 = MyProfileGet(**data) | ||
|
|
||
| data["role"] = UserRole(user_role) | ||
| m2 = MyProfileGet(**data) | ||
| assert m1 == m2 | ||
|
|
||
|
|
||
| def test_my_profile_patch_username_min_len(): | ||
| # minimum length username is 4 | ||
| with pytest.raises(ValidationError) as err_info: | ||
| MyProfilePatch.model_validate({"userName": "abc"}) | ||
|
|
||
| assert err_info.value.error_count() == 1 | ||
| assert err_info.value.errors()[0]["type"] == "too_short" | ||
|
|
||
| MyProfilePatch.model_validate({"userName": "abcd"}) # OK | ||
|
|
||
|
|
||
| def test_my_profile_patch_username_valid_characters(): | ||
| # Ensure valid characters (alphanumeric + . _ -) | ||
| with pytest.raises(ValidationError, match="start with a letter") as err_info: | ||
| MyProfilePatch.model_validate({"userName": "1234"}) | ||
|
|
||
| assert err_info.value.error_count() == 1 | ||
| assert err_info.value.errors()[0]["type"] == "value_error" | ||
|
|
||
| MyProfilePatch.model_validate({"userName": "u1234"}) # OK | ||
|
|
||
|
|
||
| def test_my_profile_patch_username_special_characters(): | ||
| # Ensure no consecutive special characters | ||
| with pytest.raises( | ||
| ValidationError, match="consecutive special characters" | ||
| ) as err_info: | ||
| MyProfilePatch.model_validate({"userName": "u1__234"}) | ||
|
|
||
| assert err_info.value.error_count() == 1 | ||
| assert err_info.value.errors()[0]["type"] == "value_error" | ||
|
|
||
| MyProfilePatch.model_validate({"userName": "u1_234"}) # OK | ||
|
|
||
| # Ensure it doesn't end with a special character | ||
| with pytest.raises(ValidationError, match="end with") as err_info: | ||
| MyProfilePatch.model_validate({"userName": "u1234_"}) | ||
|
|
||
| assert err_info.value.error_count() == 1 | ||
| assert err_info.value.errors()[0]["type"] == "value_error" | ||
|
|
||
| MyProfilePatch.model_validate({"userName": "u1_234"}) # OK | ||
|
|
||
|
|
||
| def test_my_profile_patch_username_reserved_words(): | ||
| # Check reserved words (example list; extend as needed) | ||
| with pytest.raises(ValidationError, match="cannot be used") as err_info: | ||
| MyProfilePatch.model_validate({"userName": "admin"}) | ||
|
|
||
| assert err_info.value.error_count() == 1 | ||
| assert err_info.value.errors()[0]["type"] == "value_error" | ||
|
|
||
| MyProfilePatch.model_validate({"userName": "midas"}) # OK |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 0.61.1 | ||
| 0.61.2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,9 @@ | ||
| # pylint: disable=protected-access | ||
| # pylint: disable=redefined-outer-name | ||
| # pylint: disable=too-many-arguments | ||
| # pylint: disable=unused-argument | ||
| # pylint: disable=unused-variable | ||
| # pylint: disable=too-many-arguments | ||
|
|
||
| import itertools | ||
| from copy import deepcopy | ||
| from datetime import UTC, datetime | ||
| from typing import Any | ||
|
|
||
|
|
@@ -16,46 +15,12 @@ | |
| MyProfilePrivacyGet, | ||
| ) | ||
| from models_library.generics import Envelope | ||
| from models_library.users import UserThirdPartyToken | ||
| from models_library.utils.fastapi_encoders import jsonable_encoder | ||
| from pydantic import BaseModel | ||
| from pytest_simcore.pydantic_models import ( | ||
| assert_validation_model, | ||
| iter_model_examples_in_class, | ||
| ) | ||
| from servicelib.rest_constants import RESPONSE_MODEL_POLICY | ||
| from simcore_postgres_database.models.users import UserRole | ||
| from simcore_postgres_database import utils_users | ||
| from simcore_service_webserver.users._common.models import ToUserUpdateDB | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "model_cls, example_name, example_data", | ||
| itertools.chain( | ||
| iter_model_examples_in_class(MyProfileGet), | ||
| iter_model_examples_in_class(UserThirdPartyToken), | ||
| ), | ||
| ) | ||
| def test_user_models_examples( | ||
| model_cls: type[BaseModel], example_name: str, example_data: Any | ||
| ): | ||
| model_instance = assert_validation_model( | ||
| model_cls, example_name=example_name, example_data=example_data | ||
| ) | ||
|
|
||
| model_enveloped = Envelope[model_cls].from_data( | ||
| model_instance.model_dump(by_alias=True) | ||
| ) | ||
| model_array_enveloped = Envelope[list[model_cls]].from_data( | ||
| [ | ||
| model_instance.model_dump(by_alias=True), | ||
| model_instance.model_dump(by_alias=True), | ||
| ] | ||
| ) | ||
|
|
||
| assert model_enveloped.error is None | ||
| assert model_array_enveloped.error is None | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def fake_profile_get(faker: Faker) -> MyProfileGet: | ||
| fake_profile: dict[str, Any] = faker.simple_profile() | ||
|
|
@@ -104,18 +69,6 @@ def test_auto_compute_gravatar__deprecated(fake_profile_get: MyProfileGet): | |
| assert data["preferences"] == profile.preferences | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("user_role", [u.name for u in UserRole]) | ||
| def test_profile_get_role(user_role: str): | ||
| for example in MyProfileGet.model_json_schema()["examples"]: | ||
| data = deepcopy(example) | ||
| data["role"] = user_role | ||
| m1 = MyProfileGet(**data) | ||
|
|
||
| data["role"] = UserRole(user_role) | ||
| m2 = MyProfileGet(**data) | ||
| assert m1 == m2 | ||
|
|
||
|
|
||
| def test_parsing_output_of_get_user_profile(): | ||
| result_from_db_query_and_composition = { | ||
| "id": 1, | ||
|
|
@@ -185,3 +138,12 @@ def test_mapping_update_models_from_rest_to_db(): | |
| "name": "foo1234", | ||
| "privacy_hide_fullname": False, | ||
| } | ||
|
|
||
|
|
||
| def test_utils_user_generates_valid_myprofile_patch(): | ||
| username = utils_users._generate_username_from_email("[email protected]") # noqa: SLF001 | ||
|
|
||
| MyProfilePatch.model_validate({"userName": username}) | ||
| MyProfilePatch.model_validate( | ||
| {"userName": utils_users.generate_alternative_username(username)} | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.