mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: separate out project feature model
This commit is contained in:
parent
532da80375
commit
6c6aa3b0d5
@ -8,6 +8,7 @@ from plane.db.models import (
|
||||
WorkspaceMember,
|
||||
State,
|
||||
Estimate,
|
||||
ProjectFeature,
|
||||
)
|
||||
from .base import BaseSerializer
|
||||
|
||||
@ -78,6 +79,7 @@ class ProjectSerializer(BaseSerializer):
|
||||
project = Project.objects.create(
|
||||
**validated_data, workspace_id=self.context["workspace_id"]
|
||||
)
|
||||
|
||||
_ = ProjectIdentifier.objects.create(
|
||||
name=project.identifier,
|
||||
project=project,
|
||||
|
@ -11,7 +11,6 @@ from rest_framework.serializers import ValidationError
|
||||
from plane.db.models import (
|
||||
Workspace,
|
||||
Project,
|
||||
ProjectFavorite,
|
||||
ProjectMember,
|
||||
ProjectDeployBoard,
|
||||
State,
|
||||
@ -19,6 +18,7 @@ from plane.db.models import (
|
||||
Module,
|
||||
IssueProperty,
|
||||
Inbox,
|
||||
ProjectFeature,
|
||||
)
|
||||
from plane.app.permissions import ProjectBasePermission
|
||||
from plane.api.serializers import ProjectSerializer
|
||||
@ -149,6 +149,11 @@ class ProjectAPIEndpoint(WebhookMixin, BaseAPIView):
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
|
||||
# features
|
||||
_ = ProjectFeature.objects.create(
|
||||
project_id=serializer.data["id"]
|
||||
)
|
||||
|
||||
# Add the user as Administrator to the project
|
||||
project_member = ProjectMember.objects.create(
|
||||
project_id=serializer.data["id"],
|
||||
|
@ -21,6 +21,7 @@ from .workspace import (
|
||||
)
|
||||
from .project import (
|
||||
ProjectSerializer,
|
||||
ProjectFeatureSerializer,
|
||||
ProjectListSerializer,
|
||||
ProjectDetailSerializer,
|
||||
ProjectMemberSerializer,
|
||||
|
@ -16,6 +16,7 @@ from plane.db.models import (
|
||||
ProjectFavorite,
|
||||
ProjectDeployBoard,
|
||||
ProjectPublicMember,
|
||||
ProjectFeature,
|
||||
)
|
||||
|
||||
|
||||
@ -47,6 +48,8 @@ class ProjectSerializer(BaseSerializer):
|
||||
project = Project.objects.create(
|
||||
**validated_data, workspace_id=self.context["workspace_id"]
|
||||
)
|
||||
|
||||
# Create identifiers
|
||||
_ = ProjectIdentifier.objects.create(
|
||||
name=project.identifier,
|
||||
project=project,
|
||||
@ -237,3 +240,14 @@ class ProjectPublicMemberSerializer(BaseSerializer):
|
||||
"project",
|
||||
"member",
|
||||
]
|
||||
|
||||
|
||||
class ProjectFeatureSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ProjectFeature
|
||||
fields = "__all__"
|
||||
read_only_fields = [
|
||||
"project",
|
||||
"workspace",
|
||||
]
|
||||
|
@ -14,6 +14,7 @@ from plane.app.views import (
|
||||
ProjectPublicCoverImagesEndpoint,
|
||||
ProjectDeployBoardViewSet,
|
||||
UserProjectRolesEndpoint,
|
||||
ProjectFeatureEndpoint,
|
||||
)
|
||||
|
||||
|
||||
@ -175,4 +176,9 @@ urlpatterns = [
|
||||
),
|
||||
name="project-deploy-board",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/project-features/",
|
||||
ProjectFeatureEndpoint.as_view(),
|
||||
name="project-feature",
|
||||
),
|
||||
]
|
||||
|
@ -12,6 +12,7 @@ from .project import (
|
||||
ProjectPublicCoverImagesEndpoint,
|
||||
ProjectDeployBoardViewSet,
|
||||
UserProjectRolesEndpoint,
|
||||
ProjectFeatureEndpoint,
|
||||
)
|
||||
from .user import (
|
||||
UserEndpoint,
|
||||
|
@ -37,6 +37,7 @@ from plane.app.serializers import (
|
||||
ProjectDeployBoardSerializer,
|
||||
ProjectMemberAdminSerializer,
|
||||
ProjectMemberRoleSerializer,
|
||||
ProjectFeatureSerializer,
|
||||
)
|
||||
|
||||
from plane.app.permissions import (
|
||||
@ -62,6 +63,7 @@ from plane.db.models import (
|
||||
Inbox,
|
||||
ProjectDeployBoard,
|
||||
IssueProperty,
|
||||
ProjectFeature,
|
||||
)
|
||||
|
||||
from plane.bgtasks.project_invitation_task import project_invitation
|
||||
@ -203,6 +205,10 @@ class ProjectViewSet(WebhookMixin, BaseViewSet):
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
|
||||
_ = ProjectFeature.objects.create(
|
||||
project_id=serializer.data["id"]
|
||||
)
|
||||
|
||||
# Add the user as Administrator to the project
|
||||
project_member = ProjectMember.objects.create(
|
||||
project_id=serializer.data["id"],
|
||||
@ -686,9 +692,14 @@ class ProjectMemberViewSet(BaseViewSet):
|
||||
)
|
||||
|
||||
bulk_project_members = []
|
||||
member_roles = {member.get("member_id"): member.get("role") for member in members}
|
||||
member_roles = {
|
||||
member.get("member_id"): member.get("role") for member in members
|
||||
}
|
||||
# Update roles in the members array based on the member_roles dictionary
|
||||
for project_member in ProjectMember.objects.filter(project_id=project_id, member_id__in=[member.get("member_id") for member in members]):
|
||||
for project_member in ProjectMember.objects.filter(
|
||||
project_id=project_id,
|
||||
member_id__in=[member.get("member_id") for member in members],
|
||||
):
|
||||
project_member.role = member_roles[str(project_member.member_id)]
|
||||
project_member.is_active = True
|
||||
bulk_project_members.append(project_member)
|
||||
@ -734,7 +745,10 @@ class ProjectMemberViewSet(BaseViewSet):
|
||||
bulk_issue_props, batch_size=10, ignore_conflicts=True
|
||||
)
|
||||
|
||||
project_members = ProjectMember.objects.filter(project_id=project_id, member_id__in=[member.get("member_id") for member in members])
|
||||
project_members = ProjectMember.objects.filter(
|
||||
project_id=project_id,
|
||||
member_id__in=[member.get("member_id") for member in members],
|
||||
)
|
||||
serializer = ProjectMemberRoleSerializer(project_members, many=True)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
||||
@ -1138,3 +1152,29 @@ class UserProjectRolesEndpoint(BaseAPIView):
|
||||
for member in project_members
|
||||
}
|
||||
return Response(project_members, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ProjectFeatureEndpoint(BaseAPIView):
|
||||
permission_classes = [
|
||||
ProjectBasePermission,
|
||||
]
|
||||
|
||||
def get(self, request, slug, project_id):
|
||||
project_feature = ProjectFeature.objects.get(
|
||||
workspace__slug=slug, project_id=project_id
|
||||
)
|
||||
serializer = ProjectFeatureSerializer(project_feature)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
def patch(self, request, slug, project_id):
|
||||
project_feature = ProjectFeature.objects.get(
|
||||
workspace__slug=slug,
|
||||
project_id=project_id,
|
||||
)
|
||||
serializer = ProjectFeatureSerializer(
|
||||
project_feature, 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)
|
||||
|
@ -0,0 +1,120 @@
|
||||
# Generated by Django 4.2.7 on 2024-01-29 07:11
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
def create_project_preferences(apps, schema_editor):
|
||||
ProjectFeature = apps.get_model("db", "ProjectFeature")
|
||||
Project = apps.get_model("db", "Project")
|
||||
|
||||
ProjectFeature.objects.bulk_create(
|
||||
[
|
||||
ProjectFeature(
|
||||
project_id=project.get("id"),
|
||||
workspace_id=project.get("workspace_id"),
|
||||
cycles=project.get("cycle_view"),
|
||||
modules=project.get("module_view"),
|
||||
views=project.get("issue_views_view"),
|
||||
pages=project.get("page_view"),
|
||||
inbox=project.get("inbox_view"),
|
||||
)
|
||||
for project in Project.objects.values(
|
||||
"id",
|
||||
"workspace_id",
|
||||
"cycle_view",
|
||||
"inbox_view",
|
||||
"issue_views_view",
|
||||
"page_view",
|
||||
"module_view",
|
||||
)
|
||||
],
|
||||
batch_size=100,
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("db", "0057_auto_20240122_0901"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ProjectFeature",
|
||||
fields=[
|
||||
(
|
||||
"created_at",
|
||||
models.DateTimeField(
|
||||
auto_now_add=True, verbose_name="Created At"
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_at",
|
||||
models.DateTimeField(
|
||||
auto_now=True, verbose_name="Last Modified At"
|
||||
),
|
||||
),
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
db_index=True,
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
),
|
||||
),
|
||||
("modules", models.BooleanField(default=True)),
|
||||
("cycles", models.BooleanField(default=True)),
|
||||
("views", models.BooleanField(default=True)),
|
||||
("pages", models.BooleanField(default=True)),
|
||||
("inbox", models.BooleanField(default=False)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="%(class)s_created_by",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Created By",
|
||||
),
|
||||
),
|
||||
(
|
||||
"project",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="features",
|
||||
to="db.project",
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_by",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="%(class)s_updated_by",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Last Modified By",
|
||||
),
|
||||
),
|
||||
(
|
||||
"workspace",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="project_features",
|
||||
to="db.workspace",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Project Feature",
|
||||
"verbose_name_plural": "Project Features",
|
||||
"db_table": "project_features",
|
||||
"ordering": ("-created_at",),
|
||||
},
|
||||
),
|
||||
migrations.RunPython(create_project_preferences),
|
||||
]
|
@ -22,6 +22,7 @@ from .project import (
|
||||
ProjectFavorite,
|
||||
ProjectDeployBoard,
|
||||
ProjectPublicMember,
|
||||
ProjectFeature,
|
||||
)
|
||||
|
||||
from .issue import (
|
||||
|
@ -89,11 +89,6 @@ class Project(BaseModel):
|
||||
)
|
||||
emoji = models.CharField(max_length=255, null=True, blank=True)
|
||||
icon_prop = models.JSONField(null=True)
|
||||
module_view = models.BooleanField(default=True)
|
||||
cycle_view = models.BooleanField(default=True)
|
||||
issue_views_view = models.BooleanField(default=True)
|
||||
page_view = models.BooleanField(default=True)
|
||||
inbox_view = models.BooleanField(default=False)
|
||||
cover_image = models.URLField(blank=True, null=True, max_length=800)
|
||||
estimate = models.ForeignKey(
|
||||
"db.Estimate",
|
||||
@ -146,6 +141,36 @@ class ProjectBaseModel(BaseModel):
|
||||
super(ProjectBaseModel, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class ProjectFeature(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="project_features",
|
||||
)
|
||||
project = models.OneToOneField(
|
||||
Project, on_delete=models.CASCADE, related_name="features"
|
||||
)
|
||||
modules = models.BooleanField(default=False)
|
||||
cycles = models.BooleanField(default=False)
|
||||
views = models.BooleanField(default=False)
|
||||
pages = models.BooleanField(default=True)
|
||||
inbox = models.BooleanField(default=False)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.workspace = self.project.workspace
|
||||
super(ProjectFeature, self).save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
"""Return feature of the project"""
|
||||
return f"{self.project.name} <{self.id}>"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Project Feature"
|
||||
verbose_name_plural = "Project Features"
|
||||
db_table = "project_features"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
|
||||
class ProjectMemberInvite(ProjectBaseModel):
|
||||
email = models.CharField(max_length=255)
|
||||
accepted = models.BooleanField(default=False)
|
||||
|
Loading…
Reference in New Issue
Block a user