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-2092] fix: added unique constraints for project, module and states #5281

Merged
merged 2 commits into from
Jul 31, 2024

Conversation

NarayanBavisetti
Copy link
Collaborator

@NarayanBavisetti NarayanBavisetti commented Jul 31, 2024

fix:

  • added unique constraints for project, module, and labels.
  • this PR fixes the bug where the project was not being deleted when deleting a page.
  • also resolved the issue where issues were not being deleted when removing modules or cycles.

Issue Link: WEB-2092

Summary by CodeRabbit

  • New Features

    • Introduced new functionality for handling soft deletions, allowing for better management of deletion timestamps across various models.
    • Enhanced data integrity by implementing unique constraints that allow multiple records when soft deleted.
  • Bug Fixes

    • Improved the deletion process to ensure associated records are also deleted, maintaining data integrity.
  • Chores

    • Cleaned up code formatting for better readability throughout several files.

Copy link
Contributor

coderabbitai bot commented Jul 31, 2024

Walkthrough

The recent changes significantly enhance the application's management of soft deletions by introducing a deleted_at field across various models and serializers. This allows improved data tracking and integrity, ensuring that relationships between models are maintained when entities are marked as deleted. Additionally, modifications to deletion methods ensure that associated records are also removed, preventing orphaned entries in the database and improving overall functionality.

Changes

Files Change Summary
apiserver/plane/api/serializers/cycle.py, module.py, project.py Added deleted_at field to Meta classes for cycle, module, and project serializers, enhancing soft deletion tracking and lifecycle management.
apiserver/plane/api/views/cycle.py, module.py, base.py Modified delete and destroy methods to also delete associated CycleIssue and ModuleIssue records upon deletion, ensuring data integrity.
apiserver/plane/api/views/cycle/issue.py Improved destroy method by changing retrieval from get() to filter(), increasing robustness in handling deletions.
apiserver/plane/api/views/issue/attachment.py Restricted deletion of attachments to creators or admins, adding security to the delete method.
apiserver/plane/db/migrations/0074_alter_label_unique_together_and_more.py Introduced new unique constraints with deleted_at to support soft deletions across various models.
apiserver/plane/db/models/issue.py, module.py, project.py Updated models to include deleted_at in uniqueness constraints, improving management of soft deletions and reinforcing data integrity.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CycleAPI
    participant CycleIssueDB

    User->>CycleAPI: Delete Cycle
    CycleAPI->>CycleIssueDB: Remove associated CycleIssues
    CycleAPI->>User: Confirm Cycle deletion
Loading
sequenceDiagram
    participant User
    participant ModuleAPI
    participant ModuleIssueDB

    User->>ModuleAPI: Delete Module
    ModuleAPI->>ModuleIssueDB: Remove associated ModuleIssues
    ModuleAPI->>User: Confirm Module deletion
Loading

Poem

🐇 In the garden of code, where soft deletes grow,
A timestamp is planted, to manage the flow.
With cycles and modules, we tidy the mess,
Removing old issues, we strive for success.
So hop with delight, as changes unfold,
In the realm of the digital, new tales to be told! 🌼


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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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 as 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.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

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

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 67f2e2f and 68b6472.

Files selected for processing (17)
  • apiserver/plane/api/serializers/cycle.py (1 hunks)
  • apiserver/plane/api/serializers/module.py (1 hunks)
  • apiserver/plane/api/serializers/project.py (1 hunks)
  • apiserver/plane/api/views/cycle.py (1 hunks)
  • apiserver/plane/api/views/module.py (1 hunks)
  • apiserver/plane/app/serializers/module.py (1 hunks)
  • apiserver/plane/app/serializers/project.py (1 hunks)
  • apiserver/plane/app/views/cycle/base.py (1 hunks)
  • apiserver/plane/app/views/cycle/issue.py (3 hunks)
  • apiserver/plane/app/views/issue/attachment.py (2 hunks)
  • apiserver/plane/app/views/module/base.py (1 hunks)
  • apiserver/plane/app/views/module/issue.py (5 hunks)
  • apiserver/plane/bgtasks/issue_activites_task.py (3 hunks)
  • apiserver/plane/db/migrations/0074_alter_label_unique_together_and_more.py (1 hunks)
  • apiserver/plane/db/models/issue.py (2 hunks)
  • apiserver/plane/db/models/module.py (2 hunks)
  • apiserver/plane/db/models/project.py (3 hunks)
Additional comments not posted (19)
apiserver/plane/api/serializers/cycle.py (1)

43-43: LGTM!

The addition of the deleted_at field to the read_only_fields list in the Meta class aligns with the objective of managing soft deletions.

apiserver/plane/db/migrations/0074_alter_label_unique_together_and_more.py (1)

1-49: LGTM!

The migration file correctly introduces unique constraints and conditions for the label, module, project, and projectidentifier models to handle soft deletions. This aligns with the objective of ensuring data integrity and uniqueness.

apiserver/plane/api/serializers/project.py (1)

34-34: LGTM!

The addition of the deleted_at field to the read_only_fields list in the Meta class aligns with the objective of managing soft deletions.

apiserver/plane/api/serializers/module.py (1)

42-42: Ensure proper handling of the new field deleted_at.

The addition of the deleted_at field to the fields list in the Meta class enhances the functionality of the serializer. Ensure that the deleted_at field is properly handled in the serializer's methods, such as to_representation, validate, create, and update.

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

100-107: Ensure proper handling of the new constraints.

The addition of the deleted_at field to the unique_together constraint and the new UniqueConstraint enhance data integrity and provide a mechanism for managing soft deletions. Ensure that the new constraints are properly handled in the model's methods, such as save, delete, and any custom methods that may interact with these constraints.

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

42-43: Addition of deleted_at field approved.

The deleted_at field has been correctly added to the read_only_fields list, ensuring it is included in the serialized output but not modifiable through the serializer.

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

31-32: Addition of deleted_at field approved.

The deleted_at field has been correctly added to the read_only_fields list, ensuring it is included in the serialized output but not modifiable through the serializer.

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

128-143: Modifications to unique_together constraints and addition of UniqueConstraint entries approved.

The modifications to the unique_together constraints and the addition of the new UniqueConstraint entries ensure that the combination of identifier and workspace as well as name and workspace are unique when deleted_at is null. This effectively prevents duplicates of active projects and maintains data integrity.


242-249: Modifications to unique_together constraints and addition of UniqueConstraint entry approved.

The modifications to the unique_together constraints and the addition of the new UniqueConstraint entry ensure that the combination of name and workspace is unique when deleted_at is null. This effectively prevents duplicates of active project identifiers and maintains data integrity.

apiserver/plane/app/views/module/issue.py (2)

Line range hint 310-323:
LGTM! But verify the function usage in the codebase.

The change to use filter() instead of get() improves robustness by preventing exceptions when no records are found. Ensure that all usages of destroy are verified to confirm compatibility with this change.


Line range hint 286-299:
LGTM! But verify the function usage in the codebase.

The change to use filter() instead of get() improves robustness by preventing exceptions when no records are found. Ensure that all usages of create_issue_modules are verified to confirm compatibility with this change.

Verification successful

LGTM! The change to use filter() instead of get() improves robustness by preventing exceptions when no records are found.

  • create_issue_modules method properly handles the results of filter().
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all usages of `create_issue_modules` to ensure compatibility with the changes.

# Test: Search for the function usage. Expect: No breaking changes.
rg --type python -A 5 $'create_issue_modules'

Length of output: 75


Script:

#!/bin/bash
# Description: Verify all usages of `create_issue_modules` to ensure compatibility with the changes.

# Test: Search for the function usage. Expect: No breaking changes.
rg --type py -A 5 $'create_issue_modules'

Length of output: 887


Script:

#!/bin/bash
# Description: Examine the content of `apiserver/plane/app/views/module/issue.py` around the `create_issue_modules` method to ensure proper handling of the `filter()` results.

# Test: Display the content of `apiserver/plane/app/views/module/issue.py` around the `create_issue_modules` method.
rg --type py -A 20 -B 10 $'def create_issue_modules' apiserver/plane/app/views/module/issue.py

Length of output: 1320


Script:

#!/bin/bash
# Description: Display the complete content of the `create_issue_modules` method in `apiserver/plane/app/views/module/issue.py`.

# Test: Display the complete content of the `create_issue_modules` method.
rg --type py -A 50 -B 10 $'def create_issue_modules' apiserver/plane/app/views/module/issue.py

Length of output: 2534

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

Line range hint 337-350:
LGTM! But verify the function usage in the codebase.

The change to use filter() instead of get() improves robustness by preventing exceptions when no records are found. Ensure that all usages of destroy are verified to confirm compatibility with this change.

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

538-545: LGTM! But verify the class usage in the codebase.

The change to enhance uniqueness constraints by adding the deleted_at field improves data integrity. Ensure that all usages of the Label class are verified to confirm compatibility with this change.

apiserver/plane/api/views/module.py (1)

304-307: Good addition for maintaining data integrity.

The added lines ensure that ModuleIssue records related to the deleted module are also removed, preventing orphaned records.

apiserver/plane/app/views/module/base.py (1)

776-779: Good addition for maintaining data integrity.

The added lines ensure that ModuleIssue records related to the deleted module are also removed, preventing orphaned records.

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

407-410: Good addition for maintaining data integrity.

The added lines ensure that CycleIssue records related to the deleted cycle are also removed, preventing orphaned records.

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

Line range hint 1085-1088:
LGTM!

The removal of the blank line is a minor formatting change and does not affect the logic or functionality.


675-675: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to delete_issue_activity match the new signature.

Verification successful

Function usage matches the new signature.

The only usage of delete_issue_activity is in the dictionary mapping, and no other calls were found in the codebase. Therefore, the function usage matches the new signature.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all function calls to `delete_issue_activity` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type python -A 5 $'delete_issue_activity'

Length of output: 76


Script:

#!/bin/bash
# Description: Verify all function calls to `delete_issue_activity` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type py -A 5 $'delete_issue_activity'

Length of output: 1127


Script:

#!/bin/bash
# Description: Verify all function calls to `delete_issue_activity` match the new signature.

# Test: Search for all function calls to `delete_issue_activity` across the codebase.
rg '\bdelete_issue_activity\b' --type py -A 5

Length of output: 1133

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

1085-1088: LGTM! But verify the function usage in the codebase.

The code changes are approved.

However, ensure that all function calls to destroy properly handle the deletion of associated CycleIssue records.

Comment on lines +52 to +64
if issue_attachment.created_by_id != request.user.id and (
not ProjectMember.objects.filter(
workspace__slug=slug,
member=request.user,
role=20,
project_id=project_id,
is_active=True,
).exists()
):
return Response(
{"error": "Only admin or creator can delete the attachment"},
status=status.HTTP_403_FORBIDDEN,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error handling and security measures.

The condition correctly restricts deletion to either the creator of the attachment or a user with a specific role (admin) within the project. However, consider handling the case where IssueAttachment.objects.get(pk=pk) raises a DoesNotExist exception to avoid potential server errors.

+ from django.core.exceptions import ObjectDoesNotExist

    def delete(self, request, slug, project_id, issue_id, pk):
+       try:
            issue_attachment = IssueAttachment.objects.get(pk=pk)
+       except ObjectDoesNotExist:
+           return Response(
+               {"error": "Issue attachment not found"},
+               status=status.HTTP_404_NOT_FOUND,
+           )
        if issue_attachment.created_by_id != request.user.id and (
            not ProjectMember.objects.filter(
                workspace__slug=slug,
                member=request.user,
                role=20,
                project_id=project_id,
                is_active=True,
            ).exists()
        ):
            return Response(
                {"error": "Only admin or creator can delete the attachment"},
                status=status.HTTP_403_FORBIDDEN,
            )
        issue_attachment.asset.delete(save=False)
        issue_attachment.delete()
        issue_activity.delay(
            type="attachment.activity.deleted",
            requested_data=None,
            actor_id=str(self.request.user.id),
            issue_id=str(self.kwargs.get("issue_id", None)),
            project_id=str(self.kwargs.get("project_id", None)),
            current_instance=None,
            epoch=int(timezone.now().timestamp()),
            notification=True,
            origin=request.META.get("HTTP_ORIGIN"),
        )

        return Response(status=status.HTTP_204_NO_CONTENT)
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
if issue_attachment.created_by_id != request.user.id and (
not ProjectMember.objects.filter(
workspace__slug=slug,
member=request.user,
role=20,
project_id=project_id,
is_active=True,
).exists()
):
return Response(
{"error": "Only admin or creator can delete the attachment"},
status=status.HTTP_403_FORBIDDEN,
)
from django.core.exceptions import ObjectDoesNotExist
def delete(self, request, slug, project_id, issue_id, pk):
try:
issue_attachment = IssueAttachment.objects.get(pk=pk)
except ObjectDoesNotExist:
return Response(
{"error": "Issue attachment not found"},
status=status.HTTP_404_NOT_FOUND,
)
if issue_attachment.created_by_id != request.user.id and (
not ProjectMember.objects.filter(
workspace__slug=slug,
member=request.user,
role=20,
project_id=project_id,
is_active=True,
).exists()
):
return Response(
{"error": "Only admin or creator can delete the attachment"},
status=status.HTTP_403_FORBIDDEN,
)
issue_attachment.asset.delete(save=False)
issue_attachment.delete()
issue_activity.delay(
type="attachment.activity.deleted",
requested_data=None,
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("issue_id", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=None,
epoch=int(timezone.now().timestamp()),
notification=True,
origin=request.META.get("HTTP_ORIGIN"),
)
return Response(status=status.HTTP_204_NO_CONTENT)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 68b6472 and 8c0b977.

Files selected for processing (1)
  • apiserver/plane/db/migrations/0074_alter_label_unique_together_and_more.py (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • apiserver/plane/db/migrations/0074_alter_label_unique_together_and_more.py

@sriramveeraghanta sriramveeraghanta merged commit daaa04c into preview Jul 31, 2024
13 of 14 checks passed
@sriramveeraghanta sriramveeraghanta deleted the chore/soft-delete-unique-constraints branch July 31, 2024 14:08
@coderabbitai coderabbitai bot mentioned this pull request Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants