diff --git a/apiserver/.env.example b/apiserver/.env.example index 38944f79c7..7af2f00569 100644 --- a/apiserver/.env.example +++ b/apiserver/.env.example @@ -50,3 +50,6 @@ GUNICORN_WORKERS=2 ADMIN_BASE_URL= SPACE_BASE_URL= APP_BASE_URL= + +# Hard delete files after days +HARD_DELETE_AFTER_DAYS= \ No newline at end of file diff --git a/apiserver/plane/app/views/cycle/archive.py b/apiserver/plane/app/views/cycle/archive.py index dc5f6a5730..947f43a5f8 100644 --- a/apiserver/plane/app/views/cycle/archive.py +++ b/apiserver/plane/app/views/cycle/archive.py @@ -14,21 +14,18 @@ from django.db.models import ( UUIDField, Value, When, + Subquery, + Sum, + FloatField, ) -from django.db.models.functions import Coalesce +from django.db.models.functions import Coalesce, Cast from django.utils import timezone # Third party imports from rest_framework import status from rest_framework.response import Response from plane.app.permissions import ProjectEntityPermission -from plane.db.models import ( - Cycle, - UserFavorite, - Issue, - Label, - User, -) +from plane.db.models import Cycle, UserFavorite, Issue, Label, User, Project from plane.utils.analytics_plot import burndown_plot # Module imports @@ -49,6 +46,89 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): project_id=self.kwargs.get("project_id"), workspace__slug=self.kwargs.get("slug"), ) + backlog_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="backlog", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate( + backlog_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("backlog_estimate_point")[:1] + ) + unstarted_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="unstarted", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate( + unstarted_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("unstarted_estimate_point")[:1] + ) + started_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="started", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate( + started_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("started_estimate_point")[:1] + ) + cancelled_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="cancelled", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate( + cancelled_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("cancelled_estimate_point")[:1] + ) + completed_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="completed", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate( + completed_estimate_points=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("completed_estimate_points")[:1] + ) + total_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + issue_cycle__cycle_id=OuterRef("pk"), + ) + .values("issue_cycle__cycle_id") + .annotate( + total_estimate_points=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("total_estimate_points")[:1] + ) return ( Cycle.objects.filter(workspace__slug=self.kwargs.get("slug")) .filter(project_id=self.kwargs.get("project_id")) @@ -172,6 +252,42 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): Value([], output_field=ArrayField(UUIDField())), ) ) + .annotate( + backlog_estimate_points=Coalesce( + Subquery(backlog_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + unstarted_estimate_points=Coalesce( + Subquery(unstarted_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + started_estimate_points=Coalesce( + Subquery(started_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + cancelled_estimate_points=Coalesce( + Subquery(cancelled_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + completed_estimate_points=Coalesce( + Subquery(completed_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + total_estimate_points=Coalesce( + Subquery(total_estimate_point), + Value(0, output_field=FloatField()), + ), + ) .order_by("-is_favorite", "name") .distinct() ) @@ -179,17 +295,7 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): def get(self, request, slug, project_id, pk=None): if pk is None: queryset = ( - self.get_queryset() - .annotate( - total_issues=Count( - "issue_cycle", - filter=Q( - issue_cycle__issue__archived_at__isnull=True, - issue_cycle__issue__is_draft=False, - ), - ) - ) - .values( + self.get_queryset().values( # necessary fields "id", "workspace_id", @@ -255,7 +361,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): "external_id", "progress_snapshot", "sub_issues", + "logo_props", # meta fields + "completed_estimate_points", + "total_estimate_points", "is_favorite", "total_issues", "cancelled_issues", @@ -265,17 +374,114 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): "backlog_issues", "assignee_ids", "status", + "created_by", + "archived_at", ) .first() ) queryset = queryset.first() - if data is None: - return Response( - {"error": "Cycle does not exist"}, - status=status.HTTP_400_BAD_REQUEST, + estimate_type = Project.objects.filter( + workspace__slug=slug, + pk=project_id, + estimate__isnull=False, + estimate__type="points", + ).exists() + + data["estimate_distribution"] = {} + if estimate_type: + assignee_distribution = ( + Issue.issue_objects.filter( + issue_cycle__cycle_id=pk, + workspace__slug=slug, + project_id=project_id, + ) + .annotate(display_name=F("assignees__display_name")) + .annotate(assignee_id=F("assignees__id")) + .annotate(avatar=F("assignees__avatar")) + .values("display_name", "assignee_id", "avatar") + .annotate( + total_estimates=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .annotate( + completed_estimates=Sum( + Cast("estimate_point__value", FloatField()), + filter=Q( + completed_at__isnull=False, + archived_at__isnull=True, + is_draft=False, + ), + ) + ) + .annotate( + pending_estimates=Sum( + Cast("estimate_point__value", FloatField()), + filter=Q( + completed_at__isnull=True, + archived_at__isnull=True, + is_draft=False, + ), + ) + ) + .order_by("display_name") ) + label_distribution = ( + Issue.issue_objects.filter( + issue_cycle__cycle_id=pk, + workspace__slug=slug, + project_id=project_id, + ) + .annotate(label_name=F("labels__name")) + .annotate(color=F("labels__color")) + .annotate(label_id=F("labels__id")) + .values("label_name", "color", "label_id") + .annotate( + total_estimates=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .annotate( + completed_estimates=Sum( + Cast("estimate_point__value", FloatField()), + filter=Q( + completed_at__isnull=False, + archived_at__isnull=True, + is_draft=False, + ), + ) + ) + .annotate( + pending_estimates=Sum( + Cast("estimate_point__value", FloatField()), + filter=Q( + completed_at__isnull=True, + archived_at__isnull=True, + is_draft=False, + ), + ) + ) + .order_by("label_name") + ) + data["estimate_distribution"] = { + "assignees": assignee_distribution, + "labels": label_distribution, + "completion_chart": {}, + } + + if data["start_date"] and data["end_date"]: + data["estimate_distribution"]["completion_chart"] = ( + burndown_plot( + queryset=queryset, + slug=slug, + project_id=project_id, + plot_type="points", + cycle_id=pk, + ) + ) + # Assignee Distribution assignee_distribution = ( Issue.issue_objects.filter( @@ -298,7 +504,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): .annotate( total_issues=Count( "id", - filter=Q(archived_at__isnull=True, is_draft=False), + filter=Q( + archived_at__isnull=True, + is_draft=False, + ), ), ) .annotate( @@ -338,7 +547,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView): .annotate( total_issues=Count( "id", - filter=Q(archived_at__isnull=True, is_draft=False), + filter=Q( + archived_at__isnull=True, + is_draft=False, + ), ), ) .annotate( diff --git a/apiserver/plane/app/views/cycle/base.py b/apiserver/plane/app/views/cycle/base.py index 5d9316d444..33231c282f 100644 --- a/apiserver/plane/app/views/cycle/base.py +++ b/apiserver/plane/app/views/cycle/base.py @@ -386,7 +386,7 @@ class CycleViewSet(BaseViewSet): data[0]["estimate_distribution"] = {} if estimate_type: assignee_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=data[0]["id"], workspace__slug=slug, project_id=project_id, @@ -424,7 +424,7 @@ class CycleViewSet(BaseViewSet): ) label_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=data[0]["id"], workspace__slug=slug, project_id=project_id, @@ -478,7 +478,7 @@ class CycleViewSet(BaseViewSet): ) assignee_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=data[0]["id"], workspace__slug=slug, project_id=project_id, @@ -520,7 +520,7 @@ class CycleViewSet(BaseViewSet): ) label_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=data[0]["id"], workspace__slug=slug, project_id=project_id, @@ -835,7 +835,7 @@ class CycleViewSet(BaseViewSet): data["estimate_distribution"] = {} if estimate_type: assignee_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=pk, workspace__slug=slug, project_id=project_id, @@ -873,7 +873,7 @@ class CycleViewSet(BaseViewSet): ) label_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=pk, workspace__slug=slug, project_id=project_id, @@ -928,7 +928,7 @@ class CycleViewSet(BaseViewSet): # Assignee Distribution assignee_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=pk, workspace__slug=slug, project_id=project_id, @@ -979,7 +979,7 @@ class CycleViewSet(BaseViewSet): # Label Distribution label_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_cycle__cycle_id=pk, workspace__slug=slug, project_id=project_id, diff --git a/apiserver/plane/app/views/issue/archive.py b/apiserver/plane/app/views/issue/archive.py index 82b5be6591..9be4cf79b3 100644 --- a/apiserver/plane/app/views/issue/archive.py +++ b/apiserver/plane/app/views/issue/archive.py @@ -66,6 +66,7 @@ class IssueArchiveViewSet(BaseViewSet): .annotate(count=Func(F("id"), function="Count")) .values("count") ) + .filter(deleted_at__isnull=True) .filter(archived_at__isnull=False) .filter(project_id=self.kwargs.get("project_id")) .filter(workspace__slug=self.kwargs.get("slug")) diff --git a/apiserver/plane/app/views/issue/draft.py b/apiserver/plane/app/views/issue/draft.py index 3526e03a83..c5899d9725 100644 --- a/apiserver/plane/app/views/issue/draft.py +++ b/apiserver/plane/app/views/issue/draft.py @@ -68,6 +68,7 @@ class IssueDraftViewSet(BaseViewSet): Issue.objects.filter(project_id=self.kwargs.get("project_id")) .filter(workspace__slug=self.kwargs.get("slug")) .filter(is_draft=True) + .filter(deleted_at__isnull=True) .select_related("workspace", "project", "state", "parent") .prefetch_related("assignees", "labels", "issue_module__module") .annotate(cycle_id=F("issue_cycle__cycle_id")) diff --git a/apiserver/plane/app/views/module/archive.py b/apiserver/plane/app/views/module/archive.py index 8f6d9c6b0e..243c680cad 100644 --- a/apiserver/plane/app/views/module/archive.py +++ b/apiserver/plane/app/views/module/archive.py @@ -12,7 +12,8 @@ from django.db.models import ( Subquery, UUIDField, Value, - Sum + Sum, + FloatField, ) from django.db.models.functions import Coalesce, Cast from django.utils import timezone @@ -44,8 +45,8 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): def get_queryset(self): favorite_subquery = UserFavorite.objects.filter( user=self.request.user, - entity_identifier=OuterRef("pk"), entity_type="module", + entity_identifier=OuterRef("pk"), project_id=self.kwargs.get("project_id"), workspace__slug=self.kwargs.get("slug"), ) @@ -102,8 +103,93 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): .annotate(cnt=Count("pk")) .values("cnt") ) + completed_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="completed", + issue_module__module_id=OuterRef("pk"), + ) + .values("issue_module__module_id") + .annotate( + completed_estimate_points=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("completed_estimate_points")[:1] + ) + + total_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + issue_module__module_id=OuterRef("pk"), + ) + .values("issue_module__module_id") + .annotate( + total_estimate_points=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("total_estimate_points")[:1] + ) + backlog_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="backlog", + issue_module__module_id=OuterRef("pk"), + ) + .values("issue_module__module_id") + .annotate( + backlog_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("backlog_estimate_point")[:1] + ) + unstarted_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="unstarted", + issue_module__module_id=OuterRef("pk"), + ) + .values("issue_module__module_id") + .annotate( + unstarted_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("unstarted_estimate_point")[:1] + ) + started_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="started", + issue_module__module_id=OuterRef("pk"), + ) + .values("issue_module__module_id") + .annotate( + started_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("started_estimate_point")[:1] + ) + cancelled_estimate_point = ( + Issue.issue_objects.filter( + estimate_point__estimate__type="points", + state__group="cancelled", + issue_module__module_id=OuterRef("pk"), + ) + .values("issue_module__module_id") + .annotate( + cancelled_estimate_point=Sum( + Cast("estimate_point__value", FloatField()) + ) + ) + .values("cancelled_estimate_point")[:1] + ) return ( Module.objects.filter(workspace__slug=self.kwargs.get("slug")) + .filter(project_id=self.kwargs.get("project_id")) .filter(archived_at__isnull=False) .annotate(is_favorite=Exists(favorite_subquery)) .select_related("workspace", "project", "lead") @@ -152,6 +238,42 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): Value(0, output_field=IntegerField()), ) ) + .annotate( + backlog_estimate_points=Coalesce( + Subquery(backlog_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + unstarted_estimate_points=Coalesce( + Subquery(unstarted_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + started_estimate_points=Coalesce( + Subquery(started_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + cancelled_estimate_points=Coalesce( + Subquery(cancelled_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + completed_estimate_points=Coalesce( + Subquery(completed_estimate_point), + Value(0, output_field=FloatField()), + ), + ) + .annotate( + total_estimate_points=Coalesce( + Subquery(total_estimate_point), + Value(0, output_field=FloatField()), + ), + ) .annotate( member_ids=Coalesce( ArrayAgg( @@ -232,7 +354,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): data["estimate_distribution"] = {} if estimate_type: - label_distribution = ( + assignee_distribution = ( Issue.issue_objects.filter( issue_module__module_id=pk, workspace__slug=slug, @@ -252,12 +374,12 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): ) .annotate( total_estimates=Sum( - Cast("estimate_point__value", IntegerField()) + Cast("estimate_point__value", FloatField()) ), ) .annotate( completed_estimates=Sum( - Cast("estimate_point__value", IntegerField()), + Cast("estimate_point__value", FloatField()), filter=Q( completed_at__isnull=False, archived_at__isnull=True, @@ -267,7 +389,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): ) .annotate( pending_estimates=Sum( - Cast("estimate_point__value", IntegerField()), + Cast("estimate_point__value", FloatField()), filter=Q( completed_at__isnull=True, archived_at__isnull=True, @@ -278,7 +400,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): .order_by("first_name", "last_name") ) - assignee_distribution = ( + label_distribution = ( Issue.issue_objects.filter( issue_module__module_id=pk, workspace__slug=slug, @@ -290,12 +412,12 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): .values("label_name", "color", "label_id") .annotate( total_estimates=Sum( - Cast("estimate_point__value", IntegerField()) + Cast("estimate_point__value", FloatField()) ), ) .annotate( completed_estimates=Sum( - Cast("estimate_point__value", IntegerField()), + Cast("estimate_point__value", FloatField()), filter=Q( completed_at__isnull=False, archived_at__isnull=True, @@ -305,7 +427,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): ) .annotate( pending_estimates=Sum( - Cast("estimate_point__value", IntegerField()), + Cast("estimate_point__value", FloatField()), filter=Q( completed_at__isnull=True, archived_at__isnull=True, @@ -315,8 +437,8 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): ) .order_by("label_name") ) - data["estimate_distribution"]["assignee"] = assignee_distribution - data["estimate_distribution"]["label"] = label_distribution + data["estimate_distribution"]["assignees"] = assignee_distribution + data["estimate_distribution"]["labels"] = label_distribution if modules and modules.start_date and modules.target_date: data["estimate_distribution"]["completion_chart"] = ( @@ -328,6 +450,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): module_id=pk, ) ) + assignee_distribution = ( Issue.issue_objects.filter( issue_module__module_id=pk, @@ -353,7 +476,7 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): archived_at__isnull=True, is_draft=False, ), - ) + ), ) .annotate( completed_issues=Count( @@ -425,8 +548,6 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView): "labels": label_distribution, "completion_chart": {}, } - - # Fetch the modules if modules and modules.start_date and modules.target_date: data["distribution"]["completion_chart"] = burndown_plot( queryset=modules, diff --git a/apiserver/plane/app/views/module/base.py b/apiserver/plane/app/views/module/base.py index a0402823bc..94a930bee9 100644 --- a/apiserver/plane/app/views/module/base.py +++ b/apiserver/plane/app/views/module/base.py @@ -555,7 +555,7 @@ class ModuleViewSet(BaseViewSet): ) assignee_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_module__module_id=pk, workspace__slug=slug, project_id=project_id, @@ -605,7 +605,7 @@ class ModuleViewSet(BaseViewSet): ) label_distribution = ( - Issue.objects.filter( + Issue.issue_objects.filter( issue_module__module_id=pk, workspace__slug=slug, project_id=project_id, diff --git a/apiserver/plane/bgtasks/deletion_task.py b/apiserver/plane/bgtasks/deletion_task.py index 6b155934e9..d8272591a9 100644 --- a/apiserver/plane/bgtasks/deletion_task.py +++ b/apiserver/plane/bgtasks/deletion_task.py @@ -1,6 +1,7 @@ # Django imports from django.utils import timezone from django.apps import apps +from django.conf import settings from django.core.exceptions import ObjectDoesNotExist # Third party imports @@ -15,9 +16,9 @@ def soft_delete_related_objects( instance = model_class.all_objects.get(pk=instance_pk) related_fields = instance._meta.get_fields() for field in related_fields: - if field.one_to_many or field.one_to_one or field.many_to_many: + if field.one_to_many or field.one_to_one: try: - if field.one_to_many or field.many_to_many: + if field.one_to_many: related_objects = getattr(instance, field.name).all() elif field.one_to_one: related_object = getattr(instance, field.name) @@ -58,88 +59,89 @@ def hard_delete(): ModuleIssue, CycleIssue, Estimate, - EstimatePoint + EstimatePoint, ) + days = settings.HARD_DELETE_AFTER_DAYS # check delete workspace _ = Workspace.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete project _ = Project.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete cycle _ = Cycle.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete module _ = Module.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete issue _ = Issue.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete page _ = Page.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete view _ = IssueView.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete label _ = Label.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # check delete state _ = State.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = IssueActivity.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = IssueComment.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = IssueLink.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = IssueReaction.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = UserFavorite.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = ModuleIssue.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = CycleIssue.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = Estimate.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() _ = EstimatePoint.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() - timezone.timedelta(days=days) ).delete() # at last, check for every thing which ever is left and delete it @@ -152,7 +154,8 @@ def hard_delete(): if hasattr(model, "deleted_at"): # Get all instances where 'deleted_at' is greater than 30 days ago _ = model.all_objects.filter( - deleted_at__lt=timezone.now() - timezone.timedelta(days=30) + deleted_at__lt=timezone.now() + - timezone.timedelta(days=days) ).delete() return diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index a2eb129ad0..896776f62f 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -364,6 +364,8 @@ ADMIN_BASE_URL = os.environ.get("ADMIN_BASE_URL", None) SPACE_BASE_URL = os.environ.get("SPACE_BASE_URL", None) APP_BASE_URL = os.environ.get("APP_BASE_URL") +HARD_DELETE_AFTER_DAYS = int(os.environ.get("HARD_DELETE_AFTER_DAYS", 60)) + # Prime Server Base url PRIME_SERVER_BASE_URL = os.environ.get("PRIME_SERVER_BASE_URL", False) PRIME_SERVER_AUTH_TOKEN = os.environ.get("PRIME_SERVER_AUTH_TOKEN", "") diff --git a/space/core/components/issues/issue-layouts/kanban/block-reactions.tsx b/space/core/components/issues/issue-layouts/kanban/block-reactions.tsx new file mode 100644 index 0000000000..241a087e78 --- /dev/null +++ b/space/core/components/issues/issue-layouts/kanban/block-reactions.tsx @@ -0,0 +1,45 @@ +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +//plane +import { cn } from "@plane/editor"; +// components +import { IssueEmojiReactions, IssueVotes } from "@/components/issues/reactions"; +// hooks +import { usePublish } from "@/hooks/store"; + +type Props = { + issueId: string; +}; +export const BlockReactions = observer((props: Props) => { + const { issueId } = props; + const { anchor } = useParams(); + const { canVote, canReact } = usePublish(anchor.toString()); + + // if the user cannot vote or react then return empty + if (!canVote && !canReact) return <>>; + + return ( +