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-2693] chore: removed the deleted cycles from the issue list #5868

Merged
merged 3 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion apiserver/plane/api/views/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,15 @@ def get(self, request, slug, project_id, pk=None):

issue_queryset = (
self.get_queryset()
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
Q(issue_cycle__cycle__deleted_at__isnull=True),
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
12 changes: 10 additions & 2 deletions apiserver/plane/app/views/cycle/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Django imports
from django.core import serializers
from django.db.models import F, Func, OuterRef, Q
from django.db.models import F, Func, OuterRef, Q, Case, When
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
Expand Down Expand Up @@ -102,7 +102,15 @@ def list(self, request, slug, project_id, cycle_id):
"issue_cycle__cycle",
)
.filter(**filters)
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
12 changes: 10 additions & 2 deletions apiserver/plane/app/views/inbox/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Django import
from django.utils import timezone
from django.db.models import Q, Count, OuterRef, Func, F, Prefetch
from django.db.models import Q, Count, OuterRef, Func, F, Prefetch, Case, When
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib.postgres.aggregates import ArrayAgg
from django.contrib.postgres.fields import ArrayField
Expand Down Expand Up @@ -112,7 +112,15 @@ def get_queryset(self):
),
)
)
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
19 changes: 10 additions & 9 deletions apiserver/plane/app/views/issue/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,7 @@

# Django imports
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import (
F,
Func,
OuterRef,
Q,
Prefetch,
Exists,
)
from django.db.models import F, Func, OuterRef, Q, Prefetch, Exists, Case, When
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
Expand Down Expand Up @@ -71,7 +64,15 @@ def get_queryset(self):
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
Comment on lines +67 to +75
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

Issues Found with cycle_id Handling.

The recent change allowing cycle_id to be None has introduced potential issues in both serializers and query filters. The following areas need attention to ensure proper handling of None values for cycle_id:

  • Serializers:

    • apiserver/plane/app/serializers/draft.py:
      cycle_id = serializers.PrimaryKeyRelatedField(read_only=True)
    • apiserver/plane/app/serializers/issue.py:
      cycle_id = serializers.PrimaryKeyRelatedField(read_only=True)

    Action: Add allow_null=True to the cycle_id fields to permit None values.

  • Query Filters:

    • apiserver/plane/bgtasks/issue_activities_task.py:
      cycle = Cycle.objects.filter(pk=cycle_id).first()
    • apiserver/plane/api/views/cycle.py:
      .filter(cycle_id=self.kwargs.get("cycle_id"))
      Issue.issue_objects.filter(issue_cycle__cycle_id=cycle_id)
    • apiserver/plane/app/views/cycle/issue.py:
      .filter(cycle_id=self.kwargs.get("cycle_id"))
      Issue.issue_objects.filter(issue_cycle__cycle_id=cycle_id)

    Action: Update these query filters to handle cases where cycle_id is None. For example, include checks like cycle_id__isnull=True where appropriate.

Please address these issues to ensure that the application correctly handles scenarios where cycle_id can be None, thereby maintaining data consistency and preventing potential runtime errors.

🔗 Analysis chain

Verify the impact of the cycle_id annotation change.

While the change in the cycle_id annotation improves data consistency, it's important to ensure that this modification doesn't unintentionally affect other parts of the codebase that might rely on the cycle_id field, especially for deleted cycles.

Please run the following script to identify any potential issues:

This script will help identify areas of the codebase that might need attention due to the cycle_id annotation change. Please review the results and update any affected code as necessary.


Further verification needed for cycle_id null handling.

To ensure that the recent change allowing cycle_id to be None does not introduce issues, please run the following scripts to verify that serializers and query filters handle cycle_id appropriately.

This script performs the following checks:

  1. Serializers Null Handling:

    • Searches for cycle_id fields in serializers.
    • Ensures that allow_null=True is set, indicating that the field can accept None values.
  2. Query Filters Null Handling:

    • Looks for query filters that involve cycle_id.
    • Checks whether these filters include conditions to handle None values, such as cycle_id__isnull=True.
  3. Direct Access Checks (Optional):

    • Identifies places where cycle_id is accessed directly.
    • Ensures that there are checks in place to handle scenarios where cycle_id might be None.

Please review the results of these scripts and update the serializers or query conditions as necessary to handle cycle_id being None.

```markdown
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usages of cycle_id that might be affected by the new annotation logic

# Search for cycle_id usages in Python files
echo "Searching for cycle_id usages:"
rg "cycle_id" --type py -g "!*/migrations/*"

# Search for potential filter conditions on cycle_id that might need updating
echo "\nSearching for potential cycle_id filters:"
rg "filter\(.*cycle_id" --type py -g "!*/migrations/*"

# Search for serializers that include cycle_id to ensure they handle None values
echo "\nSearching for serializers including cycle_id:"
rg "class.*Serializer" -A 10 -g "!*/migrations/*" | rg "cycle_id"

Length of output: 21795


Script:

#!/bin/bash
# Description: Verify serializers allow null values for cycle_id and query filters handle None appropriately

# Check serializers for cycle_id fields allowing nulls
echo "Checking serializers for cycle_id fields allowing null values:"
rg 'cycle_id\s*=\s*serializers\.PrimaryKeyRelatedField' --type py -g "!*/migrations/*" | grep -v 'allow_null=True'

# Check query filters using cycle_id without handling None
echo "\nChecking query filters for cycle_id without handling nulls:"
rg '\.filter\([^)]*cycle_id[^)]*\)' --type py -g "!*/migrations/*" | grep -v 'cycle_id__isnull'

# Optionally, check for direct accesses to cycle_id that might not account for None
echo "\nChecking for direct cycle_id accesses without None checks:"
rg 'cycle_id' --type py -g "!*/migrations/*" | grep -E 'if\s+cycle_id\s+|cycle_id\s*='

Length of output: 10160

.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
32 changes: 29 additions & 3 deletions apiserver/plane/app/views/issue/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
Q,
UUIDField,
Value,
When,
Case,
)
from django.db.models.functions import Coalesce
from django.utils import timezone
Expand Down Expand Up @@ -83,7 +85,15 @@ def get(self, request, slug, project_id):
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down Expand Up @@ -207,7 +217,15 @@ def get_queryset(self):
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down Expand Up @@ -757,7 +775,15 @@ def get_queryset(self):
"workspace", "project", "state", "parent"
)
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
22 changes: 20 additions & 2 deletions apiserver/plane/app/views/issue/relation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@

# Django imports
from django.utils import timezone
from django.db.models import Q, OuterRef, F, Func, UUIDField, Value, CharField
from django.db.models import (
Q,
OuterRef,
F,
Func,
UUIDField,
Value,
CharField,
Case,
When,
)
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models.functions import Coalesce
from django.contrib.postgres.aggregates import ArrayAgg
Expand Down Expand Up @@ -83,7 +93,15 @@ def list(self, request, slug, project_id, issue_id):
Issue.issue_objects.filter(workspace__slug=slug)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
12 changes: 11 additions & 1 deletion apiserver/plane/app/views/issue/sub_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
Q,
Value,
UUIDField,
Case,
When,
)
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
Expand Down Expand Up @@ -48,7 +50,15 @@ def get(self, request, slug, project_id, issue_id):
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
12 changes: 11 additions & 1 deletion apiserver/plane/app/views/module/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
Func,
OuterRef,
Q,
Case,
When,
)

# Django Imports
Expand Down Expand Up @@ -65,7 +67,15 @@ def get_queryset(self):
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
22 changes: 20 additions & 2 deletions apiserver/plane/app/views/view/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
Q,
UUIDField,
Value,
Case,
When,
)
from django.db.models.functions import Coalesce
from django.utils.decorators import method_decorator
Expand Down Expand Up @@ -205,7 +207,15 @@ def get_queryset(self):
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down Expand Up @@ -275,7 +285,15 @@ def list(self, request, slug):
issue_queryset = (
self.get_queryset()
.filter(**filters)
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
)

# check for the project member role, if the role is 5 then check for the guest_view_all_features if it is true then show all the issues else show only the issues created by the user
Expand Down
19 changes: 17 additions & 2 deletions apiserver/plane/app/views/workspace/draft.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
Q,
UUIDField,
Value,
Case,
When,
)
from django.db.models.functions import Coalesce
from django.utils.decorators import method_decorator
Expand Down Expand Up @@ -55,6 +57,15 @@ def get_queryset(self):
"assignees", "labels", "draft_issue_module__module"
)
.annotate(cycle_id=F("draft_issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
label_ids=Coalesce(
ArrayAgg(
Expand All @@ -81,8 +92,12 @@ def get_queryset(self):
"draft_issue_module__module_id",
distinct=True,
filter=~Q(draft_issue_module__module_id__isnull=True)
& Q(draft_issue_module__module__archived_at__isnull=True)
& Q(draft_issue_module__module__deleted_at__isnull=True),
& Q(
draft_issue_module__module__archived_at__isnull=True
)
& Q(
draft_issue_module__module__deleted_at__isnull=True
),
),
Value([], output_field=ArrayField(UUIDField())),
),
Expand Down
10 changes: 9 additions & 1 deletion apiserver/plane/app/views/workspace/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,15 @@ def get(self, request, slug, user_id):
.filter(**filters)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down
20 changes: 18 additions & 2 deletions apiserver/plane/space/views/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,15 @@ def get(self, request, anchor):
queryset=IssueVote.objects.select_related("actor"),
)
)
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
Expand Down Expand Up @@ -695,7 +703,15 @@ def get(self, request, anchor, issue_id):
)
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels", "issue_module__module")
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(
cycle_id=Case(
When(
issue_cycle__cycle__deleted_at__isnull=True,
then=F("issue_cycle__cycle_id"),
),
default=None,
)
)
.annotate(
label_ids=Coalesce(
ArrayAgg(
Expand Down
Loading