Merge pull request #236 from makeplane/refactor/cycle_modules

refactor: update cycle and module create operation
This commit is contained in:
pablohashescobar 2023-02-07 01:20:13 +05:30 committed by GitHub
commit c7ad9f3da1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 266 additions and 53 deletions

View File

@ -1,5 +1,9 @@
# Python imports
import json
# Django imports # Django imports
from django.db.models import OuterRef, Func, F from django.db.models import OuterRef, Func, F
from django.core import serializers
# Third party imports # Third party imports
from rest_framework.response import Response from rest_framework.response import Response
@ -11,10 +15,10 @@ from . import BaseViewSet
from plane.api.serializers import CycleSerializer, CycleIssueSerializer from plane.api.serializers import CycleSerializer, CycleIssueSerializer
from plane.api.permissions import ProjectEntityPermission from plane.api.permissions import ProjectEntityPermission
from plane.db.models import Cycle, CycleIssue, Issue from plane.db.models import Cycle, CycleIssue, Issue
from plane.bgtasks.issue_activites_task import issue_activity
class CycleViewSet(BaseViewSet): class CycleViewSet(BaseViewSet):
serializer_class = CycleSerializer serializer_class = CycleSerializer
model = Cycle model = Cycle
permission_classes = [ permission_classes = [
@ -41,7 +45,6 @@ class CycleViewSet(BaseViewSet):
class CycleIssueViewSet(BaseViewSet): class CycleIssueViewSet(BaseViewSet):
serializer_class = CycleIssueSerializer serializer_class = CycleIssueSerializer
model = CycleIssue model = CycleIssue
@ -79,7 +82,6 @@ class CycleIssueViewSet(BaseViewSet):
def create(self, request, slug, project_id, cycle_id): def create(self, request, slug, project_id, cycle_id):
try: try:
issues = request.data.get("issues", []) issues = request.data.get("issues", [])
if not len(issues): if not len(issues):
@ -91,29 +93,77 @@ class CycleIssueViewSet(BaseViewSet):
workspace__slug=slug, project_id=project_id, pk=cycle_id workspace__slug=slug, project_id=project_id, pk=cycle_id
) )
issues = Issue.objects.filter( # Get all CycleIssues already created
pk__in=issues, workspace__slug=slug, project_id=project_id cycle_issues = list(CycleIssue.objects.filter(issue_id__in=issues))
) records_to_update = []
update_cycle_issue_activity = []
record_to_create = []
# Delete old records in order to maintain the database integrity for issue in issues:
CycleIssue.objects.filter(issue_id__in=issues).delete() cycle_issue = [
cycle_issue
for cycle_issue in cycle_issues
if str(cycle_issue.issue_id) in issues
]
# Update only when cycle changes
if len(cycle_issue):
if cycle_issue[0].cycle_id != cycle_id:
update_cycle_issue_activity.append(
{
"old_cycle_id": str(cycle_issue[0].cycle_id),
"new_cycle_id": str(cycle_id),
"issue_id": str(cycle_issue[0].issue_id),
}
)
cycle_issue[0].cycle_id = cycle_id
records_to_update.append(cycle_issue[0])
else:
record_to_create.append(
CycleIssue(
project_id=project_id,
workspace=cycle.workspace,
created_by=request.user,
updated_by=request.user,
cycle=cycle,
issue_id=issue,
)
)
CycleIssue.objects.bulk_create( CycleIssue.objects.bulk_create(
[ record_to_create,
CycleIssue(
project_id=project_id,
workspace=cycle.workspace,
created_by=request.user,
updated_by=request.user,
cycle=cycle,
issue=issue,
)
for issue in issues
],
batch_size=10, batch_size=10,
ignore_conflicts=True, ignore_conflicts=True,
) )
return Response({"message": "Success"}, status=status.HTTP_200_OK) CycleIssue.objects.bulk_update(
records_to_update,
["cycle"],
batch_size=10,
)
# Capture Issue Activity
issue_activity.delay(
{
"type": "issue.activity",
"requested_data": json.dumps({"cycles_list": issues}),
"actor_id": str(self.request.user.id),
"issue_id": str(self.kwargs.get("pk", None)),
"project_id": str(self.kwargs.get("project_id", None)),
"current_instance": json.dumps(
{
"updated_cycle_issues": update_cycle_issue_activity,
"created_cycle_issues": serializers.serialize(
"json", record_to_create
),
}
),
},
)
# Return all Cycle Issues
return Response(
CycleIssueSerializer(self.get_queryset(), many=True).data,
status=status.HTTP_200_OK,
)
except Cycle.DoesNotExist: except Cycle.DoesNotExist:
return Response( return Response(

View File

@ -1,6 +1,10 @@
# Python imports
import json
# Django Imports # Django Imports
from django.db import IntegrityError from django.db import IntegrityError
from django.db.models import Prefetch, F, OuterRef, Func from django.db.models import Prefetch, F, OuterRef, Func
from django.core import serializers
# Third party imports # Third party imports
from rest_framework.response import Response from rest_framework.response import Response
@ -22,10 +26,10 @@ from plane.db.models import (
Issue, Issue,
ModuleLink, ModuleLink,
) )
from plane.bgtasks.issue_activites_task import issue_activity
class ModuleViewSet(BaseViewSet): class ModuleViewSet(BaseViewSet):
model = Module model = Module
permission_classes = [ permission_classes = [
ProjectEntityPermission, ProjectEntityPermission,
@ -95,7 +99,6 @@ class ModuleViewSet(BaseViewSet):
class ModuleIssueViewSet(BaseViewSet): class ModuleIssueViewSet(BaseViewSet):
serializer_class = ModuleIssueSerializer serializer_class = ModuleIssueSerializer
model = ModuleIssue model = ModuleIssue
@ -148,29 +151,77 @@ class ModuleIssueViewSet(BaseViewSet):
workspace__slug=slug, project_id=project_id, pk=module_id workspace__slug=slug, project_id=project_id, pk=module_id
) )
issues = Issue.objects.filter( module_issues = list(ModuleIssue.objects.filter(issue_id__in=issues))
pk__in=issues, workspace__slug=slug, project_id=project_id
)
# Delete old records in order to maintain the database integrity update_module_issue_activity = []
ModuleIssue.objects.filter(issue_id__in=issues).delete() records_to_update = []
record_to_create = []
for issue in issues:
module_issue = [
module_issue
for module_issue in module_issues
if module_issue.issue_id in issues
]
if len(module_issue):
if module_issue[0].cycle_id != module_id:
update_module_issue_activity.append(
{
"old_module_id": str(module_issue[0].cycle_id),
"new_module_id": str(module_id),
"issue_id": str(module_issue[0].issue_id),
}
)
module_issue[0].module_id = module_id
records_to_update.append(module_issue[0])
else:
record_to_create.append(
ModuleIssue(
module=module,
issue=issue,
project_id=project_id,
workspace=module.workspace,
created_by=request.user,
updated_by=request.user,
)
)
ModuleIssue.objects.bulk_create( ModuleIssue.objects.bulk_create(
[ record_to_create,
ModuleIssue(
module=module,
issue=issue,
project_id=project_id,
workspace=module.workspace,
created_by=request.user,
updated_by=request.user,
)
for issue in issues
],
batch_size=10, batch_size=10,
ignore_conflicts=True, ignore_conflicts=True,
) )
return Response({"message": "Success"}, status=status.HTTP_200_OK)
ModuleIssue.objects.bulk_update(
records_to_update,
["module"],
batch_size=10,
)
# Capture Issue Activity
issue_activity.delay(
{
"type": "issue.activity",
"requested_data": json.dumps({"cycles_list": issues}),
"actor_id": str(self.request.user.id),
"issue_id": str(self.kwargs.get("pk", None)),
"project_id": str(self.kwargs.get("project_id", None)),
"current_instance": json.dumps(
{
"updated_cycle_issues": update_module_issue_activity,
"created_cycle_issues": serializers.serialize(
"json", record_to_create
),
}
),
},
)
return Response(
ModuleIssueSerializer(self.get_queryset(), many=True).data,
status=status.HTTP_200_OK,
)
except Module.DoesNotExist: except Module.DoesNotExist:
return Response( return Response(
{"error": "Module Does not exists"}, status=status.HTTP_400_BAD_REQUEST {"error": "Module Does not exists"}, status=status.HTTP_400_BAD_REQUEST

View File

@ -6,7 +6,16 @@ from django_rq import job
from sentry_sdk import capture_exception from sentry_sdk import capture_exception
# Module imports # Module imports
from plane.db.models import User, Issue, Project, Label, IssueActivity, State from plane.db.models import (
User,
Issue,
Project,
Label,
IssueActivity,
State,
Cycle,
Module,
)
# Track Chnages in name # Track Chnages in name
@ -44,7 +53,6 @@ def track_parent(
issue_activities, issue_activities,
): ):
if current_instance.get("parent") != requested_data.get("parent"): if current_instance.get("parent") != requested_data.get("parent"):
if requested_data.get("parent") == None: if requested_data.get("parent") == None:
old_parent = Issue.objects.get(pk=current_instance.get("parent")) old_parent = Issue.objects.get(pk=current_instance.get("parent"))
issue_activities.append( issue_activities.append(
@ -134,7 +142,6 @@ def track_state(
issue_activities, issue_activities,
): ):
if current_instance.get("state") != requested_data.get("state"): if current_instance.get("state") != requested_data.get("state"):
new_state = State.objects.get(pk=requested_data.get("state", None)) new_state = State.objects.get(pk=requested_data.get("state", None))
old_state = State.objects.get(pk=current_instance.get("state", None)) old_state = State.objects.get(pk=current_instance.get("state", None))
@ -167,7 +174,6 @@ def track_description(
if current_instance.get("description_html") != requested_data.get( if current_instance.get("description_html") != requested_data.get(
"description_html" "description_html"
): ):
issue_activities.append( issue_activities.append(
IssueActivity( IssueActivity(
issue_id=issue_id, issue_id=issue_id,
@ -274,7 +280,6 @@ def track_labels(
): ):
# Label Addition # Label Addition
if len(requested_data.get("labels_list")) > len(current_instance.get("labels")): if len(requested_data.get("labels_list")) > len(current_instance.get("labels")):
for label in requested_data.get("labels_list"): for label in requested_data.get("labels_list"):
if label not in current_instance.get("labels"): if label not in current_instance.get("labels"):
label = Label.objects.get(pk=label) label = Label.objects.get(pk=label)
@ -296,7 +301,6 @@ def track_labels(
# Label Removal # Label Removal
if len(requested_data.get("labels_list")) < len(current_instance.get("labels")): if len(requested_data.get("labels_list")) < len(current_instance.get("labels")):
for label in current_instance.get("labels"): for label in current_instance.get("labels"):
if label not in requested_data.get("labels_list"): if label not in requested_data.get("labels_list"):
label = Label.objects.get(pk=label) label = Label.objects.get(pk=label)
@ -326,12 +330,10 @@ def track_assignees(
actor, actor,
issue_activities, issue_activities,
): ):
# Assignee Addition # Assignee Addition
if len(requested_data.get("assignees_list")) > len( if len(requested_data.get("assignees_list")) > len(
current_instance.get("assignees") current_instance.get("assignees")
): ):
for assignee in requested_data.get("assignees_list"): for assignee in requested_data.get("assignees_list"):
if assignee not in current_instance.get("assignees"): if assignee not in current_instance.get("assignees"):
assignee = User.objects.get(pk=assignee) assignee = User.objects.get(pk=assignee)
@ -354,7 +356,6 @@ def track_assignees(
if len(requested_data.get("assignees_list")) < len( if len(requested_data.get("assignees_list")) < len(
current_instance.get("assignees") current_instance.get("assignees")
): ):
for assignee in current_instance.get("assignees"): for assignee in current_instance.get("assignees"):
if assignee not in requested_data.get("assignees_list"): if assignee not in requested_data.get("assignees_list"):
assignee = User.objects.get(pk=assignee) assignee = User.objects.get(pk=assignee)
@ -386,7 +387,6 @@ def track_blocks(
if len(requested_data.get("blocks_list")) > len( if len(requested_data.get("blocks_list")) > len(
current_instance.get("blocked_issues") current_instance.get("blocked_issues")
): ):
for block in requested_data.get("blocks_list"): for block in requested_data.get("blocks_list"):
if ( if (
len( len(
@ -418,7 +418,6 @@ def track_blocks(
if len(requested_data.get("blocks_list")) < len( if len(requested_data.get("blocks_list")) < len(
current_instance.get("blocked_issues") current_instance.get("blocked_issues")
): ):
for blocked in current_instance.get("blocked_issues"): for blocked in current_instance.get("blocked_issues"):
if blocked.get("block") not in requested_data.get("blocks_list"): if blocked.get("block") not in requested_data.get("blocks_list"):
issue = Issue.objects.get(pk=blocked.get("block")) issue = Issue.objects.get(pk=blocked.get("block"))
@ -450,7 +449,6 @@ def track_blockings(
if len(requested_data.get("blockers_list")) > len( if len(requested_data.get("blockers_list")) > len(
current_instance.get("blocker_issues") current_instance.get("blocker_issues")
): ):
for block in requested_data.get("blockers_list"): for block in requested_data.get("blockers_list"):
if ( if (
len( len(
@ -482,7 +480,6 @@ def track_blockings(
if len(requested_data.get("blockers_list")) < len( if len(requested_data.get("blockers_list")) < len(
current_instance.get("blocker_issues") current_instance.get("blocker_issues")
): ):
for blocked in current_instance.get("blocker_issues"): for blocked in current_instance.get("blocker_issues"):
if blocked.get("blocked_by") not in requested_data.get("blockers_list"): if blocked.get("blocked_by") not in requested_data.get("blockers_list"):
issue = Issue.objects.get(pk=blocked.get("blocked_by")) issue = Issue.objects.get(pk=blocked.get("blocked_by"))
@ -502,6 +499,119 @@ def track_blockings(
) )
def track_cycles(
requested_data,
current_instance,
issue_id,
project,
actor,
issue_activities,
):
# Updated Records:
updated_records = current_instance.get("updated_cycle_issues", [])
created_records = json.loads(current_instance.get("created_cycle_issues", []))
for updated_record in updated_records:
old_cycle = Cycle.objects.filter(
pk=updated_record.get("old_cycle_id", None)
).first()
new_cycle = Cycle.objects.filter(
pk=updated_record.get("new_cycle_id", None)
).first()
issue_activities.append(
IssueActivity(
issue_id=updated_record.get("issue_id"),
actor=actor,
verb="updated",
old_value=old_cycle.name,
new_value=new_cycle.name,
field="cycles",
project=project,
workspace=project.workspace,
comment=f"{actor.email} updated cycle from {old_cycle.name} to {new_cycle.name}",
old_identifier=old_cycle.id,
new_identifier=new_cycle.id,
)
)
for created_record in created_records:
cycle = Cycle.objects.filter(
pk=created_record.get("fields").get("cycle")
).first()
issue_activities.append(
IssueActivity(
issue_id=created_record.get("fields").get("issue"),
actor=actor,
verb="created",
old_value="",
new_value=cycle.name,
field="cycles",
project=project,
workspace=project.workspace,
comment=f"{actor.email} added cycle {cycle.name}",
new_identifier=cycle.id,
)
)
def track_modules(
requested_data,
current_instance,
issue_id,
project,
actor,
issue_activities,
):
# Updated Records:
updated_records = current_instance.get("updated_module_issues", [])
created_records = json.loads(current_instance.get("created_module_issues", []))
for updated_record in updated_records:
old_module = Module.objects.filter(
pk=updated_record.get("old_module_id", None)
).first()
new_module = Module.objects.filter(
pk=updated_record.get("new_module_id", None)
).first()
issue_activities.append(
IssueActivity(
issue_id=updated_record.get("issue_id"),
actor=actor,
verb="updated",
old_value=old_module.name,
new_value=new_module.name,
field="modules",
project=project,
workspace=project.workspace,
comment=f"{actor.email} updated module from {old_module.name} to {new_module.name}",
old_identifier=old_module.id,
new_identifier=new_module.id,
)
)
for created_record in created_records:
module = Module.objects.filter(
pk=created_record.get("fields").get("module")
).first()
issue_activities.append(
IssueActivity(
issue_id=created_record.get("fields").get("issue"),
actor=actor,
verb="created",
old_value="",
new_value=module.name,
field="modules",
project=project,
workspace=project.workspace,
comment=f"{actor.email} added module {module.name}",
new_identifier=module.id,
)
)
# Receive message from room group # Receive message from room group
@job("default") @job("default")
def issue_activity(event): def issue_activity(event):
@ -510,7 +620,7 @@ def issue_activity(event):
requested_data = json.loads(event.get("requested_data")) requested_data = json.loads(event.get("requested_data"))
current_instance = json.loads(event.get("current_instance")) current_instance = json.loads(event.get("current_instance"))
issue_id = event.get("issue_id") issue_id = event.get("issue_id", None)
actor_id = event.get("actor_id") actor_id = event.get("actor_id")
project_id = event.get("project_id") project_id = event.get("project_id")
@ -530,6 +640,8 @@ def issue_activity(event):
"assignees_list": track_assignees, "assignees_list": track_assignees,
"blocks_list": track_blocks, "blocks_list": track_blocks,
"blockers_list": track_blockings, "blockers_list": track_blockings,
"cycles_list": track_cycles,
"modules_list": track_modules,
} }
for key in requested_data: for key in requested_data: