Merge pull request #2121 from makeplane/sync/ce-ee

Sync: Community Changes
This commit is contained in:
pushya22
2025-01-06 19:01:27 +05:30
committed by GitHub
6 changed files with 148 additions and 32 deletions

View File

@@ -21,6 +21,7 @@ from .workspace import (
WorkspaceUserPropertiesSerializer,
WorkspaceUserLinkSerializer,
WorkspaceRecentVisitSerializer,
WorkspaceHomePreferenceSerializer,
WorkspaceUserMeSerializer,
)
from .project import (

View File

@@ -16,10 +16,11 @@ from plane.db.models import (
WorkspaceUserProperties,
WorkspaceUserLink,
UserRecentVisit,
Issue,
Page,
Issue,
Page,
Project,
ProjectMember
ProjectMember,
WorkspaceHomePreference,
)
from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS
@@ -27,6 +28,7 @@ from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
class WorkSpaceSerializer(DynamicBaseSerializer):
owner = UserLiteSerializer(read_only=True)
total_members = serializers.IntegerField(read_only=True)
@@ -141,6 +143,7 @@ class WorkspaceUserPropertiesSerializer(BaseSerializer):
fields = "__all__"
read_only_fields = ["workspace", "user"]
class WorkspaceUserLinkSerializer(BaseSerializer):
class Meta:
model = WorkspaceUserLink
@@ -151,7 +154,7 @@ class WorkspaceUserLinkSerializer(BaseSerializer):
url = data.get("url", "")
if url and not url.startswith(("http://", "https://")):
data["url"] = "http://" + url
return super().to_internal_value(data)
def validate_url(self, value):
@@ -163,18 +166,29 @@ class WorkspaceUserLinkSerializer(BaseSerializer):
return value
class IssueRecentVisitSerializer(serializers.ModelSerializer):
project_identifier = serializers.SerializerMethodField()
class Meta:
model = Issue
fields = ["name", "state", "priority", "assignees", "type", "sequence_id", "project_id", "project_identifier"]
fields = [
"name",
"state",
"priority",
"assignees",
"type",
"sequence_id",
"project_id",
"project_identifier",
]
def get_project_identifier(self, obj):
project = obj.project
return project.identifier if project else None
class ProjectMemberSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True)
@@ -182,55 +196,66 @@ class ProjectMemberSerializer(BaseSerializer):
model = ProjectMember
fields = ["member"]
class ProjectRecentVisitSerializer(serializers.ModelSerializer):
project_members = serializers.SerializerMethodField()
project_members = serializers.SerializerMethodField()
class Meta:
model = Project
fields = ["id", "name", "logo_props", "project_members", "identifier"]
def get_project_members(self, obj):
members = ProjectMember.objects.filter(project_id=obj.id).select_related('member')
members = ProjectMember.objects.filter(project_id=obj.id).select_related(
"member"
)
serializer = ProjectMemberSerializer(members, many=True)
return serializer.data
class PageRecentVisitSerializer(serializers.ModelSerializer):
project_id = serializers.SerializerMethodField()
project_identifier = serializers.SerializerMethodField()
class Meta:
model = Page
fields = ["id", "name", "logo_props", "project_id", "owned_by", "project_identifier"]
fields = [
"id",
"name",
"logo_props",
"project_id",
"owned_by",
"project_identifier",
]
def get_project_id(self, obj):
return obj.project_id if hasattr(obj, 'project_id') else obj.projects.values_list('id', flat=True).first()
return (
obj.project_id
if hasattr(obj, "project_id")
else obj.projects.values_list("id", flat=True).first()
)
def get_project_identifier(self, obj):
project = obj.projects.first()
return project.identifier if project else None
def get_entity_model_and_serializer(entity_type):
entity_map = {
"issue": (Issue, IssueRecentVisitSerializer),
"page": (Page, PageRecentVisitSerializer),
"project": (Project, ProjectRecentVisitSerializer)
"project": (Project, ProjectRecentVisitSerializer),
}
return entity_map.get(entity_type, (None, None))
class WorkspaceRecentVisitSerializer(BaseSerializer):
entity_data = serializers.SerializerMethodField()
class Meta:
model = UserRecentVisit
fields = [
"id",
"entity_name",
"entity_identifier",
"entity_data",
"visited_at"
]
fields = ["id", "entity_name", "entity_identifier", "entity_data", "visited_at"]
read_only_fields = ["workspace", "owner", "created_by", "updated_by"]
def get_entity_data(self, obj):
@@ -247,3 +272,10 @@ class WorkspaceRecentVisitSerializer(BaseSerializer):
except entity_model.DoesNotExist:
return None
return None
class WorkspaceHomePreferenceSerializer(BaseSerializer):
class Meta:
model = WorkspaceHomePreference
fields = ["key", "is_enabled", "sort_order"]
read_only_fields = ["worspace", "created_by", "update_by"]

View File

@@ -28,7 +28,8 @@ from plane.app.views import (
WorkspaceFavoriteGroupEndpoint,
WorkspaceDraftIssueViewSet,
QuickLinkViewSet,
UserRecentVisitViewSet
UserRecentVisitViewSet,
WorkspacePreferenceViewSet,
)
@@ -215,25 +216,33 @@ urlpatterns = [
WorkspaceDraftIssueViewSet.as_view({"post": "create_draft_to_issue"}),
name="workspace-drafts-issues",
),
# quick link
path(
"workspaces/<str:slug>/quick-links/",
QuickLinkViewSet.as_view({"get": "list", "post": "create"}),
name="workspace-quick-links"
name="workspace-quick-links",
),
path(
"workspaces/<str:slug>/quick-links/<uuid:pk>/",
QuickLinkViewSet.as_view({
"get": "retrieve",
"patch": "partial_update",
"delete": "destroy"
}),
name="workspace-quick-links"
"workspaces/<str:slug>/quick-links/<uuid:pk>/",
QuickLinkViewSet.as_view(
{"get": "retrieve", "patch": "partial_update", "delete": "destroy"}
),
name="workspace-quick-links",
),
# Widgets
path(
"workspaces/<str:slug>/home-preferences/",
WorkspacePreferenceViewSet.as_view(),
name="workspace-home-preference",
),
path(
"workspaces/<str:slug>/home-preferences/<str:key>/",
WorkspacePreferenceViewSet.as_view(),
name="workspace-home-preference",
),
path(
"workspaces/<str:slug>/recent-visits/",
UserRecentVisitViewSet.as_view({"get": "list"}),
name="workspace-recent-visits"
)
name="workspace-recent-visits",
),
]

View File

@@ -41,6 +41,7 @@ from .workspace.base import (
from .workspace.draft import WorkspaceDraftIssueViewSet
from .workspace.preference import WorkspacePreferenceViewSet
from .workspace.favorite import (
WorkspaceFavoriteEndpoint,
WorkspaceFavoriteGroupEndpoint,

View File

@@ -0,0 +1,72 @@
# Module imports
from ..base import BaseAPIView
from plane.db.models.workspace import WorkspaceHomePreference
from plane.app.permissions import allow_permission, ROLE
from plane.db.models import Workspace
from plane.app.serializers.workspace import WorkspaceHomePreferenceSerializer
# Third party imports
from rest_framework.response import Response
from rest_framework import status
class WorkspacePreferenceViewSet(BaseAPIView):
model = WorkspaceHomePreference
def get_serializer_class(self):
return WorkspaceHomePreferenceSerializer
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST], level="WORKSPACE")
def get(self, request, slug):
workspace = Workspace.objects.get(slug=slug)
get_preference = WorkspaceHomePreference.objects.filter(
user=request.user, workspace_id=workspace.id
)
create_preference_keys = []
keys = [key for key, _ in WorkspaceHomePreference.HomeWidgetKeys.choices]
for preference in keys:
if preference not in get_preference.values_list("key", flat=True):
create_preference_keys.append(preference)
preference = WorkspaceHomePreference.objects.bulk_create(
[
WorkspaceHomePreference(
key=key, user=request.user, workspace=workspace
)
for key in create_preference_keys
],
batch_size=10,
ignore_conflicts=True,
)
preference = WorkspaceHomePreference.objects.filter(
user=request.user, workspace_id=workspace.id
)
return Response(
preference.values("key", "is_enabled", "config", "sort_order"),
status=status.HTTP_200_OK,
)
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST], level="WORKSPACE")
def patch(self, request, slug, key):
preference = WorkspaceHomePreference.objects.filter(
key=key, workspace__slug=slug
).first()
if preference:
serializer = WorkspaceHomePreferenceSerializer(
preference, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response(
{"detail": "Preference not found"}, status=status.HTTP_400_BAD_REQUEST
)

View File

@@ -69,6 +69,7 @@ from .workspace import (
WorkspaceTheme,
WorkspaceUserProperties,
WorkspaceUserLink,
WorkspaceHomePreference
)
from .favorite import UserFavorite