Skip to content

fix(profile): enforce profile name validation and input constraints#15694

Open
carlh7777 wants to merge 2 commits into
infiniflow:mainfrom
carlh7777:fix/input-validation
Open

fix(profile): enforce profile name validation and input constraints#15694
carlh7777 wants to merge 2 commits into
infiniflow:mainfrom
carlh7777:fix/input-validation

Conversation

@carlh7777
Copy link
Copy Markdown

What problem does this PR solve?

The Profile Name field currently lacks application-level validation and allows users to save excessively long names and unsupported special characters.

While the database enforces a maximum length of 100 characters, neither the frontend nor backend validates nickname format before persistence. This can result in inconsistent user data, poor user experience, and UI layout issues when long names wrap across multiple lines.

This PR introduces consistent frontend and backend validation for profile names, enforces length and character constraints, provides clear validation feedback, and prevents invalid values from being saved.

Fixes #15693

Type of change

  • Bug Fix (non-breaking change which fixes an issue)
  • New Feature (non-breaking change which adds functionality)
  • Documentation Update
  • Refactoring
  • Performance Improvement
  • Other (please describe):

Screenshots

image

- Introduced a new constant `NICKNAME_MAX_LENGTH` in `api/constants.py` to define the maximum length for user nicknames.
- Implemented `validate_nickname` function in `api/utils/validation_utils.py` to enforce nickname rules, including character validation and length checks.
- Updated `setting_user` and `user_add` functions in `user_api.py` to validate nicknames during user updates and additions.
- Enhanced frontend validation in user settings to reflect nickname constraints, including error messages for invalid input.
- Added unit tests to ensure nickname validation works as expected.

This change improves user experience by enforcing consistent nickname rules across the application.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. 🐞 bug Something isn't working, pull request that fix bug. labels Jun 5, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a6c2b0d-3b0c-489f-841a-70e2add3e59c

📥 Commits

Reviewing files that changed from the base of the PR and between ed41073 and bad7987.

📒 Files selected for processing (3)
  • api/utils/validation_utils.py
  • test/unit_test/api/utils/test_nickname_validation.py
  • web/src/pages/user-setting/profile/constants.ts
✅ Files skipped from review due to trivial changes (1)
  • web/src/pages/user-setting/profile/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • api/utils/validation_utils.py
  • test/unit_test/api/utils/test_nickname_validation.py

📝 Walkthrough

Walkthrough

Adds nickname validation end-to-end: a 100-character max and allowed-character regex on backend and frontend, integrates validation into registration and profile update endpoints, includes unit tests, localized error messages, and minor UI/input attribute adjustments.

Changes

Nickname Validation Implementation

Layer / File(s) Summary
Backend validation logic and constants
api/constants.py, api/utils/validation_utils.py
Adds NICKNAME_MAX_LENGTH = 100 and implements _NICKNAME_PATTERN plus validate_nickname() which trims input, enforces presence, max length, and allowed characters; returns standardized error tuples.
Backend API endpoint integration
api/apps/restful_apis/user_api.py
Imports validate_nickname and applies it in PATCH /users/me (settings update) and POST /users (registration); invalid nicknames return structured argument errors; valid nicknames are stripped before persistence.
Backend validation testing
test/unit_test/api/utils/test_nickname_validation.py, test/testcases/test_web_api/test_user_app/test_user_app_unit.py
Adds parametrized tests for valid and invalid nickname inputs and an endpoint-level assertion ensuring invalid-character nicknames produce RetCode.ARGUMENT_ERROR.
Frontend validation constants
web/src/pages/user-setting/profile/constants.ts
Exports NICKNAME_MAX_LENGTH (100) and NICKNAME_PATTERN (Unicode-aware regex) for client-side validation.
Frontend form validation and UI
web/src/pages/user-setting/profile/index.tsx
Updates username Zod schema with maxLength and pattern checks using i18n messages, adds maxLength attribute to the input, and adjusts display container classes (min-w-0, truncate) to manage overflow.
Frontend localized error messages
web/src/locales/en.ts, web/src/locales/zh.ts
Adds usernameMaxLength and usernameInvalidCharacters translation keys for validation feedback.

Sequence Diagram(s):

sequenceDiagram
  participant Client
  participant FrontendForm
  participant UserAPI
  participant ValidationUtils
  Client->>FrontendForm: Enter nickname
  FrontendForm->>ValidationUtils: (client-side) validate via NICKNAME_PATTERN / maxLength
  FrontendForm-->>Client: show client-side validation errors or submit
  FrontendForm->>UserAPI: POST/PATCH with nickname
  UserAPI->>ValidationUtils: validate_nickname(nickname)
  ValidationUtils-->>UserAPI: (error_message, code) or (None, None)
  UserAPI-->>FrontendForm: structured error response or success
Loading

Estimated code review effort:
🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels:
size:L

"🐰 I nibbled at strings, trimmed them neat,
Bounded the name so UI keeps its seat,
Regex to guard each curious char,
Now profiles stay tidy, near and far!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: enforcing profile name validation and input constraints on the profile name field.
Description check ✅ Passed The description follows the template, provides clear context about the problem, explicitly states the type of change (Bug Fix), references the linked issue (#15693), and includes validation details.
Linked Issues check ✅ Passed The PR fully addresses the objectives from linked issue #15693: enforces maximum length (100 chars) via NICKNAME_MAX_LENGTH, restricts invalid characters via NICKNAME_PATTERN regex, validates on both frontend and backend, provides user feedback via i18n messages, and prevents invalid values from persisting.
Out of Scope Changes check ✅ Passed All code changes are directly related to nickname/profile name validation as specified in issue #15693; no unrelated modifications or scope creep detected across frontend, backend, tests, and localization files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
test/unit_test/api/utils/test_nickname_validation.py (3)

24-37: ⚡ Quick win

Consider adding a test case for leading/trailing whitespace.

The validation function strips whitespace before checking (line 1105 in validation_utils.py), so a nickname like " John Doe " should pass validation. Adding this test case would verify the trimming behavior explicitly.

🧪 Suggested test case
`@pytest.mark.parametrize`(
    "nickname",
    [
        "John Doe",
        "张三",
        "O'Brien",
        "valid-name_123",
        "a" * NICKNAME_MAX_LENGTH,
        "  trimmed  ",  # Leading/trailing whitespace should be accepted
    ],
)
def test_validate_nickname_accepts_valid_values(nickname):
    message, code = validate_nickname(nickname)
    assert message is None
    assert code is None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit_test/api/utils/test_nickname_validation.py` around lines 24 - 37,
Add a test case verifying leading/trailing whitespace is accepted by
validate_nickname: update the pytest.parametrize list in
test_validate_nickname_accepts_valid_values (file test_nickname_validation.py)
to include a nickname like "  trimmed  " so the test asserts
validate_nickname(str) returns (None, None) for inputs that are
whitespace-trimmed by the validate_nickname function.

40-52: ⚡ Quick win

Consider adding a test case for None input.

The validate_nickname function explicitly handles None input at line 1102 and returns "Nickname is required.". Adding a test case for this would improve coverage and document the expected behavior.

🧪 Suggested test case
`@pytest.mark.parametrize`(
    "nickname, expected_message",
    [
        (None, "Nickname is required."),
        ("", "Nickname cannot be empty."),
        ("   ", "Nickname cannot be empty."),
        ("carh!@#$%^&*()_+WFAGD", "Nickname contains invalid characters."),
        ("a" * (NICKNAME_MAX_LENGTH + 1), f"Nickname must be at most {NICKNAME_MAX_LENGTH} characters."),
    ],
)
def test_validate_nickname_rejects_invalid_values(nickname, expected_message):
    message, code = validate_nickname(nickname)
    assert message == expected_message
    assert code == RetCode.ARGUMENT_ERROR
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit_test/api/utils/test_nickname_validation.py` around lines 40 - 52,
Add a test case for None input to the existing
test_validate_nickname_rejects_invalid_values parametrized test: include (None,
"Nickname is required.") in the parametrized list so that calling
validate_nickname(None) asserts the expected message and RetCode.ARGUMENT_ERROR;
update the tuple list in test_validate_nickname_rejects_invalid_values in
test_nickname_validation.py to include this case, keeping the test function name
and assertions unchanged.

24-52: ⚡ Quick win

Add pytest priority markers per coding guidelines.

The coding guidelines specify "Use pytest with priority markers (p1/p2/p3) for Python testing." These test functions should be marked with an appropriate priority level.

📝 Suggested markers
+@pytest.mark.p1
 `@pytest.mark.parametrize`(
     "nickname",
     [
+@pytest.mark.p1
 `@pytest.mark.parametrize`(
     "nickname, expected_message",
     [

As per coding guidelines: "Use pytest with priority markers (p1/p2/p3) for Python testing."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit_test/api/utils/test_nickname_validation.py` around lines 24 - 52,
Add the required pytest priority markers to the two test functions: annotate
test_validate_nickname_accepts_valid_values and
test_validate_nickname_rejects_invalid_values with the appropriate priority
marker (e.g., `@pytest.mark.p1`) immediately above each def so the tests comply
with the project's pytest priority convention; ensure the marker is
imported/available from pytest if needed.
api/utils/validation_utils.py (1)

1094-1113: 💤 Low value

Consider returning the stripped nickname on success.

The function strips the nickname at line 1105 for validation but discards the result on success, forcing callers to strip again (see user_api.py lines 368 and 532). Returning the stripped value would eliminate this duplication.

♻️ Proposed refactor
-def validate_nickname(nickname: str | None) -> tuple[str | None, int | None]:
+def validate_nickname(nickname: str | None) -> tuple[str | None, int | None, str | None]:
     """
     Validate a user nickname/display name.
 
     Returns:
-        A tuple of (error_message, error_code) if validation fails,
-        or (None, None) if validation passes.
+        A tuple of (error_message, error_code, None) if validation fails,
+        or (None, None, stripped_nickname) if validation passes.
     """
     if nickname is None:
-        return "Nickname is required.", RetCode.ARGUMENT_ERROR
+        return "Nickname is required.", RetCode.ARGUMENT_ERROR, None
     
     nickname = nickname.strip()
     if not nickname:
-        return "Nickname cannot be empty.", RetCode.ARGUMENT_ERROR
+        return "Nickname cannot be empty.", RetCode.ARGUMENT_ERROR, None
     if len(nickname) > NICKNAME_MAX_LENGTH:
-        return f"Nickname must be at most {NICKNAME_MAX_LENGTH} characters.", RetCode.ARGUMENT_ERROR
+        return f"Nickname must be at most {NICKNAME_MAX_LENGTH} characters.", RetCode.ARGUMENT_ERROR, None
     if not _NICKNAME_PATTERN.fullmatch(nickname):
-        return "Nickname contains invalid characters.", RetCode.ARGUMENT_ERROR
-    return None, None
+        return "Nickname contains invalid characters.", RetCode.ARGUMENT_ERROR, None
+    return None, None, nickname

Then update callers to use the returned stripped value instead of stripping again.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/utils/validation_utils.py` around lines 1094 - 1113, Change
validate_nickname to return the cleaned/stripped nickname on success so callers
don't have to strip again: update the function signature/type annotations and
docstring for validate_nickname to return (error_message: str | None,
error_code: int | None, cleaned_nickname: str | None), perform nickname =
nickname.strip() as you already do, and on success return (None, None,
nickname); update callers (e.g., the places in user_api.py that currently call
validate_nickname and then call .strip() again) to accept the third return value
and use the returned cleaned_nickname instead of re-stripping.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/utils/validation_utils.py`:
- Around line 1094-1113: Update validate_nickname to accept Optional strings and
defensively handle non-string input: change the parameter type from str to str |
None (or Optional[str]) and keep the existing None check, but add an
isinstance(nickname, str) guard that returns an ARGUMENT_ERROR message (e.g.,
"Nickname must be a string.") if the input is not a string; then proceed with
.strip(), length check against NICKNAME_MAX_LENGTH, and pattern check with
_NICKNAME_PATTERN, returning errors via RetCode where appropriate.

In `@web/src/pages/user-setting/profile/constants.ts`:
- Line 3: NICKNAME_PATTERN uses JS \w which is ASCII-only and causes a
frontend/backend mismatch; update the constant NICKNAME_PATTERN in
web/src/pages/user-setting/profile/constants.ts to use Unicode property escapes
(e.g. include \p{L}, \p{N}, and combining marks \p{M} plus whitespace and
allowed punctuation) with the u flag instead of \w so the pattern matches the
backend's Unicode-aware \w behavior; ensure the new regex still allows spaces,
periods, apostrophes and hyphens and add a quick test with non-Latin nicknames
to verify parity with api/utils/validation_utils.py.

---

Nitpick comments:
In `@api/utils/validation_utils.py`:
- Around line 1094-1113: Change validate_nickname to return the cleaned/stripped
nickname on success so callers don't have to strip again: update the function
signature/type annotations and docstring for validate_nickname to return
(error_message: str | None, error_code: int | None, cleaned_nickname: str |
None), perform nickname = nickname.strip() as you already do, and on success
return (None, None, nickname); update callers (e.g., the places in user_api.py
that currently call validate_nickname and then call .strip() again) to accept
the third return value and use the returned cleaned_nickname instead of
re-stripping.

In `@test/unit_test/api/utils/test_nickname_validation.py`:
- Around line 24-37: Add a test case verifying leading/trailing whitespace is
accepted by validate_nickname: update the pytest.parametrize list in
test_validate_nickname_accepts_valid_values (file test_nickname_validation.py)
to include a nickname like "  trimmed  " so the test asserts
validate_nickname(str) returns (None, None) for inputs that are
whitespace-trimmed by the validate_nickname function.
- Around line 40-52: Add a test case for None input to the existing
test_validate_nickname_rejects_invalid_values parametrized test: include (None,
"Nickname is required.") in the parametrized list so that calling
validate_nickname(None) asserts the expected message and RetCode.ARGUMENT_ERROR;
update the tuple list in test_validate_nickname_rejects_invalid_values in
test_nickname_validation.py to include this case, keeping the test function name
and assertions unchanged.
- Around line 24-52: Add the required pytest priority markers to the two test
functions: annotate test_validate_nickname_accepts_valid_values and
test_validate_nickname_rejects_invalid_values with the appropriate priority
marker (e.g., `@pytest.mark.p1`) immediately above each def so the tests comply
with the project's pytest priority convention; ensure the marker is
imported/available from pytest if needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b89bbe43-e546-4c14-b8af-2015a07caa2d

📥 Commits

Reviewing files that changed from the base of the PR and between f78ef32 and ed41073.

📒 Files selected for processing (9)
  • api/apps/restful_apis/user_api.py
  • api/constants.py
  • api/utils/validation_utils.py
  • test/testcases/test_web_api/test_user_app/test_user_app_unit.py
  • test/unit_test/api/utils/test_nickname_validation.py
  • web/src/locales/en.ts
  • web/src/locales/zh.ts
  • web/src/pages/user-setting/profile/constants.ts
  • web/src/pages/user-setting/profile/index.tsx

Comment thread api/utils/validation_utils.py Outdated
Comment thread web/src/pages/user-setting/profile/constants.ts Outdated
- Updated `validate_nickname` function in `validation_utils.py` to accept None as a valid input and return an appropriate error message for non-string types.
- Added unit tests in `test_nickname_validation.py` to cover cases for None and non-string inputs, ensuring robust validation behavior.
- Modified the nickname pattern in `constants.ts` to allow Unicode letters and numbers, improving character validation for nicknames.

These changes improve the reliability of nickname validation and enhance user feedback for invalid inputs.
@carlh7777
Copy link
Copy Markdown
Author

@JinHai-CN, @dcc123456 could you please check this PR?

@carlh7777
Copy link
Copy Markdown
Author

@KevinHuSh @yingfeng could you please check this pr?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 bug Something isn't working, pull request that fix bug. size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Profile name field accepts excessive length and invalid characters

1 participant