feat: workspace themes

This commit is contained in:
pablohashescobar 2023-04-10 18:14:09 +05:30
parent 33ea1cb9d3
commit b6c911f484
7 changed files with 139 additions and 4 deletions

View File

@ -11,6 +11,7 @@ from .workspace import (
TeamSerializer, TeamSerializer,
WorkSpaceMemberInviteSerializer, WorkSpaceMemberInviteSerializer,
WorkspaceLiteSerializer, WorkspaceLiteSerializer,
WorkspaceThemeSerializer,
) )
from .project import ( from .project import (
ProjectSerializer, ProjectSerializer,

View File

@ -5,8 +5,15 @@ from rest_framework import serializers
from .base import BaseSerializer from .base import BaseSerializer
from .user import UserLiteSerializer from .user import UserLiteSerializer
from plane.db.models import User, Workspace, WorkspaceMember, Team, TeamMember from plane.db.models import (
from plane.db.models import Workspace, WorkspaceMember, Team, WorkspaceMemberInvite User,
Workspace,
WorkspaceMember,
Team,
TeamMember,
WorkspaceMemberInvite,
WorkspaceTheme,
)
class WorkSpaceSerializer(BaseSerializer): class WorkSpaceSerializer(BaseSerializer):
@ -100,3 +107,13 @@ class WorkspaceLiteSerializer(BaseSerializer):
"id", "id",
] ]
read_only_fields = fields read_only_fields = fields
class WorkspaceThemeSerializer(BaseSerializer):
class Meta:
model = WorkspaceTheme
fields = "__all__"
read_only_fields = [
"workspace",
"actor",
]

View File

@ -42,6 +42,8 @@ from plane.api.views import (
UserActivityGraphEndpoint, UserActivityGraphEndpoint,
UserIssueCompletedGraphEndpoint, UserIssueCompletedGraphEndpoint,
UserWorkspaceDashboardEndpoint, UserWorkspaceDashboardEndpoint,
WorkspaceThemeViewSet,
UserWorkspaceThemeEndpoint,
## End Workspaces ## End Workspaces
# File Assets # File Assets
FileAssetEndpoint, FileAssetEndpoint,
@ -350,6 +352,32 @@ urlpatterns = [
WorkspaceMemberUserViewsEndpoint.as_view(), WorkspaceMemberUserViewsEndpoint.as_view(),
name="workspace-member-details", name="workspace-member-details",
), ),
path(
"workspaces/<str:slug>/workspace-themes/",
WorkspaceThemeViewSet.as_view(
{
"get": "list",
"post": "create",
}
),
name="workspace-themes",
),
path(
"workspaces/<str:slug>/workspace-themes/<uuid:pk>/",
WorkspaceThemeViewSet.as_view(
{
"get": "retrieve",
"patch": "partial_update",
"delete": "destroy",
}
),
name="workspace-themes",
),
path(
"users/me/workspaces/<str:slug>/workspace-themes/",
UserWorkspaceThemeEndpoint.as_view(),
name="user-workspace-themes",
),
## End Workspaces ## ## End Workspaces ##
# Projects # Projects
path( path(

View File

@ -40,6 +40,8 @@ from .workspace import (
UserActivityGraphEndpoint, UserActivityGraphEndpoint,
UserIssueCompletedGraphEndpoint, UserIssueCompletedGraphEndpoint,
UserWorkspaceDashboardEndpoint, UserWorkspaceDashboardEndpoint,
WorkspaceThemeViewSet,
UserWorkspaceThemeEndpoint,
) )
from .state import StateViewSet from .state import StateViewSet
from .shortcut import ShortCutViewSet from .shortcut import ShortCutViewSet

View File

@ -36,6 +36,7 @@ from plane.api.serializers import (
WorkSpaceMemberInviteSerializer, WorkSpaceMemberInviteSerializer,
UserLiteSerializer, UserLiteSerializer,
ProjectMemberSerializer, ProjectMemberSerializer,
WorkspaceThemeSerializer,
) )
from plane.api.views.base import BaseAPIView from plane.api.views.base import BaseAPIView
from . import BaseViewSet from . import BaseViewSet
@ -48,6 +49,7 @@ from plane.db.models import (
ProjectMember, ProjectMember,
IssueActivity, IssueActivity,
Issue, Issue,
WorkspaceTheme,
) )
from plane.api.permissions import WorkSpaceBasePermission, WorkSpaceAdminPermission from plane.api.permissions import WorkSpaceBasePermission, WorkSpaceAdminPermission
from plane.bgtasks.workspace_invitation_task import workspace_invitation from plane.bgtasks.workspace_invitation_task import workspace_invitation
@ -752,3 +754,65 @@ class UserWorkspaceDashboardEndpoint(BaseAPIView):
{"error": "Something went wrong please try again later"}, {"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
class WorkspaceThemeViewSet(BaseViewSet):
permission_classes = [
WorkSpaceAdminPermission,
]
model = WorkspaceTheme
serializer_class = WorkspaceThemeSerializer
def get_queryset(self):
return super().get_queryset().filter(workspace__slug=self.kwargs.get("slug"))
def create(self, request, slug):
try:
workspace = Workspace.objects.get(slug=slug)
serializer = WorkspaceThemeSerializer(data=request.data)
if serializer.is_valid():
serializer.save(workspace=workspace, actor=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Workspace.DoesNotExist:
return Response(
{"error": "Workspace does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
print(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UserWorkspaceThemeEndpoint(BaseAPIView):
def post(self, request, slug):
try:
workspace_theme_id = request.data.get("workspace_theme_id", False)
if not workspace_theme_id:
return Response(
{"error": "Workspace Theme ID is required"},
status=status.HTTP_400_BAD_REQUEST,
)
workspace_theme = WorkspaceTheme.objects.get(
workspace__slug=slug, pk=workspace_theme_id
)
# Update at member level
workspace_member = WorkspaceMember.objects.get(
workspace__slug=slug, member=request.user
)
workspace_member.workspace_theme = workspace_theme
workspace_member.save()
serializer = WorkSpaceMemberSerializer(workspace_member)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@ -8,6 +8,7 @@ from .workspace import (
Team, Team,
WorkspaceMemberInvite, WorkspaceMemberInvite,
TeamMember, TeamMember,
WorkspaceTheme,
) )
from .project import ( from .project import (

View File

@ -36,7 +36,6 @@ class Workspace(BaseModel):
ordering = ("-created_at",) ordering = ("-created_at",)
class WorkspaceMember(BaseModel): class WorkspaceMember(BaseModel):
workspace = models.ForeignKey( workspace = models.ForeignKey(
"db.Workspace", on_delete=models.CASCADE, related_name="workspace_member" "db.Workspace", on_delete=models.CASCADE, related_name="workspace_member"
@ -49,6 +48,9 @@ class WorkspaceMember(BaseModel):
role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, default=10) role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, default=10)
company_role = models.TextField(null=True, blank=True) company_role = models.TextField(null=True, blank=True)
view_props = models.JSONField(null=True, blank=True) view_props = models.JSONField(null=True, blank=True)
workspace_theme = models.ForeignKey(
"db.WorkspaceTheme", on_delete=models.SET_NULL, related_name="theme", null=True
)
class Meta: class Meta:
unique_together = ["workspace", "member"] unique_together = ["workspace", "member"]
@ -111,7 +113,6 @@ class Team(BaseModel):
class TeamMember(BaseModel): class TeamMember(BaseModel):
workspace = models.ForeignKey( workspace = models.ForeignKey(
Workspace, on_delete=models.CASCADE, related_name="team_member" Workspace, on_delete=models.CASCADE, related_name="team_member"
) )
@ -129,3 +130,24 @@ class TeamMember(BaseModel):
verbose_name_plural = "Team Members" verbose_name_plural = "Team Members"
db_table = "team_members" db_table = "team_members"
ordering = ("-created_at",) ordering = ("-created_at",)
class WorkspaceTheme(BaseModel):
workspace = models.ForeignKey(
"db.Workspace", on_delete=models.CASCADE, related_name="themes"
)
name = models.CharField(max_length=300)
actor = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="themes"
)
colors = models.JSONField(default=dict)
def __str__(self):
return str(self.name) + str(self.actor.email)
class Meta:
unique_together = ["workspace", "name"]
verbose_name = "Workspace Theme"
verbose_name_plural = "Workspace Themes"
db_table = "workspace_themes"
ordering = ("-created_at",)