feat: project grouping migrations (#691)

* feat: project grouping migrations

* chore: updated migration file

* chore: migration file changes

* chore: replaced base modal with project base modal in project attribute

* chore: project attribute migration

* chore: unique constraints migration

* dev: soft delete for project states

* chore: removed db dependency

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
This commit is contained in:
Nikhil
2024-08-02 17:20:32 +05:30
committed by GitHub
parent 92fb3dcb78
commit ccd53979f2
5 changed files with 503 additions and 2 deletions

View File

@@ -0,0 +1,375 @@
# Generated by Django 4.2.14 on 2024-08-02 09:52
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("ee", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="ProjectAttribute",
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"
),
),
(
"deleted_at",
models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
(
"id",
models.UUIDField(
db_index=True,
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
(
"priority",
models.CharField(
choices=[
("none", "None"),
("low", "Low"),
("medium", "Medium"),
("high", "High"),
("urgent", "Urgent"),
],
default="none",
max_length=50,
),
),
("start_date", models.DateTimeField(blank=True, null=True)),
("target_date", models.DateTimeField(blank=True, null=True)),
],
options={
"verbose_name": "Project Attribute",
"verbose_name_plural": "Project Attributes",
"db_table": "project_attributes",
"ordering": ("created_at",),
},
),
migrations.CreateModel(
name="ProjectState",
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"
),
),
(
"deleted_at",
models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
(
"id",
models.UUIDField(
db_index=True,
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("name", models.CharField(max_length=50)),
("description", models.TextField(blank=True)),
("color", models.CharField(max_length=255)),
("sequence", models.FloatField(default=65535)),
(
"group",
models.CharField(
choices=[
("draft", "Draft"),
("planning", "Planning"),
("execution", "Execution"),
("monitoring", "Monitoring"),
("completed", "Completed"),
("cancelled", "Cancelled"),
],
default="draft",
max_length=20,
),
),
("default", models.BooleanField(default=False)),
(
"external_source",
models.CharField(blank=True, max_length=255, null=True),
),
(
"external_id",
models.CharField(blank=True, max_length=255, null=True),
),
],
options={
"verbose_name": "Project State",
"verbose_name_plural": "Project States",
"db_table": "project_states",
"ordering": ("sequence",),
},
),
migrations.CreateModel(
name="WorkspaceFeature",
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"
),
),
(
"deleted_at",
models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
(
"id",
models.UUIDField(
db_index=True,
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
(
"is_project_grouping_enabled",
models.BooleanField(default=False),
),
],
options={
"verbose_name": "Workspace Feature",
"verbose_name_plural": "Workspace Features",
"db_table": "workspace_features",
"ordering": ("-created_at",),
},
),
migrations.AlterUniqueTogether(
name="issueproperty",
unique_together=set(),
),
migrations.AlterUniqueTogether(
name="issuepropertyoption",
unique_together=set(),
),
migrations.AddField(
model_name="issueproperty",
name="deleted_at",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
migrations.AddField(
model_name="issuepropertyactivity",
name="deleted_at",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
migrations.AddField(
model_name="issuepropertyoption",
name="deleted_at",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
migrations.AddField(
model_name="issuepropertyvalue",
name="deleted_at",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
migrations.AddField(
model_name="issueworklog",
name="deleted_at",
field=models.DateTimeField(
blank=True, null=True, verbose_name="Deleted At"
),
),
migrations.AlterUniqueTogether(
name="issueproperty",
unique_together={("name", "issue_type", "deleted_at")},
),
migrations.AlterUniqueTogether(
name="issuepropertyoption",
unique_together={("name", "property", "deleted_at")},
),
migrations.AddConstraint(
model_name="issueproperty",
constraint=models.UniqueConstraint(
condition=models.Q(("deleted_at__isnull", True)),
fields=("name", "issue_type"),
name="issue_property_unique_name_project_when_deleted_at_null",
),
),
migrations.AddConstraint(
model_name="issuepropertyoption",
constraint=models.UniqueConstraint(
condition=models.Q(("deleted_at__isnull", True)),
fields=("name", "property"),
name="issue_property_option_unique_name_project_when_deleted_at_null",
),
),
migrations.AddField(
model_name="workspacefeature",
name="created_by",
field=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",
),
),
migrations.AddField(
model_name="workspacefeature",
name="updated_by",
field=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",
),
),
migrations.AddField(
model_name="workspacefeature",
name="workspace",
field=models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="features",
to="db.workspace",
),
),
migrations.AddField(
model_name="projectstate",
name="created_by",
field=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",
),
),
migrations.AddField(
model_name="projectstate",
name="updated_by",
field=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",
),
),
migrations.AddField(
model_name="projectstate",
name="workspace",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="project_states",
to="db.workspace",
),
),
migrations.AddField(
model_name="projectattribute",
name="created_by",
field=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",
),
),
migrations.AddField(
model_name="projectattribute",
name="project",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="project_%(class)s",
to="db.project",
),
),
migrations.AddField(
model_name="projectattribute",
name="state",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="project_attributes",
to="ee.projectstate",
),
),
migrations.AddField(
model_name="projectattribute",
name="updated_by",
field=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",
),
),
migrations.AddField(
model_name="projectattribute",
name="workspace",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="workspace_%(class)s",
to="db.workspace",
),
),
migrations.AddConstraint(
model_name="projectstate",
constraint=models.UniqueConstraint(
condition=models.Q(("deleted_at__isnull", True)),
fields=("name", "workspace"),
name="project_state_unique_name_project_when_deleted_at_null",
),
),
migrations.AlterUniqueTogether(
name="projectstate",
unique_together={("name", "workspace", "deleted_at")},
),
]

View File

@@ -5,3 +5,5 @@ from .issue_properties import (
IssuePropertyActivity,
)
from .issue import IssueWorkLog
from .project import ProjectState, ProjectAttribute
from .workspace import WorkspaceFeature

View File

@@ -1,6 +1,7 @@
# Django imports
from django.db import models
from django.conf import settings
from django.db.models import Q
from django.template.defaultfilters import slugify
from django.contrib.postgres.fields import ArrayField
@@ -54,7 +55,14 @@ class IssueProperty(WorkspaceBaseModel):
class Meta:
ordering = ["sort_order"]
unique_together = ["name", "issue_type"]
unique_together = ["name", "issue_type", "deleted_at"]
constraints = [
models.UniqueConstraint(
fields=["name", "issue_type"],
condition=Q(deleted_at__isnull=True),
name="issue_property_unique_name_project_when_deleted_at_null",
)
]
db_table = "issue_properties"
def save(self, *args, **kwargs):
@@ -95,7 +103,14 @@ class IssuePropertyOption(WorkspaceBaseModel):
class Meta:
ordering = ["sort_order"]
unique_together = ["name", "property"]
unique_together = ["name", "property", "deleted_at"]
constraints = [
models.UniqueConstraint(
fields=["name", "property"],
condition=Q(deleted_at__isnull=True),
name="issue_property_option_unique_name_project_when_deleted_at_null",
)
]
db_table = "issue_property_options"
def save(self, *args, **kwargs):

View File

@@ -0,0 +1,91 @@
# Django imports
from django.db import models
# Module imports
from plane.db.models.base import BaseModel
from plane.db.models.project import ProjectBaseModel
class GroupChoices(models.TextChoices):
DRAFT = "draft", "Draft"
PLANNING = "planning", "Planning"
EXECUTION = "execution", "Execution"
MONITORING = "monitoring", "Monitoring"
COMPLETED = "completed", "Completed"
CANCELLED = "cancelled", "Cancelled"
class ProjectState(BaseModel):
workspace = models.ForeignKey(
"db.Workspace", on_delete=models.CASCADE, related_name="project_states"
)
name = models.CharField(max_length=50)
description = models.TextField(blank=True)
color = models.CharField(max_length=255)
sequence = models.FloatField(default=65535)
group = models.CharField(
max_length=20, choices=GroupChoices.choices, default=GroupChoices.DRAFT
)
default = models.BooleanField(default=False)
external_source = models.CharField(max_length=255, null=True, blank=True)
external_id = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
"""Return name of the state"""
return f"{self.name} <{self.workspace.name}>"
class Meta:
unique_together = ["name", "workspace", "deleted_at"]
constraints = [
models.UniqueConstraint(
fields=["name", "workspace"],
condition=models.Q(deleted_at__isnull=True),
name="project_state_unique_name_project_when_deleted_at_null",
)
]
verbose_name = "Project State"
verbose_name_plural = "Project States"
db_table = "project_states"
ordering = ("sequence",)
def save(self, *args, **kwargs):
if self._state.adding:
# Get the maximum sequence value from the database
last_id = ProjectState.objects.filter(
workspace=self.workspace
).aggregate(largest=models.Max("sequence"))["largest"]
# if last_id is not None
if last_id is not None:
self.sequence = last_id + 15000
return super().save(*args, **kwargs)
class PriorityChoices(models.TextChoices):
NONE = "none", "None"
LOW = "low", "Low"
MEDIUM = "medium", "Medium"
HIGH = "high", "High"
URGENT = "urgent", "Urgent"
class ProjectAttribute(ProjectBaseModel):
priority = models.CharField(
max_length=50,
choices=PriorityChoices.choices,
default=PriorityChoices.NONE,
)
state = models.ForeignKey(
ProjectState,
on_delete=models.SET_NULL,
related_name="project_attributes",
null=True,
)
start_date = models.DateTimeField(null=True, blank=True)
target_date = models.DateTimeField(null=True, blank=True)
class Meta:
verbose_name = "Project Attribute"
verbose_name_plural = "Project Attributes"
db_table = "project_attributes"
ordering = ("created_at",)

View File

@@ -0,0 +1,18 @@
# Django imports
from django.db import models
# Module imports
from plane.db.models.base import BaseModel
class WorkspaceFeature(BaseModel):
workspace = models.OneToOneField(
"db.Workspace", on_delete=models.CASCADE, related_name="features"
)
is_project_grouping_enabled = models.BooleanField(default=False)
class Meta:
verbose_name = "Workspace Feature"
verbose_name_plural = "Workspace Features"
db_table = "workspace_features"
ordering = ("-created_at",)