From defd3cf3c879c9330661f7ed80401164a920f620 Mon Sep 17 00:00:00 2001 From: sangeethailango Date: Mon, 15 Dec 2025 17:04:37 +0530 Subject: [PATCH 1/5] chore: set project timezone same as workspace timezone in project creation --- apps/api/plane/api/views/project.py | 3 +++ apps/api/plane/app/views/project/base.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/apps/api/plane/api/views/project.py b/apps/api/plane/api/views/project.py index fa735f557d7..d1a545174b9 100644 --- a/apps/api/plane/api/views/project.py +++ b/apps/api/plane/api/views/project.py @@ -210,6 +210,9 @@ def post(self, request, slug): """ try: workspace = Workspace.objects.get(slug=slug) + + request.data["timezone"] = workspace.timezone + serializer = ProjectCreateSerializer(data={**request.data}, context={"workspace_id": workspace.id}) if serializer.is_valid(): serializer.save() diff --git a/apps/api/plane/app/views/project/base.py b/apps/api/plane/app/views/project/base.py index 34e13d472d8..cbd7dc0d0b7 100644 --- a/apps/api/plane/app/views/project/base.py +++ b/apps/api/plane/app/views/project/base.py @@ -240,6 +240,8 @@ def retrieve(self, request, slug, pk): def create(self, request, slug): workspace = Workspace.objects.get(slug=slug) + request.data["timezone"] = workspace.timezone + serializer = ProjectSerializer(data={**request.data}, context={"workspace_id": workspace.id}) if serializer.is_valid(): serializer.save() From 9c3e78741a5d41095828c4200fd70a8d19b98be5 Mon Sep 17 00:00:00 2001 From: sangeethailango Date: Mon, 15 Dec 2025 17:25:00 +0530 Subject: [PATCH 2/5] chore: move the logic to serializer --- apps/api/plane/api/serializers/project.py | 14 +++++++------- apps/api/plane/api/views/project.py | 3 +-- apps/api/plane/app/serializers/project.py | 7 ++++++- apps/api/plane/app/views/project/base.py | 2 -- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/api/plane/api/serializers/project.py b/apps/api/plane/api/serializers/project.py index b22438ad513..b0d8ef875eb 100644 --- a/apps/api/plane/api/serializers/project.py +++ b/apps/api/plane/api/serializers/project.py @@ -3,13 +3,7 @@ from rest_framework import serializers # Module imports -from plane.db.models import ( - Project, - ProjectIdentifier, - WorkspaceMember, - State, - Estimate, -) +from plane.db.models import Project, ProjectIdentifier, WorkspaceMember, State, Estimate, Workspace from plane.utils.content_validator import ( validate_html_content, @@ -123,6 +117,7 @@ def validate(self, data): def create(self, validated_data): identifier = validated_data.get("identifier", "").strip().upper() + if identifier == "": raise serializers.ValidationError(detail="Project Identifier is required") @@ -139,6 +134,11 @@ def create(self, validated_data): }, } + workspace = Workspace.objects.get(id=self.context["workspace_id"]) + + if "timezone" not in validated_data: + validated_data["timezone"] = workspace.timezone + project = Project.objects.create(**validated_data, workspace_id=self.context["workspace_id"]) return project diff --git a/apps/api/plane/api/views/project.py b/apps/api/plane/api/views/project.py index d1a545174b9..fbf67905167 100644 --- a/apps/api/plane/api/views/project.py +++ b/apps/api/plane/api/views/project.py @@ -211,9 +211,8 @@ def post(self, request, slug): try: workspace = Workspace.objects.get(slug=slug) - request.data["timezone"] = workspace.timezone - serializer = ProjectCreateSerializer(data={**request.data}, context={"workspace_id": workspace.id}) + if serializer.is_valid(): serializer.save() diff --git a/apps/api/plane/app/serializers/project.py b/apps/api/plane/app/serializers/project.py index d7c458d40d1..911b8c0c3b1 100644 --- a/apps/api/plane/app/serializers/project.py +++ b/apps/api/plane/app/serializers/project.py @@ -13,7 +13,8 @@ ProjectIdentifier, DeployBoard, ProjectPublicMember, - IssueSequence + IssueSequence, + Workspace, ) from plane.utils.content_validator import ( validate_html_content, @@ -76,6 +77,10 @@ def validate(self, data): def create(self, validated_data): workspace_id = self.context["workspace_id"] + workspace = Workspace.objects.get(id=workspace_id) + + if "timezone" not in validated_data: + validated_data["timezone"] = workspace.timezone project = Project.objects.create(**validated_data, workspace_id=workspace_id) diff --git a/apps/api/plane/app/views/project/base.py b/apps/api/plane/app/views/project/base.py index cbd7dc0d0b7..34e13d472d8 100644 --- a/apps/api/plane/app/views/project/base.py +++ b/apps/api/plane/app/views/project/base.py @@ -240,8 +240,6 @@ def retrieve(self, request, slug, pk): def create(self, request, slug): workspace = Workspace.objects.get(slug=slug) - request.data["timezone"] = workspace.timezone - serializer = ProjectSerializer(data={**request.data}, context={"workspace_id": workspace.id}) if serializer.is_valid(): serializer.save() From 8d1a9f284ffb39db7cdfddfd34f68de39d074330 Mon Sep 17 00:00:00 2001 From: sangeethailango Date: Mon, 15 Dec 2025 18:33:47 +0530 Subject: [PATCH 3/5] fix: move the logic to model --- apps/api/plane/api/serializers/project.py | 5 ----- apps/api/plane/app/serializers/project.py | 4 ---- apps/api/plane/db/models/project.py | 9 +++++++++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/api/plane/api/serializers/project.py b/apps/api/plane/api/serializers/project.py index b0d8ef875eb..d44790f529f 100644 --- a/apps/api/plane/api/serializers/project.py +++ b/apps/api/plane/api/serializers/project.py @@ -134,11 +134,6 @@ def create(self, validated_data): }, } - workspace = Workspace.objects.get(id=self.context["workspace_id"]) - - if "timezone" not in validated_data: - validated_data["timezone"] = workspace.timezone - project = Project.objects.create(**validated_data, workspace_id=self.context["workspace_id"]) return project diff --git a/apps/api/plane/app/serializers/project.py b/apps/api/plane/app/serializers/project.py index 911b8c0c3b1..1b6235588cb 100644 --- a/apps/api/plane/app/serializers/project.py +++ b/apps/api/plane/app/serializers/project.py @@ -77,10 +77,6 @@ def validate(self, data): def create(self, validated_data): workspace_id = self.context["workspace_id"] - workspace = Workspace.objects.get(id=workspace_id) - - if "timezone" not in validated_data: - validated_data["timezone"] = workspace.timezone project = Project.objects.create(**validated_data, workspace_id=workspace_id) diff --git a/apps/api/plane/db/models/project.py b/apps/api/plane/db/models/project.py index 8495ac9df43..97bed3aa632 100644 --- a/apps/api/plane/db/models/project.py +++ b/apps/api/plane/db/models/project.py @@ -155,7 +155,16 @@ class Meta: ordering = ("-created_at",) def save(self, *args, **kwargs): + from plane.db.models import Workspace + self.identifier = self.identifier.strip().upper() + is_creating = self._state.adding + + if is_creating: + workspace = Workspace.objects.get(id=self.workspace_id) + + self.timezone = workspace.timezone + return super().save(*args, **kwargs) From 42f14ebdf00aed20f53726c1ab0612a9e317f225 Mon Sep 17 00:00:00 2001 From: sangeethailango Date: Mon, 15 Dec 2025 18:34:42 +0530 Subject: [PATCH 4/5] fix: unused imports --- apps/api/plane/api/serializers/project.py | 2 +- apps/api/plane/app/serializers/project.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/api/plane/api/serializers/project.py b/apps/api/plane/api/serializers/project.py index d44790f529f..c9a0a31c89b 100644 --- a/apps/api/plane/api/serializers/project.py +++ b/apps/api/plane/api/serializers/project.py @@ -3,7 +3,7 @@ from rest_framework import serializers # Module imports -from plane.db.models import Project, ProjectIdentifier, WorkspaceMember, State, Estimate, Workspace +from plane.db.models import Project, ProjectIdentifier, WorkspaceMember, State, Estimate from plane.utils.content_validator import ( validate_html_content, diff --git a/apps/api/plane/app/serializers/project.py b/apps/api/plane/app/serializers/project.py index 1b6235588cb..b8a4136c962 100644 --- a/apps/api/plane/app/serializers/project.py +++ b/apps/api/plane/app/serializers/project.py @@ -14,7 +14,6 @@ DeployBoard, ProjectPublicMember, IssueSequence, - Workspace, ) from plane.utils.content_validator import ( validate_html_content, From 7ee427c32f703bf399f1dff061a5aa49b7fe04a8 Mon Sep 17 00:00:00 2001 From: Dheeraj Kumar Ketireddy Date: Tue, 16 Dec 2025 19:47:46 +0530 Subject: [PATCH 5/5] fix: prevent overriding workspace timezone when a custom timezone is provided during project creation --- apps/api/plane/db/models/project.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/api/plane/db/models/project.py b/apps/api/plane/db/models/project.py index 97bed3aa632..173ed43854a 100644 --- a/apps/api/plane/db/models/project.py +++ b/apps/api/plane/db/models/project.py @@ -116,6 +116,11 @@ class Project(BaseModel): external_source = models.CharField(max_length=255, null=True, blank=True) external_id = models.CharField(max_length=255, blank=True, null=True) + def __init__(self, *args, **kwargs): + # Track if timezone is provided, if so, don't override it with the workspace timezone when saving + self.is_timezone_provided = kwargs.get("timezone") is not None + super().__init__(*args, **kwargs) + @property def cover_image_url(self): # Return cover image url @@ -160,9 +165,8 @@ def save(self, *args, **kwargs): self.identifier = self.identifier.strip().upper() is_creating = self._state.adding - if is_creating: + if is_creating and not self.is_timezone_provided: workspace = Workspace.objects.get(id=self.workspace_id) - self.timezone = workspace.timezone return super().save(*args, **kwargs)