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

[WEB-2388] fix: workspace draft issues migration #5749

Merged
merged 3 commits into from
Oct 8, 2024

Conversation

NarayanBavisetti
Copy link
Collaborator

@NarayanBavisetti NarayanBavisetti commented Oct 4, 2024

fix:

  • this pull request includes the new tables for the draft issue and the data migration from the issue table to the draft table.

Issue Link: WEB-2388

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced draft issue management with new serializers and view sets for creating, updating, and retrieving draft issues.
    • Added timezone support for projects and cycles, enhancing date and time handling.
  • Bug Fixes

    • Improved date comparison logic across various endpoints to ensure accurate cycle state determination.
  • Refactor

    • Streamlined dashboard methods for better performance and clarity.
  • Chores

    • Removed deprecated draft issue routes and imports to clean up the codebase.

Copy link
Contributor

coderabbitai bot commented Oct 4, 2024

Walkthrough

The changes in this pull request primarily focus on enhancing the handling of datetime comparisons across various components of the application. Key modifications include updating date checks to utilize timezone.now() instead of timezone.now().date(), ensuring more precise datetime handling for cycle management and draft issues. Additionally, new serializers and view sets for draft issues are introduced, while outdated draft-related routes and classes are removed, reflecting a reorganization of draft issue management within the application.

Changes

File Path Change Summary
apiserver/plane/api/views/cycle.py Updated date comparisons in CycleAPIEndpoint, CycleArchiveUnarchiveAPIEndpoint, and TransferCycleIssueAPIEndpoint to use timezone.now().
apiserver/plane/app/serializers/__init__.py Added imports for new draft-related serializers: DraftIssueCreateSerializer, DraftIssueSerializer, DraftIssueDetailSerializer.
apiserver/plane/app/serializers/draft.py Introduced new serializers for draft issues: DraftIssueCreateSerializer, DraftIssueSerializer, DraftIssueDetailSerializer.
apiserver/plane/app/urls/issue.py Removed all routes related to IssueDraftViewSet, eliminating draft issue management from this URL configuration.
apiserver/plane/app/urls/workspace.py Added new paths for WorkspaceDraftIssueViewSet to manage draft issues within workspaces.
apiserver/plane/app/views/__init__.py Added import for WorkspaceDraftIssueViewSet, removed import for IssueDraftViewSet.
apiserver/plane/app/views/cycle/archive.py Updated archiving logic in CycleArchiveUnarchiveEndpoint to use timezone.now() for date comparisons.
apiserver/plane/app/views/cycle/base.py Modified date checks in CycleViewSet and TransferCycleIssueEndpoint to use timezone.now().
apiserver/plane/app/views/cycle/issue.py Updated create method in CycleIssueViewSet to use timezone.now() for cycle end date comparisons.
apiserver/plane/app/views/dashboard/base.py Removed unused imports and retained existing functionality in dashboard-related methods.
apiserver/plane/app/views/issue/draft.py Removed IssueDraftViewSet, which managed draft issues.
apiserver/plane/app/views/workspace/draft.py Introduced WorkspaceDraftIssueViewSet for managing draft issues in workspaces.
apiserver/plane/db/migrations/0077_draftissue_cycle_user_timezone_project_user_timezone_and_more.py Added migration for new draft-related models and fields, including timezone management for cycles and projects.
apiserver/plane/db/models/__init__.py Added imports for new draft-related models: DraftIssue, DraftIssueAssignee, DraftIssueLabel, DraftIssueModule, DraftIssueCycle.
apiserver/plane/db/models/cycle.py Changed start_date and end_date fields from DateField to DateTimeField, added timezone and version fields.
apiserver/plane/db/models/draft.py Created new model file defining DraftIssue, DraftIssueAssignee, DraftIssueLabel, DraftIssueModule, and DraftIssueCycle.
apiserver/plane/db/models/project.py Added timezone field to Project model, allowing for timezone selection.
apiserver/plane/utils/analytics_plot.py Updated date calculations in burndown_plot function to ensure correct date type handling.

Possibly related PRs

Suggested labels

🌟improvement

Suggested reviewers

  • SatishGandham
  • pablohashescobar

Poem

In the meadow where cycles spin,
A draft of ideas begins to win.
With timestamps precise, we hop and play,
Enhancing the code in a bright new way.
So gather 'round, let the changes flow,
For every leap, our projects grow! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

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

@NarayanBavisetti NarayanBavisetti added ⚙️backend 🔄migrations Contains Migration changes labels Oct 4, 2024
@NarayanBavisetti NarayanBavisetti changed the title fix: workspace draft issues migration [WEB-2388] fix: workspace draft issues migration Oct 4, 2024
@NarayanBavisetti NarayanBavisetti marked this pull request as ready for review October 4, 2024 08:14
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: 22

🧹 Outside diff range and nitpick comments (12)
apiserver/plane/bgtasks/issue_automation_task.py (1)

Line range hint 1-179: Summary of changes and their potential impact

The changes made to both archive_old_issues and close_old_issues functions improve the precision of date comparisons by including the time component. This is achieved by changing timezone.now().date() to timezone.now() in the query filters.

Key points:

  1. The changes are consistent across both functions, which is good for code maintainability.
  2. The improved precision allows for more accurate filtering of issues based on their associated cycles and modules.
  3. There's a potential for timezone-related issues if the dates stored in the database are not in the same timezone as the application server.
  4. The changes might affect which issues are selected for archiving or closing, potentially altering the behavior of these automated tasks.

Recommendations:

  1. Verify that all date fields in the database are stored in a consistent timezone, preferably UTC.
  2. Test the impact of these changes on the number and type of issues being archived or closed in different scenarios.
  3. Consider adding logging or monitoring to track any significant changes in the number of issues being processed after deploying this update.

To mitigate potential timezone issues in the future, consider standardizing all date/time operations to use UTC throughout the application, and only convert to local timezones when necessary for display purposes.

apiserver/plane/app/urls/workspace.py (1)

268-278: LGTM with a minor suggestion: URL pattern for specific draft issue operations

The new URL pattern for operations on specific draft issues is well-structured and consistent with existing patterns:

  • Path: "workspaces/str:slug/draft-issues/uuid:pk/"
  • Uses WorkspaceDraftIssueViewSet with 'retrieve', 'partial_update', and 'destroy' methods

This addition aligns well with the PR objective of introducing functionality for draft issues.

Consider changing the name from "workspace-drafts-issues" to "workspace-draft-issues" for consistency with the previous pattern:

-        name="workspace-drafts-issues",
+        name="workspace-draft-issues",

This minor change would maintain consistency in naming across related endpoints.

apiserver/plane/db/models/project.py (1)

Line range hint 1-365: Summary: Timezone support added to Project model

The changes in this file add timezone support to the Project model, which is a valuable addition for managing projects across different time zones. The implementation is clean and follows best practices:

  1. The pytz library is imported correctly.
  2. A comprehensive list of timezone choices is created using pytz.all_timezones.
  3. The new timezone field is added to the Project model with appropriate parameters.

These changes will enhance the project management capabilities of the application, especially for teams working across different geographical locations.

Consider the following to fully leverage this new feature:

  1. Update any project creation/editing forms to include the new timezone field.
  2. Adjust any date/time display logic in the application to respect the project's timezone.
  3. If you have any scheduling or time-based features, ensure they take the project timezone into account.
  4. Update any relevant documentation or user guides to explain this new project attribute.
apiserver/plane/db/models/cycle.py (1)

84-84: Clarify the purpose of the version field

The addition of the version field suggests versioning within the Cycle model. Consider adding a comment or documentation to explain its intended use, which will aid in maintainability and clarity for other developers.

apiserver/plane/db/models/draft.py (5)

20-26: Review the use of on_delete=models.CASCADE for ForeignKey relationships.

Using on_delete=models.CASCADE will delete the related DraftIssue when the referenced object is deleted. Consider whether this is the desired behavior for the parent, state, and type fields. If you want to preserve DraftIssue instances even if related objects are deleted, you might use on_delete=models.SET_NULL with null=True and blank=True.

Apply this diff if you decide to change the behavior:

 parent = models.ForeignKey(
     "db.Issue",
-    on_delete=models.CASCADE,
+    on_delete=models.SET_NULL,
     null=True,
     blank=True,
     related_name="draft_parent_issue",
 )

 state = models.ForeignKey(
     "db.State",
-    on_delete=models.CASCADE,
+    on_delete=models.SET_NULL,
     null=True,
     blank=True,
     related_name="state_draft_issue",
 )

 type = models.ForeignKey(
     "db.IssueType",
-    on_delete=models.SET_NULL,
+    on_delete=models.SET_NULL,
     related_name="draft_issue_type",
     null=True,
     blank=True,
 )

Also applies to: 27-33, 73-79


45-45: Consider changing the default value of description_html to an empty string.

Setting the default of description_html to "<p></p>" may not be necessary and could introduce unwanted HTML elements. An empty string "" might better represent the absence of content.

Apply this diff:

-description_html = models.TextField(blank=True, default="<p></p>")
+description_html = models.TextField(blank=True, default="")

49-53: Reevaluate the default priority value.

The priority field defaults to "none". Ensure that this value aligns with how priorities are handled in the application. If "medium" is considered the standard priority, it might be more appropriate as a default.

Apply this diff if you choose to change the default:

 priority = models.CharField(
     max_length=30,
     choices=PRIORITY_CHOICES,
     verbose_name="Issue Priority",
-    default="none",
+    default="medium",
 )

164-172: Eliminate redundancy in Meta class constraints.

In DraftIssueAssignee and DraftIssueModule, both unique_together and UniqueConstraint are used for the same fields. Since UniqueConstraint provides more flexibility, you can remove the unique_together to avoid redundancy.

Apply this diff for DraftIssueAssignee:

 class Meta:
-    unique_together = ["draft_issue", "assignee", "deleted_at"]
     constraints = [
         models.UniqueConstraint(
             fields=["draft_issue", "assignee"],
             condition=models.Q(deleted_at__isnull=True),
             name="draft_issue_assignee_unique_issue_assignee_when_deleted_at_null",
         )
     ]

And similarly for DraftIssueModule:

 class Meta:
-    unique_together = ["draft_issue", "module", "deleted_at"]
     constraints = [
         models.UniqueConstraint(
             fields=["draft_issue", "module"],
             condition=models.Q(deleted_at__isnull=True),
             name="module_draft_issue_unique_issue_module_when_deleted_at_null",
         )
     ]

Also applies to: 216-222


147-149: Review the __str__ method for clarity and security.

Returning self.name along with self.project.name might expose project names inadvertently. Consider if only self.name is sufficient for representation.

Apply this diff if you decide to simplify:

 def __str__(self):
     """Return name of the draft issue"""
-    return f"{self.name} <{self.project.name}>"
+    return f"{self.name}"
apiserver/plane/app/views/workspace/draft.py (1)

178-178: Remove redundant filter(pk=pk) in the retrieve method

The retrieve method applies filter(pk=pk) twice, which is redundant. Removing the extra filter improves code clarity.

Apply this diff to eliminate the redundant filter:

             .filter(pk=pk)
-            .filter(pk=pk)

Also applies to: 185-185

apiserver/plane/db/migrations/0077_draftissue_cycle_user_timezone_project_user_timezone_and_more.py (2)

10-123: Clean up: Remove commented-out code or provide justification.

There are several sections of commented-out code in the migrate_draft_issues function, such as:

  • Line 46: # issue_ids_to_delete = []
  • Lines 109-110: # issue_ids_to_delete.append(issue.id)
  • Lines 122-123: # Issue.objects.filter(id__in=issue_ids_to_delete).delete()

If these lines are no longer necessary, consider removing them to keep the codebase clean and maintainable. If they are intentionally left for future use or reference, please add comments explaining their purpose.


2031-2033: Versioning: Consider implications of adding a version field to the cycle model.

The version field has been added to the cycle model with a default value of 1. Ensure that this addition aligns with the application's versioning strategy and that any existing code interacting with cycle instances accounts for this new field.

If this field is intended for optimistic locking or tracking changes, consider implementing relevant logic to handle concurrent updates.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f1a0a8d and dddbfce.

📒 Files selected for processing (20)
  • apiserver/plane/api/views/cycle.py (4 hunks)
  • apiserver/plane/app/serializers/init.py (1 hunks)
  • apiserver/plane/app/serializers/draft.py (1 hunks)
  • apiserver/plane/app/urls/issue.py (0 hunks)
  • apiserver/plane/app/urls/workspace.py (2 hunks)
  • apiserver/plane/app/views/init.py (1 hunks)
  • apiserver/plane/app/views/cycle/archive.py (1 hunks)
  • apiserver/plane/app/views/cycle/base.py (2 hunks)
  • apiserver/plane/app/views/cycle/issue.py (1 hunks)
  • apiserver/plane/app/views/dashboard/base.py (0 hunks)
  • apiserver/plane/app/views/issue/draft.py (0 hunks)
  • apiserver/plane/app/views/workspace/draft.py (1 hunks)
  • apiserver/plane/app/views/workspace/user.py (1 hunks)
  • apiserver/plane/bgtasks/issue_automation_task.py (2 hunks)
  • apiserver/plane/db/migrations/0077_draftissue_cycle_user_timezone_project_user_timezone_and_more.py (1 hunks)
  • apiserver/plane/db/models/init.py (1 hunks)
  • apiserver/plane/db/models/cycle.py (3 hunks)
  • apiserver/plane/db/models/draft.py (1 hunks)
  • apiserver/plane/db/models/project.py (3 hunks)
  • apiserver/plane/utils/analytics_plot.py (2 hunks)
💤 Files with no reviewable changes (3)
  • apiserver/plane/app/urls/issue.py
  • apiserver/plane/app/views/dashboard/base.py
  • apiserver/plane/app/views/issue/draft.py
🧰 Additional context used
🪛 Ruff
apiserver/plane/app/serializers/__init__.py

129-129: .draft.DraftIssueCreateSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


130-130: .draft.DraftIssueSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


131-131: .draft.DraftIssueDetailSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

apiserver/plane/app/views/__init__.py

43-43: .workspace.draft.WorkspaceDraftIssueViewSet imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

apiserver/plane/db/models/__init__.py

8-8: .draft.DraftIssue imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueAssignee imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueLabel imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueModule imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueCycle imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

🪛 GitHub Check: Codacy Static Code Analysis
apiserver/plane/app/serializers/__init__.py

[notice] 128-128: apiserver/plane/app/serializers/init.py#L128
'.draft.DraftIssueCreateSerializer' imported but unused (F401)

apiserver/plane/app/views/__init__.py

[notice] 43-43: apiserver/plane/app/views/init.py#L43
'.workspace.draft.WorkspaceDraftIssueViewSet' imported but unused (F401)

apiserver/plane/db/models/__init__.py

[notice] 8-8: apiserver/plane/db/models/init.py#L8
'.draft.DraftIssue' imported but unused (F401)

🔇 Additional comments (33)
apiserver/plane/db/models/__init__.py (1)

8-8: LGTM! New draft issue models added.

The addition of these new draft issue models aligns with the PR objectives of introducing new tables for draft issues. The import statement is correctly placed, maintaining the alphabetical order of imports.

However, static analysis tools have flagged these imports as unused. While this is likely a false positive (as init.py files often import models to make them available elsewhere), it's worth verifying that these new models are being utilized in the application.

To ensure these new models are being used in the codebase, we can run the following script:

If you find that some of these models are not currently used, they may be part of ongoing development. In that case, you might want to add a comment explaining their future use or consider importing them when they're actually needed.

✅ Verification successful

Action Required: Update Verification Script to Correctly Search Python Files

The previous verification script encountered errors due to the unrecognized file type python. To resolve this, please run the updated script below, which searches for the usage of the new draft issue models within Python files:

Please execute this script and provide the output to further verify the usage of the new models in the codebase.


Review Verified: Draft Issue Models Are Actively Used

The shell script results confirm that the newly imported draft issue models (DraftIssue, DraftIssueAssignee, DraftIssueLabel, DraftIssueModule, DraftIssueCycle) are actively utilized across multiple files in the codebase. This verifies that the static analysis warnings about unused imports are false positives.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of newly imported draft issue models across the codebase.

# Test: Search for usage of each new model
echo "Searching for DraftIssue usage:"
rg --type python 'DraftIssue'

echo "Searching for DraftIssueAssignee usage:"
rg --type python 'DraftIssueAssignee'

echo "Searching for DraftIssueLabel usage:"
rg --type python 'DraftIssueLabel'

echo "Searching for DraftIssueModule usage:"
rg --type python 'DraftIssueModule'

echo "Searching for DraftIssueCycle usage:"
rg --type python 'DraftIssueCycle'

Length of output: 741


Script:

#!/bin/bash
# Description: Verify the usage of newly imported draft issue models across the codebase.

# Test: Search for usage of each new model in Python files
echo "Searching for DraftIssue usage:"
rg 'DraftIssue' --glob '*.py'

echo "Searching for DraftIssueAssignee usage:"
rg 'DraftIssueAssignee' --glob '*.py'

echo "Searching for DraftIssueLabel usage:"
rg 'DraftIssueLabel' --glob '*.py'

echo "Searching for DraftIssueModule usage:"
rg 'DraftIssueModule' --glob '*.py'

echo "Searching for DraftIssueCycle usage:"
rg 'DraftIssueCycle' --glob '*.py'

Length of output: 15428

🧰 Tools
🪛 Ruff

8-8: .draft.DraftIssue imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueAssignee imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueLabel imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueModule imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


8-8: .draft.DraftIssueCycle imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

🪛 GitHub Check: Codacy Static Code Analysis

[notice] 8-8: apiserver/plane/db/models/init.py#L8
'.draft.DraftIssue' imported but unused (F401)

apiserver/plane/app/serializers/__init__.py (1)

128-132: Verify the intended use of new draft serializer imports

The addition of draft-related serializers (DraftIssueCreateSerializer, DraftIssueSerializer, and DraftIssueDetailSerializer) aligns well with the PR objectives to address draft issues migration. This is a good step towards implementing the new functionality.

However, these imports are currently flagged as unused by static analysis tools. In an __init__.py file, this might be intentional to make these classes available when importing from the serializers package. To ensure proper implementation:

  1. Verify if the current import structure is sufficient for your needs.
  2. If you intend to expose these serializers for use in other modules, consider adding them to an __all__ list in this file.

To help verify the usage of these new serializers across the project, you can run the following command:

This will help identify if and where these serializers are being used in the project.

If you need assistance in properly exposing these serializers or adjusting the import structure, please let me know, and I'd be happy to provide more specific recommendations.

🧰 Tools
🪛 Ruff

129-129: .draft.DraftIssueCreateSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


130-130: .draft.DraftIssueSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)


131-131: .draft.DraftIssueDetailSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

🪛 GitHub Check: Codacy Static Code Analysis

[notice] 128-128: apiserver/plane/app/serializers/init.py#L128
'.draft.DraftIssueCreateSerializer' imported but unused (F401)

apiserver/plane/app/views/__init__.py (1)

43-44: ⚠️ Potential issue

New import added for workspace draft issues

The addition of WorkspaceDraftIssueViewSet from .workspace.draft suggests a new feature or restructuring related to draft issues at the workspace level. This aligns with the PR objective of addressing workspace draft issues migration.

However, the static analysis tools have flagged this import as unused.

To address this:

  1. If this import is needed for future use or in other parts of the codebase, consider adding it to __all__ to explicitly export it.
  2. If it's not needed, remove the unused import.

Let's verify the usage of this new import:

Additionally, can you confirm if IssueDraftViewSet from .issue.draft has been removed as mentioned in the AI summary? If so, we should ensure that all references to it have been updated or removed.

🧰 Tools
🪛 Ruff

43-43: .workspace.draft.WorkspaceDraftIssueViewSet imported but unused; consider removing, adding to __all__, or using a redundant alias

(F401)

🪛 GitHub Check: Codacy Static Code Analysis

[notice] 43-43: apiserver/plane/app/views/init.py#L43
'.workspace.draft.WorkspaceDraftIssueViewSet' imported but unused (F401)

apiserver/plane/bgtasks/issue_automation_task.py (2)

123-124: Consistent improvement in date comparison, reiterating timezone considerations.

This change is consistent with the modification in the archive_old_issues function, which is good for maintaining code consistency. The same benefits of improved precision in date comparison apply here.

As mentioned in the previous comment, please ensure that:

  1. The end_date and target_date stored in the database are in the same timezone as the application server to avoid any timezone-related issues.

  2. The impact of this change on the number and type of issues being closed is verified, as it might affect which issues are selected for closing.

To verify the impact of this change on issue closing, you can run a similar script to the one provided for archiving:

#!/bin/bash
# Description: Compare the number of issues that would be closed before and after the change.

# Test: Count issues that would be closed with the old logic
old_count=$(python3 -c "
from django.utils import timezone
from plane.db.models import Issue
print(Issue.issue_objects.filter(
    issue_cycle__cycle__end_date__lt=timezone.now().date(),
    issue_module__module__target_date__lt=timezone.now().date()
).count())
")

# Test: Count issues that would be closed with the new logic
new_count=$(python3 -c "
from django.utils import timezone
from plane.db.models import Issue
print(Issue.issue_objects.filter(
    issue_cycle__cycle__end_date__lt=timezone.now(),
    issue_module__module__target_date__lt=timezone.now()
).count())
")

echo "Issues that would be closed with old logic: $old_count"
echo "Issues that would be closed with new logic: $new_count"
echo "Difference: $((new_count - old_count))"

This script will help you understand the impact of the change on the number of issues that would be closed.

Also applies to: 128-129


45-46: Improved precision in date comparison, but consider timezone implications.

The change from timezone.now().date() to timezone.now() improves the precision of the date comparison by including the time component. This is a good improvement that allows for more accurate filtering of issues based on their associated cycles and modules.

However, there are a couple of points to consider:

  1. Ensure that the end_date and target_date stored in the database are in the same timezone as the application server. If they are not, this change could lead to unexpected behavior.

  2. This change might affect which issues are selected for archiving. It would be beneficial to verify the impact of this change on the number and type of issues being archived.

To verify the impact of this change, you can run the following script:

This script will help you understand the impact of the change on the number of issues that would be archived.

Also applies to: 50-51

apiserver/plane/app/urls/workspace.py (3)

30-30: LGTM: Import statement for WorkspaceDraftIssueViewSet

The import of WorkspaceDraftIssueViewSet is correctly placed and follows the existing naming convention. This import is necessary for the new URL patterns added for draft issues.


258-267: LGTM: New URL pattern for listing and creating draft issues

The new URL pattern for draft issues is well-structured and consistent with existing patterns:

  • Path: "workspaces/str:slug/draft-issues/"
  • Uses WorkspaceDraftIssueViewSet with 'list' and 'create' methods
  • Named "workspace-draft-issues"

This addition aligns well with the PR objective of introducing functionality for draft issues.


Line range hint 1-278: Summary: Well-implemented draft issue endpoints

The changes in this file successfully implement URL patterns for draft issues within the workspace context. The additions are consistent with existing patterns and align well with the PR objectives. Only a minor naming inconsistency was noted.

To ensure completeness:

Let's verify the implementation of the WorkspaceDraftIssueViewSet:

This will help confirm that the view set is properly implemented with the expected methods (list, create, retrieve, partial_update, destroy).

apiserver/plane/utils/analytics_plot.py (3)

Line range hint 166-170: Improved date consistency in cycle date range calculation.

The addition of .date() to the date calculation ensures that the date range consists of date objects rather than datetime objects. This change improves type consistency throughout the function and prevents potential issues with date comparisons.


Line range hint 206-210: Improved date consistency in module date range calculation.

Similar to the change in the cycle scenario, adding .date() to the date calculation for the module scenario ensures that the date range consists of date objects. This change maintains consistency throughout the function and prevents potential issues with date comparisons.


Line range hint 166-170: Overall improvement in date handling consistency.

The changes in both cycle and module scenarios improve the consistency of date object handling throughout the burndown_plot function. This enhancement could potentially resolve subtle bugs related to date comparisons without altering the core logic of the burndown plot calculation.

To ensure the changes haven't introduced any unintended side effects, please run the following verification script:

This script will help identify any potential issues with function calls or date-related errors that might have been introduced by these changes.

Also applies to: 206-210

apiserver/plane/db/models/project.py (2)

2-2: LGTM: pytz import added correctly

The addition of the pytz import is appropriate for handling time zones in the Project model. It's correctly placed with other Python imports at the top of the file.


123-127: LGTM: timezone field added correctly

The addition of the timezone field to the Project model is well-implemented:

  • The TIMEZONE_CHOICES tuple provides a comprehensive list of time zones.
  • The timezone field is correctly defined with appropriate parameters.
  • The default value of "UTC" is a sensible choice.

Please ensure that a corresponding database migration has been created for this new field. You can verify this by running:

If no recent migration is found, you may need to create one using:

python manage.py makemigrations
apiserver/plane/app/views/cycle/issue.py (1)

251-251: Approve the datetime comparison change with suggestions.

The modification to use timezone.now() instead of timezone.now().date() improves the precision of the cycle end date check. This change allows for more accurate control over when issues can be added to a cycle, especially on the day the cycle is set to end.

However, to ensure robustness:

  1. Verify that the end_date field in the Cycle model is indeed a DateTimeField and not a DateField. If it's a DateField, consider updating the model or adjusting this comparison.

  2. Consider adding logging around this check for better traceability. For example:

if cycle.end_date is not None and cycle.end_date < timezone.now():
    logger.info(f"Attempt to add issue to completed cycle. Cycle ID: {cycle_id}, End Date: {cycle.end_date}, Current time: {timezone.now()}")
    return Response(
        {"error": "The Cycle has already been completed so no new issues can be added"},
        status=status.HTTP_400_BAD_REQUEST,
    )

This will help in debugging and monitoring the behavior of this condition in production.

To verify the end_date field type, please run the following command:

If this command doesn't return a match, it might indicate that end_date is not a DateTimeField, which would require further investigation.

✅ Verification successful

Verified: end_date is a DateTimeField.

The change to use timezone.now() instead of timezone.now().date() is appropriate and aligns with the end_date field type in the Cycle model. This ensures precise datetime comparisons for cycle end dates.

No further issues detected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the field type of end_date in Cycle model
ast-grep --lang python --pattern 'class Cycle($$$):
    $$$
    end_date = models.DateTimeField($$$)
    $$$'

Length of output: 3861

apiserver/plane/app/views/workspace/user.py (3)

507-507: Improved precision in upcoming cycles filtering

The change from timezone.now().date() to timezone.now() enhances the accuracy of determining upcoming cycles. This modification allows for more precise datetime comparisons, potentially including cycles that start later in the current day, which were previously excluded when only comparing dates.


515-516: Enhanced accuracy in present cycle determination

The changes to use timezone.now() instead of timezone.now().date() for both start_date and end_date comparisons improve the precision of determining the present cycle. This modification allows for more accurate datetime comparisons, potentially affecting which cycles are considered "present" based on the exact current time rather than just the date.


507-516: Summary of changes: Improved precision in cycle filtering

The modifications in the WorkspaceUserProfileStatsEndpoint class enhance the accuracy of determining upcoming and present cycles. By using timezone.now() instead of timezone.now().date(), the code now performs more precise datetime comparisons. This change allows for better handling of edge cases, such as cycles starting or ending later in the current day.

These improvements maintain the overall functionality while providing a more accurate representation of cycle statuses. The changes are consistent and do not introduce any apparent issues or conflicts with the rest of the codebase.

apiserver/plane/app/views/cycle/archive.py (1)

607-607: Improved precision in cycle archiving condition

The change from cycle.end_date >= timezone.now().date() to cycle.end_date >= timezone.now() enhances the accuracy of the cycle archiving condition. This modification ensures that cycles can only be archived after their exact end date and time have passed, rather than just the date.

To ensure this change doesn't introduce any unexpected behavior, please verify the following:

  1. Check if there are any other parts of the codebase that rely on the previous date-only comparison.
  2. Confirm that the end_date field of the Cycle model includes both date and time information.

You can use the following script to check for other occurrences of similar comparisons:

✅ Verification successful

Verification Successful: No Additional Instances Found

The updated condition cycle.end_date >= timezone.now() in archive.py is isolated and does not affect other parts of the codebase. No additional occurrences of cycle.end_date compared to timezone.now().date() were found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar date comparisons in the codebase
rg --type python 'cycle.*end_date.*timezone\.now\(\)\.date\(\)'

Length of output: 96


Script:

#!/bin/bash
# Search for similar date comparisons in the codebase within Python files
rg 'cycle.*end_date.*timezone\.now\(\)\.date\(\)' --glob '*.py'

Length of output: 65

apiserver/plane/api/views/cycle.py (4)

210-210: Improved datetime precision in cycle filtering

The change from timezone.now().date() to timezone.now() enhances the accuracy of cycle filtering. This modification allows for more precise comparisons, considering both date and time, which is particularly beneficial for cycles that may end or start at specific times within a day.


540-540: Enhanced precision in cycle archiving condition

The update from timezone.now().date() to timezone.now() in the cycle archiving condition improves the accuracy of determining when a cycle can be archived. This change ensures that cycles are only archived when they are truly completed, taking into account both the date and time of completion. This precision is crucial for maintaining the integrity of cycle management, especially for cycles that end at specific times within a day.


1149-1149: Improved accuracy in cycle completion check for issue transfers

The modification from timezone.now().date() to timezone.now() in the cycle completion check enhances the precision of determining whether issues can be transferred to a cycle. This change ensures that issues are not transferred to cycles that have genuinely ended, taking into account both the date and time of cycle completion. This increased accuracy is vital for maintaining the integrity of cycle management and preventing issues from being incorrectly assigned to completed cycles.


Line range hint 210-1149: Overall improvement in datetime precision for cycle management

The changes made throughout this file consistently enhance the precision of datetime comparisons in cycle management. By replacing timezone.now().date() with timezone.now(), the code now accurately handles scenarios where cycle timings are critical down to the hour, minute, or second. This improvement affects cycle filtering, archiving, and issue transfer operations, ensuring that the system behaves correctly even in edge cases where cycles end or start at specific times within a day.

These modifications align with Django best practices for datetime handling and will lead to more reliable and precise cycle management throughout the application. The consistency of these changes across different methods and classes is commendable and shows a thorough approach to addressing this aspect of the system.

apiserver/plane/app/views/cycle/base.py (3)

311-311: Improved date comparison precision

The change from timezone.now().date() to timezone.now() enhances the accuracy of the date comparison by including the time component. This modification ensures that cycles are more precisely evaluated for their completion status, potentially allowing updates closer to the end of the day.


928-928: Consistent improvement in date comparison precision

This change from timezone.now().date() to timezone.now() is consistent with the earlier modification in the CycleViewSet.partial_update method. It enhances the accuracy of determining if a cycle is completed when transferring issues, ensuring that the time component is considered. This improvement allows for more precise control over issue transfers near the cycle's end date.


Line range hint 1-1324: Summary of changes: Improved date comparison precision in cycle management

The modifications in this file consistently improve the precision of date comparisons in cycle management operations. By changing from timezone.now().date() to timezone.now(), the system now considers both date and time when evaluating cycle statuses. This enhancement affects both updating cycles and transferring issues between cycles, allowing for more accurate control, especially near the end of a cycle's duration. These targeted changes should improve the overall reliability of cycle-related operations without introducing significant risks.

apiserver/plane/db/models/cycle.py (1)

61-66: Ensure timezone-aware DateTimeField usage for start_date and end_date

Now that start_date and end_date have been changed to DateTimeField, it's important to handle timezone-aware datetimes consistently. Ensure that when saving and retrieving these fields, the datetime objects are timezone-aware, especially in relation to the timezone field you've introduced.

Consider verifying that datetime values are correctly managed with respect to the specified timezone.

apiserver/plane/db/models/draft.py (3)

7-7: Ensure the strip_tags function is properly imported and used.

Verify that the strip_tags function from plane.utils.html_processor is correctly implemented and handles all necessary HTML tags to prevent any unintended content from remaining in the description_stripped field.


238-244: Verify the use of OneToOneField in DraftIssueCycle.

Ensure that a draft issue should be associated with only one cycle. If a draft issue can be part of multiple cycles, consider using ForeignKey instead of OneToOneField.

If a ForeignKey is more appropriate, apply this diff:

-    draft_issue = models.OneToOneField(
+    draft_issue = models.ForeignKey(
         "db.DraftIssue",
         on_delete=models.CASCADE,
         related_name="draft_issue_cycle",
     )

48-53: Validate the PRIORITY_CHOICES and alignment with business logic.

Ensure that the priority levels 'urgent', 'high', 'medium', 'low', and 'none' align with the application's priority handling and user expectations.

apiserver/plane/app/views/workspace/draft.py (2)

235-236: Confirm successful deletion response

After deleting a DraftIssue, the method returns HTTP_204_NO_CONTENT. Ensure that this response is appropriate for your API consumers and that it aligns with RESTful practices.

Check if additional information should be returned upon successful deletion, such as a confirmation message.


114-115: Ensure consistent access to draft issues in partial_update

In the partial_update method, the query filters on created_by=request.user. This restricts updates to the creator of the draft issue. Confirm whether this aligns with your permission model. If other roles should have access, adjust the filters accordingly.

Verify if other users should be able to update draft issues not created by them. If so, remove or modify the created_by filter.

apiserver/plane/db/migrations/0077_draftissue_cycle_user_timezone_project_user_timezone_and_more.py (2)

133-218: Verify model definitions and relationships for consistency.

The new models (DraftIssue, DraftIssueModule, DraftIssueLabel, DraftIssueCycle, DraftIssueAssignee) should accurately reflect the structure and relationships of their corresponding existing models. Ensure that:

  • All necessary fields are included.
  • Field types and constraints match those of the original models.
  • Relationships (ForeignKeys, OneToOneFields, ManyToManyFields) are correctly set up.
  • Meta options like db_table, ordering, and verbose_name are appropriately defined.

To confirm, you can compare the new model definitions with the existing ones in your models.py files.

Also applies to: 1529-2036


113-121: Data integrity: Verify the order of bulk_create operations.

Ensure that the bulk creation of related objects occurs after the DraftIssue instances have been saved to the database. Since related objects depend on the primary keys of the DraftIssue instances, it's crucial that these instances are saved first.

Confirm that DraftIssue.objects.bulk_create(draft_issues) is executed before bulk creating related objects.

@@ -1,3 +1,6 @@
# Python imports
import pytz
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider replacing pytz with zoneinfo for timezone management

Starting from Python 3.9 and Django 4.0, the standard library's zoneinfo module is recommended over pytz for handling timezones. This aligns with current best practices and reduces external dependencies.

Here's how you might update the import:

-import pytz
+from zoneinfo import ZoneInfo, available_timezones

You'll also need to adjust the code where pytz.all_timezones is used.

Committable suggestion was skipped due to low confidence.

Comment on lines +80 to +83
TIMEZONE_CHOICES = tuple(zip(pytz.all_timezones, pytz.all_timezones))
timezone = models.CharField(
max_length=255, default="UTC", choices=TIMEZONE_CHOICES
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update timezone choices and handle timezones appropriately

If you decide to use zoneinfo, you'll need to update the TIMEZONE_CHOICES accordingly. Also, ensure that the timezone data is correctly applied when working with datetime fields.

Here's how you might adjust the TIMEZONE_CHOICES:

- TIMEZONE_CHOICES = tuple(zip(pytz.all_timezones, pytz.all_timezones))
+ TIMEZONE_CHOICES = tuple(zip(sorted(available_timezones()), sorted(available_timezones())))

And update the timezone field:

 timezone = models.CharField(
     max_length=255, default="UTC", choices=TIMEZONE_CHOICES
 )

Ensure that all datetime operations respect the selected timezone.

Committable suggestion was skipped due to low confidence.

Comment on lines +87 to +106
def save(self, *args, **kwargs):
if self.state is None:
try:
from plane.db.models import State

default_state = State.objects.filter(
~models.Q(is_triage=True),
project=self.project,
default=True,
).first()
if default_state is None:
random_state = State.objects.filter(
~models.Q(is_triage=True), project=self.project
).first()
self.state = random_state
else:
self.state = default_state
except ImportError:
pass
else:
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

Avoid importing models within methods and handle exceptions carefully.

Importing State within the save method can lead to potential circular imports and performance issues. Consider moving the import statements to the top of the file. Additionally, catching ImportError might mask other issues. Ensure exceptions are specific and provide meaningful error handling.

Apply this diff to move imports to the top level:

 # Module imports
 from plane.utils.html_processor import strip_tags
+from plane.db.models import State

 from .workspace import WorkspaceBaseModel

 ...

 def save(self, *args, **kwargs):
-    try:
-        from plane.db.models import State
-
         if self.state is None:
             # Logic for default state
             ...

-    except ImportError:
-        pass
     else:
         # Logic for updating `completed_at`
         ...

-    try:
-        from plane.db.models import State
-
-        # Additional logic
-
-    except ImportError:
-        pass

Also applies to: 107-116

Comment on lines +118 to +126
# Strip the html tags using html parser
self.description_stripped = (
None
if (
self.description_html == ""
or self.description_html is None
)
else strip_tags(self.description_html)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor duplicated code in the save method.

The logic for setting self.description_stripped is duplicated. Refactor the code to avoid repetition by moving the common logic outside the conditional blocks.

Apply this diff to refactor:

 def save(self, *args, **kwargs):
     if self.state is None:
         # Logic for default state
         ...

     else:
         # Logic for updating `completed_at`
         ...

     # Strip the HTML tags using HTML parser
     self.description_stripped = (
         None
         if not self.description_html
         else strip_tags(self.description_html)
     )

     if self._state.adding:
         # Logic for new instances
         largest_sort_order = DraftIssue.objects.filter(
             project=self.project, state=self.state
         ).aggregate(largest=models.Max("sort_order"))["largest"]
         if largest_sort_order is not None:
             self.sort_order = largest_sort_order + 10000

     super(DraftIssue, self).save(*args, **kwargs)

Also applies to: 136-144

Comment on lines +127 to +132
largest_sort_order = DraftIssue.objects.filter(
project=self.project, state=self.state
).aggregate(largest=models.Max("sort_order"))["largest"]
if largest_sort_order is not None:
self.sort_order = largest_sort_order + 10000

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

Handle case when no existing sort_order is found.

In the save method, when calculating largest_sort_order, if no existing issues are found, largest_sort_order will be None. Ensure that self.sort_order is set appropriately in this case to avoid errors.

Apply this diff to handle the case:

 if largest_sort_order is not None:
     self.sort_order = largest_sort_order + 10000
+else:
+    self.sort_order = 10000  # Starting sort order value if none exists
📝 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
largest_sort_order = DraftIssue.objects.filter(
project=self.project, state=self.state
).aggregate(largest=models.Max("sort_order"))["largest"]
if largest_sort_order is not None:
self.sort_order = largest_sort_order + 10000
largest_sort_order = DraftIssue.objects.filter(
project=self.project, state=self.state
).aggregate(largest=models.Max("sort_order"))["largest"]
if largest_sort_order is not None:
self.sort_order = largest_sort_order + 10000
else:
self.sort_order = 10000 # Starting sort order value if none exists

Comment on lines +220 to +866
("Indian/Chagos", "Indian/Chagos"),
("Indian/Christmas", "Indian/Christmas"),
("Indian/Cocos", "Indian/Cocos"),
("Indian/Comoro", "Indian/Comoro"),
("Indian/Kerguelen", "Indian/Kerguelen"),
("Indian/Mahe", "Indian/Mahe"),
("Indian/Maldives", "Indian/Maldives"),
("Indian/Mauritius", "Indian/Mauritius"),
("Indian/Mayotte", "Indian/Mayotte"),
("Indian/Reunion", "Indian/Reunion"),
("Iran", "Iran"),
("Israel", "Israel"),
("Jamaica", "Jamaica"),
("Japan", "Japan"),
("Kwajalein", "Kwajalein"),
("Libya", "Libya"),
("MET", "MET"),
("MST", "MST"),
("MST7MDT", "MST7MDT"),
("Mexico/BajaNorte", "Mexico/BajaNorte"),
("Mexico/BajaSur", "Mexico/BajaSur"),
("Mexico/General", "Mexico/General"),
("NZ", "NZ"),
("NZ-CHAT", "NZ-CHAT"),
("Navajo", "Navajo"),
("PRC", "PRC"),
("PST8PDT", "PST8PDT"),
("Pacific/Apia", "Pacific/Apia"),
("Pacific/Auckland", "Pacific/Auckland"),
("Pacific/Bougainville", "Pacific/Bougainville"),
("Pacific/Chatham", "Pacific/Chatham"),
("Pacific/Chuuk", "Pacific/Chuuk"),
("Pacific/Easter", "Pacific/Easter"),
("Pacific/Efate", "Pacific/Efate"),
("Pacific/Enderbury", "Pacific/Enderbury"),
("Pacific/Fakaofo", "Pacific/Fakaofo"),
("Pacific/Fiji", "Pacific/Fiji"),
("Pacific/Funafuti", "Pacific/Funafuti"),
("Pacific/Galapagos", "Pacific/Galapagos"),
("Pacific/Gambier", "Pacific/Gambier"),
("Pacific/Guadalcanal", "Pacific/Guadalcanal"),
("Pacific/Guam", "Pacific/Guam"),
("Pacific/Honolulu", "Pacific/Honolulu"),
("Pacific/Johnston", "Pacific/Johnston"),
("Pacific/Kanton", "Pacific/Kanton"),
("Pacific/Kiritimati", "Pacific/Kiritimati"),
("Pacific/Kosrae", "Pacific/Kosrae"),
("Pacific/Kwajalein", "Pacific/Kwajalein"),
("Pacific/Majuro", "Pacific/Majuro"),
("Pacific/Marquesas", "Pacific/Marquesas"),
("Pacific/Midway", "Pacific/Midway"),
("Pacific/Nauru", "Pacific/Nauru"),
("Pacific/Niue", "Pacific/Niue"),
("Pacific/Norfolk", "Pacific/Norfolk"),
("Pacific/Noumea", "Pacific/Noumea"),
("Pacific/Pago_Pago", "Pacific/Pago_Pago"),
("Pacific/Palau", "Pacific/Palau"),
("Pacific/Pitcairn", "Pacific/Pitcairn"),
("Pacific/Pohnpei", "Pacific/Pohnpei"),
("Pacific/Ponape", "Pacific/Ponape"),
("Pacific/Port_Moresby", "Pacific/Port_Moresby"),
("Pacific/Rarotonga", "Pacific/Rarotonga"),
("Pacific/Saipan", "Pacific/Saipan"),
("Pacific/Samoa", "Pacific/Samoa"),
("Pacific/Tahiti", "Pacific/Tahiti"),
("Pacific/Tarawa", "Pacific/Tarawa"),
("Pacific/Tongatapu", "Pacific/Tongatapu"),
("Pacific/Truk", "Pacific/Truk"),
("Pacific/Wake", "Pacific/Wake"),
("Pacific/Wallis", "Pacific/Wallis"),
("Pacific/Yap", "Pacific/Yap"),
("Poland", "Poland"),
("Portugal", "Portugal"),
("ROC", "ROC"),
("ROK", "ROK"),
("Singapore", "Singapore"),
("Turkey", "Turkey"),
("UCT", "UCT"),
("US/Alaska", "US/Alaska"),
("US/Aleutian", "US/Aleutian"),
("US/Arizona", "US/Arizona"),
("US/Central", "US/Central"),
("US/East-Indiana", "US/East-Indiana"),
("US/Eastern", "US/Eastern"),
("US/Hawaii", "US/Hawaii"),
("US/Indiana-Starke", "US/Indiana-Starke"),
("US/Michigan", "US/Michigan"),
("US/Mountain", "US/Mountain"),
("US/Pacific", "US/Pacific"),
("US/Samoa", "US/Samoa"),
("UTC", "UTC"),
("Universal", "Universal"),
("W-SU", "W-SU"),
("WET", "WET"),
("Zulu", "Zulu"),
],
default="UTC",
max_length=255,
),
),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor: Use Django's built-in timezone choices instead of hardcoding.

The extensive hardcoded lists of timezones for the timezone fields in the cycle and project models may lead to maintenance issues and possible inconsistencies. Instead, consider utilizing Django's built-in timezone support to dynamically generate the list of choices. This approach ensures that the timezones are always up-to-date and reduces code duplication.

Apply this diff to refactor the timezone fields:

-from django.conf import settings
+from django.conf import settings
+from django.utils import timezone

 field=models.CharField(
-    choices=[
-        # Extensive list of timezones
-    ],
+    choices=[(tz, tz) for tz in pytz.all_timezones],
     default="UTC",
-    max_length=255,
+    max_length=64,
 )

Ensure you have imported pytz if it's not already available:

+import pytz

This change leverages pytz.all_timezones to generate the choices dynamically.

Also applies to: 867-1514

Comment on lines +10 to +123
.select_related("issue_cycle__cycle")
.prefetch_related(
Prefetch(
"issue_assignee",
queryset=IssueAssignee.objects.select_related("assignee"),
),
Prefetch(
"label_issue",
queryset=IssueLabel.objects.select_related("label"),
),
Prefetch(
"issue_module",
queryset=ModuleIssue.objects.select_related("module"),
),
)
)

draft_issues = []
draft_issue_cycle = []
draft_issue_labels = []
draft_issue_modules = []
draft_issue_assignees = []
# issue_ids_to_delete = []

for issue in issues:
draft_issue = DraftIssue(
parent_id=issue.parent_id,
state_id=issue.state_id,
estimate_point_id=issue.estimate_point_id,
name=issue.name,
description=issue.description,
description_html=issue.description_html,
description_stripped=issue.description_stripped,
description_binary=issue.description_binary,
priority=issue.priority,
start_date=issue.start_date,
target_date=issue.target_date,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
created_by_id=issue.created_by_id,
updated_by_id=issue.updated_by_id,
)
draft_issues.append(draft_issue)

for assignee in issue.issue_assignee.all():
draft_issue_assignees.append(
DraftIssueAssignee(
draft_issue=draft_issue,
assignee=assignee.assignee,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
)
)

# Prepare labels for bulk insert
for label in issue.label_issue.all():
draft_issue_labels.append(
DraftIssueLabel(
draft_issue=draft_issue,
label=label.label,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
)
)

for module_issue in issue.issue_module.all():
draft_issue_modules.append(
DraftIssueModule(
draft_issue=draft_issue,
module=module_issue.module,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
)
)

if hasattr(issue, "issue_cycle") and issue.issue_cycle:
draft_issue_cycle.append(
DraftIssueCycle(
draft_issue=draft_issue,
cycle=issue.issue_cycle.cycle,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
)
)

# issue_ids_to_delete.append(issue.id)

# Bulk create draft issues
DraftIssue.objects.bulk_create(draft_issues)

# Bulk create draft assignees and labels
DraftIssueLabel.objects.bulk_create(draft_issue_labels)
DraftIssueAssignee.objects.bulk_create(draft_issue_assignees)

# Bulk create draft modules
DraftIssueCycle.objects.bulk_create(draft_issue_cycle)
DraftIssueModule.objects.bulk_create(draft_issue_modules)

# Delete original issues
# Issue.objects.filter(id__in=issue_ids_to_delete).delete()
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

Exception handling: Add error handling for bulk operations.

When performing bulk operations, such as bulk_create, it's important to handle potential exceptions that might arise due to data issues or database constraints. Consider wrapping the bulk operations in try-except blocks to catch exceptions like IntegrityError or DataError.

Example:

from django.db import IntegrityError

try:
    DraftIssue.objects.bulk_create(draft_issues)
except IntegrityError as e:
    # Handle the exception or log the error
    print(f"Bulk create failed: {e}")

This ensures that your migration can gracefully handle unexpected issues without leaving the database in an inconsistent state.

Comment on lines +51 to +65
state_id=issue.state_id,
estimate_point_id=issue.estimate_point_id,
name=issue.name,
description=issue.description,
description_html=issue.description_html,
description_stripped=issue.description_stripped,
description_binary=issue.description_binary,
priority=issue.priority,
start_date=issue.start_date,
target_date=issue.target_date,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
created_by_id=issue.created_by_id,
updated_by_id=issue.updated_by_id,
)
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

Null handling: Ensure fields are properly managed during migration.

Some fields in the Issue model might contain null values, which could lead to exceptions when creating DraftIssue instances. Confirm that all fields are accurately handling nulls. For example, if estimate_point_id or description can be null, ensure that the migration accounts for this.

Consider updating the assignment with default values or checks:

estimate_point_id=issue.estimate_point_id if issue.estimate_point_id else None,
description=issue.description if issue.description else {},

Comment on lines +68 to +77
for assignee in issue.issue_assignee.all():
draft_issue_assignees.append(
DraftIssueAssignee(
draft_issue=draft_issue,
assignee=assignee.assignee,
workspace_id=issue.workspace_id,
project_id=issue.project_id,
)
)

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Performance improvement: Optimize loops with list comprehensions.

The loops for creating DraftIssueAssignee, DraftIssueLabel, and DraftIssueModule instances can be optimized using list comprehensions. This can improve readability and potentially enhance performance.

Example:

draft_issue_assignees.extend([
    DraftIssueAssignee(
        draft_issue=draft_issue,
        assignee=assignee.assignee,
        workspace_id=issue.workspace_id,
        project_id=issue.project_id,
    )
    for assignee in issue.issue_assignee.all()
])

Apply similar changes to the loops for labels and modules.

Comment on lines +16 to +17
DraftIssueLabel = apps.get_model("db", "DraftIssueLabel")
ModuleIssue = apps.get_model("db", "ModuleIssue")
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

Missing import: Ensure all models are correctly referenced.

In line 17, ModuleIssue is used but may not have been imported. Since you’re using apps.get_model, ensure that all models are retrieved appropriately.

Confirm that ModuleIssue is obtained correctly:

ModuleIssue = apps.get_model("db", "ModuleIssue")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚙️backend 🔄migrations Contains Migration changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants