Skip to content

Conversation

sangeethailango
Copy link
Member

@sangeethailango sangeethailango commented Aug 21, 2025

Description

This PR will add validation for the user's first name and last name.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Summary by CodeRabbit

  • New Features

    • Real-time validation for first and last name on web; last name is optional, first name remains required.
    • Inline error rendering for last name when invalid input is entered.
    • Server-side validation aligned with web rules for consistent behavior.
  • Bug Fixes

    • Blocks submission of names with unsupported characters and improves user-facing error messages.
  • Tests

    • Added unit tests covering valid and invalid name inputs.

Copy link
Contributor

coderabbitai bot commented Aug 21, 2025

Walkthrough

Adds client-side pattern validation for first_name and last_name in onboarding/profile forms, server-side regex validation in UserSerializer, and unit tests for serializer name validation. last_name remains optional on the client; new client error rendering appears for last_name.

Changes

Cohort / File(s) Summary
Client-side onboarding validation
apps/web/core/components/onboarding/steps/profile/root.tsx
Adds a validate rule for first_name enforcing /^[a-zA-Z0-9 _-]+$/; returns a specific error message on mismatch. Runs alongside existing required and maxLength rules. Regex permits spaces while message omits them.
Client-side profile form validation
apps/web/core/components/profile/form.tsx
Adds validate rules: first_name required with /^[a-zA-Z0-9 _-]+$/; last_name optional but must match same pattern if provided. Renders last_name validation error beneath the input. No public API signature changes.
Server-side serializer validation
apps/api/plane/app/serializers/user.py
Adds re import and regex checks in UserSerializer.validate_first_name and validate_last_name (allows empty last name). Raises ValidationError for URL-containing or disallowed characters. No signature changes.
Tests
apps/api/plane/tests/unit/serializers/test_user.py
New unit tests covering validate_first_name and validate_last_name for valid inputs, URL-related rejections, and invalid-character rejections; asserts exact error messages for failure cases.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant WebForm as Web Form (Onboarding/Profile)
  participant ClientVal as Client Validation
  participant API as API Endpoint
  participant Serializer as UserSerializer
  participant DB as Persistence

  User->>WebForm: Enter first_name / last_name
  User->>WebForm: Submit
  WebForm->>ClientVal: Run required + pattern checks
  alt Client validation fails
    ClientVal-->>User: Show field error(s)
  else Client validation passes
    WebForm->>API: POST profile data
    API->>Serializer: Deserialize + validate
    alt Server regex validation fails
      Serializer-->>API: ValidationError
      API-->>WebForm: 400 with field errors
      WebForm-->>User: Display server error(s)
    else Valid
      Serializer->>DB: Save/Update user
      DB-->>Serializer: OK
      API-->>WebForm: 200 Success
      WebForm-->>User: Proceed
    end
  end

  note over ClientVal,Serializer: Pattern allows letters, numbers, spaces, hyphens, underscores
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I twitch my whiskers at names so neat,
Hyphens hop and underscores beat,
Letters mingle, numbers play,
Spaces sneak in to join the fray.
Client checks, server winks—hippity hey! 🥕

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-user-name-validation

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

makeplane bot commented Aug 21, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

@gakshita gakshita marked this pull request as ready for review August 28, 2025 13:59
Copy link
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 (1)
apps/api/plane/db/models/user.py (1)

58-61: Validators on names: OK; confirm server-side length policy

Attaching validators here is fine and needs no migration. UI caps at 24 chars; model allows 255. If 24 is a product rule, enforce it server-side to avoid drift.

Option (no schema change):

from django.core.validators import MaxLengthValidator
first_name = models.CharField(max_length=255, blank=True, validators=[validate_name, MaxLengthValidator(24)])
last_name  = models.CharField(max_length=255, blank=True, validators=[validate_name, MaxLengthValidator(24)])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c209a71 and 03bbe79.

📒 Files selected for processing (3)
  • apps/api/plane/db/models/user.py (3 hunks)
  • apps/web/core/components/onboarding/steps/profile/root.tsx (1 hunks)
  • apps/web/core/components/profile/form.tsx (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and lint web apps
🔇 Additional comments (2)
apps/web/core/components/profile/form.tsx (2)

279-285: Remove last_name globally or reconsider scope
The last_name field is still referenced in dozens of modules—store (workspace-member.store.ts), analytics providers (posthog-provider.tsx, intercom-provider.tsx), local-DB schemas, workspace/project member-columns, profile sidebar/form, onboarding steps, greetings components, etc. Removing it only from the form snippet is insufficient. Update the PR to remove all last_name usages and related plumbing across the codebase, or adjust the scope of this change.


250-254: Trim and tighten first_name validation

-                    validate: (value) => {
-                      if (!/^[a-zA-Z0-9 _-]+$/.test(value))
-                        return "First name can only contain letters, numbers, hyphens, and underscores.";
-                      return true;
-                    },
+                    validate: (value) => {
+                      const v = value.trim();
+                      if (v.length === 0) return "First name can’t be empty or only spaces.";
+                      if (!/^[A-Za-z0-9 _-]+$/.test(v))
+                        return "First name can only contain letters, numbers, spaces, hyphens (-), and underscores (_).";
+                      return true;
+                    },

Also confirm the intended max-length (UI caps at 24 vs server at 255) and align both ends.

Comment on lines +216 to +220
validate: (value) => {
if (!/^[a-zA-Z0-9 _-]+$/.test(value))
return "First name can only contain letters, numbers, hyphens, and underscores.";
return true;
},
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Align rule with copy and block whitespace-only names

Message says “First name” though label is “Name”, and you allow spaces but don’t mention them; also accepts only-spaces. Trim and update message.

-              validate: (value) => {
-                if (!/^[a-zA-Z0-9 _-]+$/.test(value))
-                  return "First name can only contain letters, numbers, hyphens, and underscores.";
-                return true;
-              },
+              validate: (value) => {
+                const v = value.trim();
+                if (v.length === 0) return "Name can't be empty or only spaces.";
+                if (!/^[A-Za-z0-9 _-]+$/.test(v))
+                  return "Name can only contain letters, numbers, spaces, hyphens (-), and underscores (_).";
+                return true;
+              },

If the PR removes last name in onboarding, also delete it from:

  • TProfileSetupFormValues and defaultValues
  • handleSubmitUserDetail payload (Line 84)

🏁 Script executed:

#!/bin/bash
# Find remaining onboarding references to last_name
rg -nP -C2 '\blast_name\b' apps/web/core/components/onboarding

Length of output: 8338


Update name validation to trim whitespace and align message copy

apps/web/core/components/onboarding/steps/profile/root.tsx (lines 216–220):

- validate: (value) => {
-   if (!/^[a-zA-Z0-9 _-]+$/.test(value))
-     return "First name can only contain letters, numbers, hyphens, and underscores.";
-   return true;
- },
+ validate: (value) => {
+   const trimmed = value.trim();
+   if (trimmed.length === 0) return "Name can't be empty or only spaces.";
+   if (!/^[A-Za-z0-9 _-]+$/.test(trimmed))
+     return "Name can only contain letters, numbers, spaces, hyphens (-), and underscores (_).";
+   return true;
+ },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
validate: (value) => {
if (!/^[a-zA-Z0-9 _-]+$/.test(value))
return "First name can only contain letters, numbers, hyphens, and underscores.";
return true;
},
validate: (value) => {
const trimmed = value.trim();
if (trimmed.length === 0)
return "Name can't be empty or only spaces.";
if (!/^[A-Za-z0-9 _-]+$/.test(trimmed))
return "Name can only contain letters, numbers, spaces, hyphens (-), and underscores (_).";
return true;
},
🤖 Prompt for AI Agents
In apps/web/core/components/onboarding/steps/profile/root.tsx around lines 216
to 220, update the validation to trim leading/trailing whitespace before testing
and adjust the error copy to mention spaces explicitly: compute const v = (value
|| "").trim(); then run the regex test against v and if it fails return "First
name can only contain letters, numbers, spaces, hyphens, and underscores."
(optionally also check if v === "" and return a required-name message if
needed).

Copy link
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: 1

🧹 Nitpick comments (1)
apps/api/plane/app/views/user/base.py (1)

76-84: Align errors and UX; consider serializer-level validation.

  • The message omits “spaces” although they’re allowed by the regex. Field-specific messages help the UI pinpoint which input failed.
  • Consider moving this validation into UserSerializer (validate_first_name / validate_last_name) to cover both create and update uniformly and reduce view logic.
  • Optional: trim inputs before validation and enforce a sane max length to prevent all-space names and respect DB limits.

Example (serializer snippet, for reference outside this file):

# in UserSerializer
NAME_PATTERN = re.compile(r"^[a-zA-Z0-9 _-]+$")

def validate_first_name(self, v):
    v = v.strip()
    if not NAME_PATTERN.fullmatch(v):
        raise serializers.ValidationError(
            "First name can only contain letters, numbers, spaces, hyphens (-), and underscores (_)."
        )
    return v

def validate_last_name(self, v):
    if v is None:
        return v
    v = v.strip()
    if v != "" and not NAME_PATTERN.fullmatch(v):
        raise serializers.ValidationError(
            "Last name can only contain letters, numbers, spaces, hyphens (-), and underscores (_)."
        )
    return v
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 56795bb and 04e14f3.

📒 Files selected for processing (1)
  • apps/api/plane/app/views/user/base.py (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/api/plane/app/views/user/base.py (1)

8-8: LGTM: required import added.
re is needed for the validation below.

Copy link
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: 0

🧹 Nitpick comments (4)
apps/api/plane/app/serializers/user.py (4)

10-12: Label stdlib import correctly

re is a standard library import, not "Django". Rename the section label for clarity. Optionally, group stdlib imports above third-party ones to follow common import ordering.

-# Django import
+# Standard library imports
 import re

19-23: Tighten copy: capitalize and punctuate error message

Keep user-facing strings consistent with nearby messages (“First name cannot contain a URL.”). Capitalize and add a period.

-            raise serializers.ValidationError(
-                "first name can only contain letters, numbers, hyphens (-), and underscores (_)"
-            )
+            raise serializers.ValidationError(
+                "First name can only contain letters, numbers, hyphens (-), and underscores (_)."
+            )

30-34: Mirror copy fix for last_name message

Apply the same casing and punctuation for consistency.

-            raise serializers.ValidationError(
-                "last name can only contain letters, numbers, hyphens (-), and underscores (_)"
-            )
+            raise serializers.ValidationError(
+                "Last name can only contain letters, numbers, hyphens (-), and underscores (_)."
+            )

26-34: Guard against null last_name inputs (if API allows null)

If clients can send null for last_name, contains_url(value) will raise a TypeError. Consider short-circuiting empty/None before validations. If null is impossible (model/serializer sets allow_null=False), ignore this.

Example (outside the changed hunk, shown for clarity):

def validate_last_name(self, value):
    if value in (None, ""):
        return "" if value is None else value
    if contains_url(value):
        raise serializers.ValidationError("Last name cannot contain a URL.")
    if not re.match(r"^[a-zA-Z0-9_\- ]+$", value):
        raise serializers.ValidationError(
            "Last name can only contain letters, numbers, hyphens (-), and underscores (_)."
        )
    return value
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 04e14f3 and 00e38a7.

📒 Files selected for processing (1)
  • apps/api/plane/app/serializers/user.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/api/plane/app/serializers/user.py (1)
apps/api/plane/utils/url.py (1)
  • contains_url (22-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Build and lint web apps

dheeru0198
dheeru0198 previously approved these changes Sep 3, 2025
@sriramveeraghanta
Copy link
Member

@dheeru0198 What happens in case of people use different language than english? Does this Validation fail?

@sriramveeraghanta sriramveeraghanta added tests required This PR needs test cases for approval and removed ready to merge labels Sep 4, 2025
@sangeethailango
Copy link
Member Author

sangeethailango commented Sep 4, 2025

@sriramveeraghanta They cannot use other languages because we only accept English letters, and if they try, an error will be shown.

Copy link
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 (6)
apps/api/plane/tests/unit/serializers/test_user.py (6)

11-27: Parametrize the “valid first names” test for clearer failures and isolated cases.

Parametrization yields better reporting and avoids the manual loop.

Apply:

-    def test_validate_first_name_valid(self):
-        """Test that valid first names are accepted"""
-
-        serializer = UserSerializer()
-        valid_names = [
-            "John",
-            "John Doe",
-            "John-Doe",
-            "John_Doe",
-            "John123",
-        ]
-
-        for name in valid_names:
-            result = serializer.validate_first_name(name)
-            assert result == name
+    @pytest.mark.parametrize(
+        "name", ["John", "John Doe", "John-Doe", "John_Doe", "John123"]
+    )
+    def test_validate_first_name_valid(self, name):
+        """Test that valid first names are accepted"""
+        serializer = UserSerializer()
+        assert serializer.validate_first_name(name) == name

28-43: Avoid brittle equality on error text; assert via regex match.

Makes tests resilient to DRF ErrorDetail formatting.

Apply:

-        for name in invalid_names:
-            with pytest.raises(serializers.ValidationError) as exc_info:
-                serializer.validate_first_name(name)
-            assert str(exc_info.value.detail[0]) == "First name cannot contain a URL."
+        for name in invalid_names:
+            with pytest.raises(
+                serializers.ValidationError, match=r"^First name cannot contain a URL\.$"
+            ):
+                serializer.validate_first_name(name)

83-98: Use regex-based assertion for the URL error message here too.

Keep consistency with first_name URL tests.

Apply:

-        for name in invalid_names:
-            with pytest.raises(serializers.ValidationError) as exc_info:
-                serializer.validate_last_name(name)
-            assert str(exc_info.value.detail[0]) == "Last name cannot contain a URL."
+        for name in invalid_names:
+            with pytest.raises(
+                serializers.ValidationError, match=r"^Last name cannot contain a URL\.$"
+            ):
+                serializer.validate_last_name(name)

99-118: Mirror the message fix for last_name; also consider real-world invalid chars.

Include “spaces” in the message and (optionally) add cases like apostrophes and dots to document the decision explicitly.

Apply:

-            assert str(exc_info.value.detail[0]) == (
-                "last name can only contain letters, numbers, "
-                "hyphens (-), and underscores (_)"
-            )
+            assert str(exc_info.value.detail[0]) == (
+                "last name can only contain letters, numbers, spaces, "
+                "hyphens (-), and underscores (_)"
+            )

Optional extra negatives to add near this test:

+            "O'Connor",
+            "Jr.",

11-118: Prefer parametrization for all looped cases.

Applies to both valid/invalid lists across first and last name tests for consistent style and clearer test IDs.

If helpful, I can push a patch converting all list+loops to @pytest.mark.parametrize.


1-118: Add one serializer-level integration test.

Call UserSerializer(data={...}) and assert is_valid()/errors so we also catch wiring issues beyond direct method calls.

Example (append at end):

def test_user_serializer_integration_field_errors():
    s = UserSerializer(data={"first_name": "http://x", "last_name": "Smith"})
    assert not s.is_valid()
    assert "first_name" in s.errors
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 00e38a7 and b4acaa2.

📒 Files selected for processing (1)
  • apps/api/plane/tests/unit/serializers/test_user.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/api/plane/tests/unit/serializers/test_user.py (1)
apps/api/plane/app/serializers/user.py (3)
  • UserSerializer (14-71)
  • validate_first_name (15-24)
  • validate_last_name (26-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/api/plane/tests/unit/serializers/test_user.py (2)

1-4: Good test module setup.

Imports are minimal and correct for pytest + DRF ValidationError usage.


119-119: Expand negative coverage: non-ASCII and bare domains.

Given the product decision to allow only English letters, add explicit tests for non-ASCII names and bare domains (“example.com”) to ensure they’re rejected (and that URL detection meets expectations).

Suggested additions:

+    @pytest.mark.parametrize("name", ["Álvaro", "Müller", "Renée", "Иван", "张三"])
+    def test_validate_first_name_non_ascii_rejected(self, name):
+        s = UserSerializer()
+        with pytest.raises(serializers.ValidationError, match=r"letters, numbers"):
+            s.validate_first_name(name)
+
+    @pytest.mark.parametrize("name", ["example.com", "foo.bar"])
+    def test_validate_first_name_bare_domain_rejected(self, name):
+        s = UserSerializer()
+        with pytest.raises(serializers.ValidationError):
+            s.validate_first_name(name)

If contains_url currently misses bare domains, either adjust it or change this test expectation accordingly.

dheeru0198
dheeru0198 previously approved these changes Sep 4, 2025
@dheeru0198
Copy link
Member

Let's wait until we figure out if non english languages should be allowed or not

@dheeru0198 dheeru0198 self-requested a review September 4, 2025 12:42
@dheeru0198 dheeru0198 dismissed their stale review September 4, 2025 12:42

Need to rethink about supporting non english languages

@sangeethailango sangeethailango removed the tests required This PR needs test cases for approval label Sep 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants