Compare commits

...

18 Commits

Author SHA1 Message Date
sangeethailango
5279a6889e Merge branch 'feat-home-recents' of github.com:makeplane/plane into feat-home-recents 2025-01-03 14:53:00 +05:30
sangeethailango
c42d234189 Merge branch 'feat-home-recents' of github.com:makeplane/plane into feat-home-recents 2025-01-03 14:49:20 +05:30
sangeethailango
53d521f888 Merge branch 'feat-home-recents' of github.com:makeplane/plane into feat-home-recents 2025-01-02 22:41:36 +05:30
sangeethailango
80e21ea9dd Add filter 2025-01-02 22:40:51 +05:30
sangeethailango
bd2b140ac2 Add filter 2025-01-02 20:20:00 +05:30
sangeethailango
3f7033816f Return required fields 2025-01-02 20:03:57 +05:30
sangeethailango
6fbb36c265 Add filter to only list required entities 2025-01-02 14:47:52 +05:30
sangeethailango
40a18f7159 Merge branch 'feat-home-recents' of github.com:makeplane/plane into feat-home-recents 2025-01-02 10:30:17 +05:30
sangeethailango
8a58ec6c37 Resolve conflicts 2025-01-02 10:26:33 +05:30
sangeethailango
3c5c892f84 Resolve conflicts 2024-12-31 18:03:08 +05:30
sangeethailango
ac20cc4d00 Merge branch 'preview' into feat-home-recents 2024-12-31 18:02:29 +05:30
sangeethailango
bf36eb0102 feat: endpoint to get recently active items 2024-12-31 17:39:34 +05:30
sangeethailango
0eee395e72 List all the workspace quick links 2024-12-30 16:57:25 +05:30
sangeethailango
749f1ee39d Remove print statements 2024-12-30 16:54:46 +05:30
sangeethailango
a6a0da0817 Add List method 2024-12-30 16:46:48 +05:30
sangeethailango
ecfbec8e2b Add custom method for destroy and retrieve 2024-12-30 16:26:29 +05:30
sangeethailango
274612cd4a Validate quick link existence 2024-12-30 14:43:20 +05:30
sangeethailango
2c4541fdb6 Crud for wuick links 2024-12-30 14:26:10 +05:30
6 changed files with 141 additions and 6 deletions

View File

@@ -19,7 +19,8 @@ from .workspace import (
WorkspaceMemberAdminSerializer,
WorkspaceMemberMeSerializer,
WorkspaceUserPropertiesSerializer,
WorkspaceUserLinkSerializer
WorkspaceUserLinkSerializer,
WorkspaceRecentVisitSerializer
)
from .project import (
ProjectSerializer,

View File

@@ -53,7 +53,6 @@ def get_entity_model_and_serializer(entity_type):
}
return entity_map.get(entity_type, (None, None))
class UserFavoriteSerializer(serializers.ModelSerializer):
entity_data = serializers.SerializerMethodField()

View File

@@ -1,17 +1,25 @@
# Third party imports
from rest_framework import serializers
from rest_framework import status
from rest_framework.response import Response
# Module imports
from .base import BaseSerializer, DynamicBaseSerializer
from .user import UserLiteSerializer, UserAdminLiteSerializer
from plane.db.models import (
Workspace,
WorkspaceMember,
WorkspaceMemberInvite,
WorkspaceTheme,
WorkspaceUserProperties,
WorkspaceUserLink
WorkspaceUserLink,
UserRecentVisit,
Issue,
Page,
Project,
ProjectMember
)
from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS
@@ -132,3 +140,88 @@ class WorkspaceUserLinkSerializer(BaseSerializer):
raise serializers.ValidationError({"error": "Invalid URL format."})
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"]
def get_project_identifier(self, obj):
project = obj.project
return project.identifier if project else None
class ProjectMemberSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True)
class Meta:
model = ProjectMember
fields = ["member"]
class ProjectRecentVisitSerializer(serializers.ModelSerializer):
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')
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"]
def get_project_id(self, obj):
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)
}
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"
]
read_only_fields = ["workspace", "owner", "created_by", "updated_by"]
def get_entity_data(self, obj):
entity_name = obj.entity_name
entity_identifier = obj.entity_identifier
entity_model, entity_serializer = get_entity_model_and_serializer(entity_name)
if entity_model and entity_serializer:
try:
entity = entity_model.objects.get(pk=entity_identifier)
return entity_serializer(entity).data
except entity_model.DoesNotExist:
return None
return None

View File

@@ -27,7 +27,8 @@ from plane.app.views import (
WorkspaceFavoriteEndpoint,
WorkspaceFavoriteGroupEndpoint,
WorkspaceDraftIssueViewSet,
QuickLinkViewSet
QuickLinkViewSet,
UserRecentVisitViewSet
)
@@ -219,11 +220,20 @@ urlpatterns = [
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"}),
QuickLinkViewSet.as_view({
"get": "retrieve",
"patch": "partial_update",
"delete": "destroy"
}),
name="workspace-quick-links"
),
path(
"workspaces/<str:slug>/recent-visits/",
UserRecentVisitViewSet.as_view({"get": "list"}),
name="workspace-recent-visits"
)
]

View File

@@ -45,6 +45,7 @@ from .workspace.favorite import (
WorkspaceFavoriteEndpoint,
WorkspaceFavoriteGroupEndpoint,
)
from .workspace.recent_visit import UserRecentVisitViewSet
from .workspace.member import (
WorkSpaceMemberViewSet,

View File

@@ -0,0 +1,31 @@
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from plane.db.models import UserRecentVisit
from plane.app.serializers import WorkspaceRecentVisitSerializer
# Modules imports
from ..base import BaseViewSet
from plane.app.permissions import allow_permission, ROLE
class UserRecentVisitViewSet(BaseViewSet):
model = UserRecentVisit
def get_serializer_class(self):
return WorkspaceRecentVisitSerializer
@allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST], level="WORKSPACE")
def list(self, request, slug):
user_recent_visits = UserRecentVisit.objects.filter(workspace__slug=slug)
entity_name = request.query_params.get("entity_name")
if entity_name:
user_recent_visits = user_recent_visits.filter(entity_name=entity_name)
user_recent_visits = user_recent_visits.filter(entity_name__in=["issue","page","project"])
serializer = WorkspaceRecentVisitSerializer(user_recent_visits[:20], many=True)
return Response(serializer.data, status=status.HTTP_200_OK)