Skip to content

Conversation

@Saurabhkmr98
Copy link
Member

@Saurabhkmr98 Saurabhkmr98 commented Nov 20, 2025

Description

  • add check for feature enabled for module and cycle create

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

Screenshots and Media (if applicable)

Test Scenarios

References

Summary by CodeRabbit

  • Bug Fixes
    • Added validation to prevent cycles from being created when cycles are disabled for a project.
    • Added validation to prevent modules from being created when modules are disabled for a project.

✏️ Tip: You can customize this high-level summary in your review settings.

@makeplane
Copy link

makeplane bot commented Nov 20, 2025

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 20, 2025

Walkthrough

Two API serializers are enhanced with feature flag validation gates. CycleCreateSerializer now enforces project.cycle_view before allowing cycle creation, and ModuleCreateSerializer enforces project.module_view before allowing module operations. Additionally, cycle start_date conversion includes an is_start_date parameter flag.

Changes

Cohort / File(s) Change Summary
Feature flag validation gates
apps/api/plane/api/serializers/cycle.py, apps/api/plane/api/serializers/module.py
Added Project model import and validation checks in serialize methods to enforce cycle_view and module_view feature flags, raising ValidationError when disabled
Cycle date conversion
apps/api/plane/api/serializers/cycle.py
Updated start_date conversion in CycleCreateSerializer.validate to include is_start_date=True parameter in convert_to_utc call

Sequence Diagram

sequenceDiagram
    participant Client
    participant Serializer
    participant ProjectDB as Project DB
    
    Client->>Serializer: POST create cycle/module
    Serializer->>Serializer: validate() called
    Serializer->>ProjectDB: Fetch project
    ProjectDB-->>Serializer: project data
    
    alt feature flag enabled
        rect rgb(200, 220, 255)
            Note over Serializer: Continue validation
            Serializer-->>Client: Success
        end
    else feature flag disabled
        rect rgb(255, 200, 200)
            Note over Serializer: Raise ValidationError
            Serializer-->>Client: Error: Feature not enabled
        end
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Both changes follow an identical, repetitive pattern (import + feature flag check)
  • Straightforward validation logic with minimal branching
  • Limited scope affecting only 2 serializer files
  • Parameter flag addition in convert_to_utc is a minor, isolated change

Poem

🐰 With flags held high, we guard the gates,
Cycles and modules now validate states,
If views aren't enabled, deny with grace,
A little hop of logic in just the right place! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description provides the basic change summary but lacks details on implementation, testing, and references. Most template sections are empty or unchecked. Complete the Type of Change section, describe test scenarios performed, and add references to related issues (e.g., SILO-699).
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding feature enabled checks for module and cycle creation operations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore-add_feature_enable_validation

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3031a4 and df641c2.

📒 Files selected for processing (2)
  • apps/api/plane/api/serializers/cycle.py (2 hunks)
  • apps/api/plane/api/serializers/module.py (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: dheeru0198
Repo: makeplane/plane PR: 7625
File: apps/api/plane/bgtasks/workspace_seed_task.py:95-98
Timestamp: 2025-09-12T07:29:36.083Z
Learning: In the Plane codebase, workspace seed data should have project features (cycle_view, module_view, issue_views_view) enabled by default, even when regular project creation has these features disabled. This provides users with a complete demo experience in the seeded workspace.
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7969
File: apps/api/plane/api/views/cycle.py:1218-1228
Timestamp: 2025-10-17T10:46:13.825Z
Learning: In the cycle transfer functionality in apps/api/plane/api/views/cycle.py, transfers should only be allowed from completed cycles (end_date < timezone.now()), not from active or draft cycles. The guard should block when end_date is None or end_date >= timezone.now().
📚 Learning: 2025-10-17T10:46:13.825Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7969
File: apps/api/plane/api/views/cycle.py:1218-1228
Timestamp: 2025-10-17T10:46:13.825Z
Learning: In the cycle transfer functionality in apps/api/plane/api/views/cycle.py, transfers should only be allowed from completed cycles (end_date < timezone.now()), not from active or draft cycles. The guard should block when end_date is None or end_date >= timezone.now().

Applied to files:

  • apps/api/plane/api/serializers/cycle.py
📚 Learning: 2025-07-23T18:18:06.875Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7460
File: apps/api/plane/app/serializers/draft.py:112-122
Timestamp: 2025-07-23T18:18:06.875Z
Learning: In the Plane codebase serializers, workspace_id is not consistently passed in serializer context, so parent issue validation in DraftIssueCreateSerializer only checks project_id rather than both workspace_id and project_id. The existing project member authentication system already validates that users can only access projects they belong to, providing sufficient security without risking breaking functionality by adding workspace_id validation where the context might not be available.

Applied to files:

  • apps/api/plane/api/serializers/cycle.py
  • apps/api/plane/api/serializers/module.py
🧬 Code graph analysis (2)
apps/api/plane/api/serializers/cycle.py (2)
apps/api/plane/db/models/project.py (1)
  • Project (65-159)
apps/api/plane/tests/contract/api/test_cycles.py (1)
  • project (12-26)
apps/api/plane/api/serializers/module.py (1)
apps/api/plane/db/models/project.py (1)
  • Project (65-159)
⏰ 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: Analyze (javascript)
🔇 Additional comments (1)
apps/api/plane/api/serializers/cycle.py (1)

80-80: Clarify the purpose of the is_start_date=True parameter.

This change adds an is_start_date=True parameter to the convert_to_utc call, which is not mentioned in the PR description. The PR objective states adding feature checks for module and cycle creation, not modifying timezone conversion behavior.

Please clarify:

  1. Is this change intentional and related to the feature flag validation?
  2. What is the purpose of the is_start_date parameter and how does it affect UTC conversion?
  3. Should this be part of a separate PR focused on timezone handling?

Comment on lines +73 to +76
project = Project.objects.filter(id=project_id).first()
if not project.cycle_view:
raise serializers.ValidationError("Cycles are not enabled for this project")

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Add null check and move feature validation outside date validation block.

Two critical issues:

  1. Missing null check: project can be None if the project doesn't exist, causing AttributeError when accessing project.cycle_view.
  2. Incorrect placement: The feature check is nested inside the date validation block (lines 65-86), meaning cycles created without both start_date and end_date will bypass this validation entirely.

Apply this diff to fix both issues:

     def validate(self, data):
+        # Validate project and feature availability first
+        project_id = self.initial_data.get("project_id") or (
+            self.instance.project_id if self.instance and hasattr(self.instance, "project_id") else None
+        )
+        
+        if not project_id:
+            raise serializers.ValidationError("Project ID is required")
+        
+        project = Project.objects.filter(id=project_id).first()
+        if not project:
+            raise serializers.ValidationError("Project not found")
+        
+        if not project.cycle_view:
+            raise serializers.ValidationError("Cycles are not enabled for this project")
+
         if (
             data.get("start_date", None) is not None
             and data.get("end_date", None) is not None
             and data.get("start_date", None) > data.get("end_date", None)
         ):
             raise serializers.ValidationError("Start date cannot exceed end date")
 
         if data.get("start_date", None) is not None and data.get("end_date", None) is not None:
-            project_id = self.initial_data.get("project_id") or (
-                self.instance.project_id if self.instance and hasattr(self.instance, "project_id") else None
-            )
-
-            if not project_id:
-                raise serializers.ValidationError("Project ID is required")
-
-            project = Project.objects.filter(id=project_id).first()
-            if not project.cycle_view:
-                raise serializers.ValidationError("Cycles are not enabled for this project")
-
             data["start_date"] = convert_to_utc(
                 date=str(data.get("start_date").date()),
                 project_id=project_id,
                 is_start_date=True,
             )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/api/plane/api/serializers/cycle.py around lines 73 to 76, the code
assumes Project.objects.filter(id=project_id).first() never returns None and
performs the cycles-feature check inside the date-validation block; change this
so you first fetch the project, immediately check for None and raise
serializers.ValidationError("Project does not exist") (or appropriate message),
then check project.cycle_view and raise serializers.ValidationError("Cycles are
not enabled for this project") before any date-specific validation, ensuring the
feature validation runs regardless of whether start_date/end_date are present.

Comment on lines +57 to +59
project = Project.objects.get(id=self.context.get("project_id"))
if not project.module_view:
raise serializers.ValidationError("Modules are not enabled for this project")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Handle missing project gracefully to prevent unhandled exceptions.

The code uses Project.objects.get() which will raise Project.DoesNotExist if the project is not found or if project_id is None. Additionally, if project_id is not present in the context, this will fail unexpectedly.

Apply this diff to add defensive checks:

-    def validate(self, data):
-        project = Project.objects.get(id=self.context.get("project_id"))
-        if not project.module_view:
-            raise serializers.ValidationError("Modules are not enabled for this project")
+    def validate(self, data):
+        project_id = self.context.get("project_id")
+        if not project_id:
+            raise serializers.ValidationError("Project ID is required")
+        
+        project = Project.objects.filter(id=project_id).first()
+        if not project:
+            raise serializers.ValidationError("Project not found")
+        
+        if not project.module_view:
+            raise serializers.ValidationError("Modules are not enabled for this project")
🤖 Prompt for AI Agents
In apps/api/plane/api/serializers/module.py around lines 57 to 59, the code
calls Project.objects.get(id=self.context.get("project_id")) which will raise an
unhandled Project.DoesNotExist (or fail when project_id is None); update it to
first validate that project_id exists in self.context and then retrieve the
project safely (either use Project.objects.filter(id=project_id).first() and
check for None, or wrap get() in a try/except Project.DoesNotExist), and raise
serializers.ValidationError with a clear message (e.g., "Project not found" or
"project_id missing") when the project_id is missing or the project cannot be
found, instead of letting an exception bubble up.

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.

2 participants