mirror of
https://github.com/makeplane/plane
synced 2025-08-07 19:59:33 +00:00
Compare commits
18 Commits
chore-ln-h
...
feat-home-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5279a6889e | ||
|
|
c42d234189 | ||
|
|
53d521f888 | ||
|
|
80e21ea9dd | ||
|
|
bd2b140ac2 | ||
|
|
3f7033816f | ||
|
|
6fbb36c265 | ||
|
|
40a18f7159 | ||
|
|
8a58ec6c37 | ||
|
|
3c5c892f84 | ||
|
|
ac20cc4d00 | ||
|
|
bf36eb0102 | ||
|
|
0eee395e72 | ||
|
|
749f1ee39d | ||
|
|
a6a0da0817 | ||
|
|
ecfbec8e2b | ||
|
|
274612cd4a | ||
|
|
2c4541fdb6 |
@@ -19,7 +19,8 @@ from .workspace import (
|
||||
WorkspaceMemberAdminSerializer,
|
||||
WorkspaceMemberMeSerializer,
|
||||
WorkspaceUserPropertiesSerializer,
|
||||
WorkspaceUserLinkSerializer
|
||||
WorkspaceUserLinkSerializer,
|
||||
WorkspaceRecentVisitSerializer
|
||||
)
|
||||
from .project import (
|
||||
ProjectSerializer,
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
]
|
||||
|
||||
@@ -45,6 +45,7 @@ from .workspace.favorite import (
|
||||
WorkspaceFavoriteEndpoint,
|
||||
WorkspaceFavoriteGroupEndpoint,
|
||||
)
|
||||
from .workspace.recent_visit import UserRecentVisitViewSet
|
||||
|
||||
from .workspace.member import (
|
||||
WorkSpaceMemberViewSet,
|
||||
|
||||
31
apiserver/plane/app/views/workspace/recent_visit.py
Normal file
31
apiserver/plane/app/views/workspace/recent_visit.py
Normal 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)
|
||||
|
||||
Reference in New Issue
Block a user