Skip to content
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
14 changes: 13 additions & 1 deletion apiserver/plane/api/serializers/cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Module imports
from .base import BaseSerializer
from plane.db.models import Cycle, CycleIssue

from plane.utils.timezone_converter import convert_to_utc

class CycleSerializer(BaseSerializer):
total_issues = serializers.IntegerField(read_only=True)
Expand All @@ -24,6 +24,18 @@ def validate(self, data):
and data.get("start_date", None) > data.get("end_date", None)
):
raise serializers.ValidationError("Start date cannot exceed end date")

if (
data.get("start_date", None) is not None
and data.get("end_date", None) is not None
):
project_id = self.initial_data.get("project_id") or self.instance.project_id
data["start_date"] = convert_to_utc(
str(data.get("start_date").date()), project_id, is_start_date=True
)
data["end_date"] = convert_to_utc(
str(data.get("end_date", None).date()), project_id
)
Comment on lines +28 to +38
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider additional error handling for date conversion

While the validation logic is sound, consider adding error handling for the convert_to_utc calls which could raise exceptions if:

  1. Project doesn't exist
  2. Invalid timezone in project
  3. Invalid date format
 if (
     data.get("start_date", None) is not None
     and data.get("end_date", None) is not None
 ):
     project_id = self.initial_data.get("project_id") or self.instance.project_id
-    data["start_date"] = convert_to_utc(
-        str(data.get("start_date").date()), project_id, is_start_date=True
-    )
-    data["end_date"] = convert_to_utc(
-        str(data.get("end_date", None).date()), project_id
-    )
+    try:
+        data["start_date"] = convert_to_utc(
+            str(data.get("start_date").date()), project_id, is_start_date=True
+        )
+        data["end_date"] = convert_to_utc(
+            str(data.get("end_date", None).date()), project_id
+        )
+    except (Project.DoesNotExist, ValueError) as e:
+        raise serializers.ValidationError(f"Date conversion failed: {str(e)}")
📝 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 (
data.get("start_date", None) is not None
and data.get("end_date", None) is not None
):
project_id = self.initial_data.get("project_id") or self.instance.project_id
data["start_date"] = convert_to_utc(
str(data.get("start_date").date()), project_id, is_start_date=True
)
data["end_date"] = convert_to_utc(
str(data.get("end_date", None).date()), project_id
)
if (
data.get("start_date", None) is not None
and data.get("end_date", None) is not None
):
project_id = self.initial_data.get("project_id") or self.instance.project_id
try:
data["start_date"] = convert_to_utc(
str(data.get("start_date").date()), project_id, is_start_date=True
)
data["end_date"] = convert_to_utc(
str(data.get("end_date", None).date()), project_id
)
except (Project.DoesNotExist, ValueError) as e:
raise serializers.ValidationError(f"Date conversion failed: {str(e)}")

return data

class Meta:
Expand Down
4 changes: 2 additions & 2 deletions apiserver/plane/app/serializers/cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ def validate(self, data):
):
project_id = self.initial_data.get("project_id") or self.instance.project_id
data["start_date"] = convert_to_utc(
str(data.get("start_date").date()), project_id
str(data.get("start_date").date()), project_id, is_start_date=True
)
data["end_date"] = convert_to_utc(
str(data.get("end_date", None).date()), project_id, is_end_date=True
str(data.get("end_date", None).date()), project_id
)
return data

Expand Down
9 changes: 4 additions & 5 deletions apiserver/plane/app/views/cycle/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def list(self, request, slug, project_id):
"created_by",
)
datetime_fields = ["start_date", "end_date"]
data = user_timezone_converter(data, datetime_fields, project_timezone)
data = user_timezone_converter(data, datetime_fields, request.user.user_timezone)
return Response(data, status=status.HTTP_200_OK)

@allow_permission([ROLE.ADMIN, ROLE.MEMBER])
Expand Down Expand Up @@ -404,7 +404,6 @@ def partial_update(self, request, slug, project_id, pk):

@allow_permission([ROLE.ADMIN, ROLE.MEMBER])
def retrieve(self, request, slug, project_id, pk):
project = Project.objects.get(id=project_id)
queryset = self.get_queryset().filter(archived_at__isnull=True).filter(pk=pk)
data = (
self.get_queryset()
Expand Down Expand Up @@ -458,7 +457,7 @@ def retrieve(self, request, slug, project_id, pk):

queryset = queryset.first()
datetime_fields = ["start_date", "end_date"]
data = user_timezone_converter(data, datetime_fields, project.timezone)
data = user_timezone_converter(data, datetime_fields, request.user.user_timezone)

recent_visited_task.delay(
slug=slug,
Expand Down Expand Up @@ -534,8 +533,8 @@ def post(self, request, slug, project_id):
status=status.HTTP_400_BAD_REQUEST,
)

start_date = convert_to_utc(str(start_date), project_id)
end_date = convert_to_utc(str(end_date), project_id, is_end_date=True)
start_date = convert_to_utc(str(start_date), project_id, is_start_date=True)
end_date = convert_to_utc(str(end_date), project_id)

# Check if any cycle intersects in the given interval
cycles = Cycle.objects.filter(
Expand Down
2 changes: 1 addition & 1 deletion apiserver/plane/app/views/workspace/cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from plane.db.models import Cycle
from plane.app.permissions import WorkspaceViewerPermission
from plane.app.serializers.cycle import CycleSerializer

from plane.utils.timezone_converter import user_timezone_converter
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused import.

The user_timezone_converter import is not used in this file. Consider removing it until needed.

-from plane.utils.timezone_converter import user_timezone_converter
🧰 Tools
🪛 Ruff (0.8.2)

13-13: plane.utils.timezone_converter.user_timezone_converter imported but unused

Remove unused import: plane.utils.timezone_converter.user_timezone_converter

(F401)


class WorkspaceCyclesEndpoint(BaseAPIView):
permission_classes = [WorkspaceViewerPermission]
Expand Down
8 changes: 4 additions & 4 deletions apiserver/plane/utils/timezone_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def user_timezone_converter(queryset, datetime_fields, user_timezone):
return queryset_values


def convert_to_utc(date, project_id, is_end_date=False):
def convert_to_utc(date, project_id, is_start_date=False):
"""
Converts a start date string to the project's local timezone at 12:00 AM
and then converts it to UTC for storage.
Expand Down Expand Up @@ -58,9 +58,9 @@ def convert_to_utc(date, project_id, is_end_date=False):
# Localize the datetime to the project's timezone
localized_datetime = local_tz.localize(local_datetime)

# If it's an end date, subtract one minute
if is_end_date:
localized_datetime -= timedelta(minutes=1)
# If it's an start date, add one minute
if is_start_date:
localized_datetime += timedelta(minutes=1)

# Convert the localized datetime to UTC
utc_datetime = localized_datetime.astimezone(pytz.utc)
Expand Down