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-2631] chore: changed the cascading logic for soft delete #5829

Merged
merged 3 commits into from
Oct 15, 2024

Conversation

NarayanBavisetti
Copy link
Collaborator

@NarayanBavisetti NarayanBavisetti commented Oct 14, 2024

chore:

  • changed the cascading logic for soft delete

Issue Link: WEB-2631

Summary by CodeRabbit

  • New Features

    • Enhanced soft deletion logic for related objects, allowing for more flexible handling of deletions.
    • Improved data structure handling when creating cycle issue records in the workspace draft.
  • Bug Fixes

    • Addressed serialization issues in the creation of draft to issue records.

@NarayanBavisetti NarayanBavisetti added 🐛bug Something isn't working ⚙️backend labels Oct 14, 2024
Copy link
Contributor

coderabbitai bot commented Oct 14, 2024

Walkthrough

The changes in this pull request involve modifications to the soft_delete_related_objects function in deletion_task.py, broadening the conditional check for the on_delete attribute. A new but unimplemented function, restore_related_objects, has also been added. Additionally, in draft.py, the create_draft_to_issue method of the WorkspaceDraftIssueViewSet class has been updated to improve the serialization of created_records.

Changes

File Path Change Summary
apiserver/plane/bgtasks/deletion_task.py Modified soft_delete_related_objects function's conditional check for on_delete; added unimplemented restore_related_objects function.
apiserver/plane/app/views/workspace/draft.py Updated serialization of created_records in create_draft_to_issue method of WorkspaceDraftIssueViewSet.

Possibly related PRs

Suggested labels

🔄migrations

Suggested reviewers

  • pablohashescobar
  • sriramveeraghanta

🐇 In the meadow, changes bloom,
Drafts and deletions make room.
A soft delete, a new way to play,
With records serialized, bright as day!
Hopping along, we celebrate,
The code grows better, oh how great! 🌼


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9572f02 and 765240a.

📒 Files selected for processing (1)
  • apiserver/plane/bgtasks/deletion_task.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apiserver/plane/bgtasks/deletion_task.py

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.

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

🧹 Outside diff range and nitpick comments (3)
apiserver/plane/bgtasks/deletion_task.py (3)

Line range hint 46-47: Implement the restore_related_objects function

The restore_related_objects function has been added but is currently unimplemented. This function seems intended to complement the soft delete functionality by providing a way to restore related objects.

To complete this feature:

  1. Implement the logic to restore soft-deleted related objects.
  2. Ensure it handles all cases covered by soft_delete_related_objects.
  3. Add appropriate error handling and logging.
  4. Write unit tests to verify the restoration process.

Would you like assistance in drafting an initial implementation for this function?


Line range hint 1-165: Summary of review and next steps

This review has identified several areas for improvement in the deletion tasks:

  1. The changes to soft_delete_related_objects need revision to ensure correct handling of on_delete behaviors.
  2. The new restore_related_objects function needs to be implemented.
  3. The hard_delete function, while unchanged, could benefit from refactoring for improved maintainability.

To improve the overall design and reliability of these background tasks:

  1. Implement comprehensive error handling and logging throughout these functions.
  2. Consider adding transaction management to ensure data consistency during these operations.
  3. Implement the restore_related_objects function with proper testing.
  4. Refactor the hard_delete function as suggested for better maintainability.
  5. Add integration tests to verify the entire deletion and restoration workflow.

These improvements will enhance the robustness and maintainability of the deletion and restoration processes in the system.


The proposed refactor of hard_delete would miss several models currently handled by the function

While the refactoring suggestion aims to improve maintainability by dynamically identifying models with a deleted_at field through inheritance, the current implementation of hard_delete handles numerous models that do not inherit from the specified base classes (AuditModel, TimeAuditModel, UserAuditModel, SoftDeleteModel). As a result, the proposed approach would exclude these models, leading to incomplete hard deletion operations.

Models not covered by the proposed refactor:

  • Workspace
  • Project
  • Cycle
  • Module
  • Issue
  • Page
  • IssueView
  • Label
  • State
  • IssueActivity
  • IssueComment
  • IssueLink
  • IssueReaction
  • UserFavorite
  • ModuleIssue
  • CycleIssue
  • Estimate
  • EstimatePoint

To ensure comprehensive coverage, consider updating the refactor to include all models currently managed by hard_delete, possibly by:

  1. Expanding the list of base classes to include all relevant classes that define deleted_at.
  2. Implementing a search mechanism that directly identifies all models with a deleted_at field, regardless of inheritance.
🔗 Analysis chain

Line range hint 50-165: Consider refactoring the hard_delete function for improved maintainability

While the hard_delete function is unchanged in this PR, its current implementation has some potential issues:

  1. It explicitly lists many models, which could become difficult to maintain as the number of models grows.
  2. It uses a fixed number of days (HARD_DELETE_AFTER_DAYS) for all models, which might not be flexible enough for different data retention requirements.

Consider refactoring this function to:

  1. Use Django's content types framework to dynamically get all models with a deleted_at field.
  2. Allow for model-specific retention periods.

Here's a sketch of how this could look:

from django.contrib.contenttypes.models import ContentType

@shared_task
def hard_delete():
    for content_type in ContentType.objects.all():
        model = content_type.model_class()
        if hasattr(model, 'deleted_at'):
            retention_days = getattr(model, 'HARD_DELETE_AFTER_DAYS', settings.HARD_DELETE_AFTER_DAYS)
            model.all_objects.filter(
                deleted_at__lt=timezone.now() - timezone.timedelta(days=retention_days)
            ).delete()

This approach would be more maintainable and flexible. It would automatically handle new models with deleted_at fields and allow for model-specific retention periods.

To ensure this refactoring wouldn't miss any current models, let's check which models have a deleted_at field:

Compare the results of this search with the models explicitly listed in the current hard_delete function to ensure all are covered by the proposed refactoring.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for models with a deleted_at field
rg --type python 'deleted_at\s*=\s*models\.DateTimeField' -g '!*/migrations/*'

Length of output: 111


Script:

#!/bin/bash
# Search for models with a deleted_at field using the correct file type identifier
rg --type py 'deleted_at\s*=\s*models\.DateTimeField' -g '!*/migrations/*'

Length of output: 144


Script:

#!/bin/bash
# Identify base classes with 'deleted_at' in mixins.py
base_classes=$(rg --type py 'class\s+(\w+)\(.*\):' apiserver/plane/db/mixins.py | sed -E 's/class\s+(\w+)\(.*:/\1/')

# Search for models inheriting from these base classes
for base in $base_classes; do
    rg --type py "class\s+\w+\(.*${base}.*\):" -g '!*/migrations/*'
done

Length of output: 1701


Script:

#!/bin/bash
# List of models handled by hard_delete
models=(
    Workspace
    Project
    Cycle
    Module
    Issue
    Page
    IssueView
    Label
    State
    IssueActivity
    IssueComment
    IssueLink
    IssueReaction
    UserFavorite
    ModuleIssue
    CycleIssue
    Estimate
    EstimatePoint
)

# Base classes that include 'deleted_at'
base_classes=(
    AuditModel
    TimeAuditModel
    UserAuditModel
    SoftDeleteModel
)

# Check inheritance for each model
for model in "${models[@]}"; do
    # Search for the model class definition and its base classes
    inheritance=$(rg --type py "class\s+${model}\(.*\):" -g '!*/migrations/*' | grep -Eo "\(.*\)" | tr -d '()')
    # Check if any base class is in the list of base_classes
    inherited=false
    for base in "${base_classes[@]}"; do
        if echo "$inheritance" | grep -w "$base" > /dev/null; then
            inherited=true
            break
        fi
    done
    if [ "$inherited" = true ]; then
        echo "${model}: Inherits from a base class with 'deleted_at'"
    else
        echo "${model}: Does NOT inherit from a base class with 'deleted_at'"
    fi
done

Length of output: 12341

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ee823d2 and 9572f02.

📒 Files selected for processing (2)
  • apiserver/plane/app/views/workspace/draft.py (1 hunks)
  • apiserver/plane/bgtasks/deletion_task.py (1 hunks)
🧰 Additional context used
🔇 Additional comments (1)
apiserver/plane/app/views/workspace/draft.py (1)

282-282: LGTM, but verify impact on activity logging.

The change to serialize created_records as a list looks good and likely aligns with the expected data structure for the issue_activity task. However, please ensure the following:

  1. Verify that the issue_activity task and any downstream processes correctly handle this list structure.
  2. Check if similar changes are needed in other parts of the codebase for consistency.

To verify the consistency of this change across the codebase, please run the following script:

This will help identify if similar changes are needed elsewhere in the codebase.

Comment on lines 24 to 25
not hasattr(field.remote_field, "on_delete")
or field.remote_field.on_delete == "CASCADE"
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Incorrect usage of on_delete in deletion_task.py

The condition field.remote_field.on_delete == "CASCADE" uses a string literal instead of the models.CASCADE constant. This is likely incorrect and may prevent the condition from working as intended.

Suggested Revision:

if (
    not hasattr(field.remote_field, "on_delete")
    or field.remote_field.on_delete == models.CASCADE
):
🔗 Analysis chain

Review the changes in the on_delete condition

The modification to the on_delete check introduces two potential issues:

  1. The condition now includes cases where the on_delete attribute doesn't exist. This could lead to unexpected soft deletions for fields where on_delete behavior is not explicitly defined.

  2. The comparison field.remote_field.on_delete == "CASCADE" uses a string literal "CASCADE" instead of models.CASCADE. This is likely incorrect and won't match the actual models.CASCADE value.

Consider revising the condition as follows:

if (
    hasattr(field.remote_field, "on_delete") and
    field.remote_field.on_delete == models.CASCADE
):

This maintains the original behavior of only soft-deleting related objects when CASCADE is explicitly specified.

To ensure we're not missing any custom on_delete implementations, let's check the codebase:

If this search returns results, we may need to adjust our approach to handle custom on_delete behaviors.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for custom on_delete implementations
rg --type python 'on_delete\s*=(?!.*models\.CASCADE).*' -g '!*/migrations/*'

Length of output: 331


Script:

#!/bin/bash
# Search for custom on_delete implementations using PCRE2 to support look-around
rg --pcre2 --type python 'on_delete\s*=(?!.*models\.CASCADE).*' -g '!*/migrations/*'

Length of output: 117


Script:

#!/bin/bash
# Search for custom on_delete implementations using PCRE2 and target Python files
rg --pcre2 'on_delete\s*=(?!.*models\.CASCADE).*' -g '*.py' -g '!*/migrations/*'

Length of output: 97472

@pushya22 pushya22 merged commit 3d7d3c8 into preview Oct 15, 2024
14 of 15 checks passed
@pushya22 pushya22 deleted the chore/project-soft-delete branch October 15, 2024 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚙️backend 🐛bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants