Skip to content

Commit

Permalink
[WEB-2937] feat: home recent activies list endpoint (#6295)
Browse files Browse the repository at this point in the history
* Crud for wuick links

* Validate quick link existence

* Add custom method for destroy and retrieve

* Add List method

* Remove print statements

* List all the workspace quick links

* feat: endpoint to get recently active items

* Resolve conflicts

* Resolve conflicts

* Add filter to only list required entities

* Return required fields

* Add filter

* Add filter
  • Loading branch information
sangeethailango authored Jan 3, 2025
1 parent 4652ad0 commit 870ca17
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 6 deletions.
3 changes: 2 additions & 1 deletion apiserver/plane/app/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
WorkspaceMemberAdminSerializer,
WorkspaceMemberMeSerializer,
WorkspaceUserPropertiesSerializer,
WorkspaceUserLinkSerializer
WorkspaceUserLinkSerializer,
WorkspaceRecentVisitSerializer
)
from .project import (
ProjectSerializer,
Expand Down
1 change: 0 additions & 1 deletion apiserver/plane/app/serializers/favorite.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
95 changes: 94 additions & 1 deletion apiserver/plane/app/serializers/workspace.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -132,3 +140,88 @@ def validate_url(self, value):
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
16 changes: 13 additions & 3 deletions apiserver/plane/app/urls/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
WorkspaceFavoriteEndpoint,
WorkspaceFavoriteGroupEndpoint,
WorkspaceDraftIssueViewSet,
QuickLinkViewSet
QuickLinkViewSet,
UserRecentVisitViewSet
)


Expand Down Expand Up @@ -219,11 +220,20 @@
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"
)
]
1 change: 1 addition & 0 deletions apiserver/plane/app/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
WorkspaceFavoriteEndpoint,
WorkspaceFavoriteGroupEndpoint,
)
from .workspace.recent_visit import UserRecentVisitViewSet

from .workspace.member import (
WorkSpaceMemberViewSet,
Expand Down
31 changes: 31 additions & 0 deletions apiserver/plane/app/views/workspace/recent_visit.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 870ca17

Please sign in to comment.