mirror of
https://github.com/gosticks/plane.git
synced 2025-10-16 12:45:33 +00:00
[WIKI-659] chore: added issue relation and page sort order (#7784)
* chore: added issue relation and page sort order * feat: add ProjectWebhook model to manage webhooks associated with projects * chore: updated the migration file * chore: added migration * chore: reverted the page base code * chore: added a variable for sort order in pages --------- Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
This commit is contained in:
parent
c3e7cfd16b
commit
116c8118ab
152
apps/api/plane/db/migrations/0106_auto_20250912_0845.py
Normal file
152
apps/api/plane/db/migrations/0106_auto_20250912_0845.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# Generated by Django 4.2.22 on 2025-09-12 08:45
|
||||||
|
import uuid
|
||||||
|
import django
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def set_page_sort_order(apps, schema_editor):
|
||||||
|
Page = apps.get_model("db", "Page")
|
||||||
|
|
||||||
|
batch_size = 3000
|
||||||
|
sort_order = 100
|
||||||
|
|
||||||
|
# Get page IDs ordered by name using the historical model
|
||||||
|
# This should include all pages regardless of soft-delete status
|
||||||
|
page_ids = list(Page.objects.all().order_by("name").values_list("id", flat=True))
|
||||||
|
|
||||||
|
updated_pages = []
|
||||||
|
for page_id in page_ids:
|
||||||
|
# Create page instance with minimal data
|
||||||
|
updated_pages.append(Page(id=page_id, sort_order=sort_order))
|
||||||
|
sort_order += 100
|
||||||
|
|
||||||
|
# Bulk update when batch is full
|
||||||
|
if len(updated_pages) >= batch_size:
|
||||||
|
Page.objects.bulk_update(
|
||||||
|
updated_pages, ["sort_order"], batch_size=batch_size
|
||||||
|
)
|
||||||
|
updated_pages = []
|
||||||
|
|
||||||
|
# Update remaining pages
|
||||||
|
if updated_pages:
|
||||||
|
Page.objects.bulk_update(updated_pages, ["sort_order"], batch_size=batch_size)
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_set_page_sort_order(apps, schema_editor):
|
||||||
|
Page = apps.get_model("db", "Page")
|
||||||
|
Page.objects.update(sort_order=Page.DEFAULT_SORT_ORDER)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("db", "0105_alter_project_cycle_view_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ProjectWebhook",
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"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.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="project_%(class)s",
|
||||||
|
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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"webhook",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="project_webhooks",
|
||||||
|
to="db.webhook",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"workspace",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="workspace_%(class)s",
|
||||||
|
to="db.workspace",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Project Webhook",
|
||||||
|
"verbose_name_plural": "Project Webhooks",
|
||||||
|
"db_table": "project_webhooks",
|
||||||
|
"ordering": ("-created_at",),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddConstraint(
|
||||||
|
model_name="projectwebhook",
|
||||||
|
constraint=models.UniqueConstraint(
|
||||||
|
condition=models.Q(("deleted_at__isnull", True)),
|
||||||
|
fields=("project", "webhook"),
|
||||||
|
name="project_webhook_unique_project_webhook_when_deleted_at_null",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name="projectwebhook",
|
||||||
|
unique_together={("project", "webhook", "deleted_at")},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="issuerelation",
|
||||||
|
name="relation_type",
|
||||||
|
field=models.CharField(
|
||||||
|
default="blocked_by", max_length=20, verbose_name="Issue Relation Type"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
set_page_sort_order, reverse_code=reverse_set_page_sort_order
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -284,6 +284,7 @@ class IssueRelationChoices(models.TextChoices):
|
|||||||
BLOCKED_BY = "blocked_by", "Blocked By"
|
BLOCKED_BY = "blocked_by", "Blocked By"
|
||||||
START_BEFORE = "start_before", "Start Before"
|
START_BEFORE = "start_before", "Start Before"
|
||||||
FINISH_BEFORE = "finish_before", "Finish Before"
|
FINISH_BEFORE = "finish_before", "Finish Before"
|
||||||
|
IMPLEMENTED_BY = "implemented_by", "Implemented By"
|
||||||
|
|
||||||
|
|
||||||
class IssueRelation(ProjectBaseModel):
|
class IssueRelation(ProjectBaseModel):
|
||||||
@ -295,7 +296,6 @@ class IssueRelation(ProjectBaseModel):
|
|||||||
)
|
)
|
||||||
relation_type = models.CharField(
|
relation_type = models.CharField(
|
||||||
max_length=20,
|
max_length=20,
|
||||||
choices=IssueRelationChoices.choices,
|
|
||||||
verbose_name="Issue Relation Type",
|
verbose_name="Issue Relation Type",
|
||||||
default=IssueRelationChoices.BLOCKED_BY,
|
default=IssueRelationChoices.BLOCKED_BY,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -19,6 +19,7 @@ def get_view_props():
|
|||||||
class Page(BaseModel):
|
class Page(BaseModel):
|
||||||
PRIVATE_ACCESS = 1
|
PRIVATE_ACCESS = 1
|
||||||
PUBLIC_ACCESS = 0
|
PUBLIC_ACCESS = 0
|
||||||
|
DEFAULT_SORT_ORDER = 65535
|
||||||
|
|
||||||
ACCESS_CHOICES = ((PRIVATE_ACCESS, "Private"), (PUBLIC_ACCESS, "Public"))
|
ACCESS_CHOICES = ((PRIVATE_ACCESS, "Private"), (PUBLIC_ACCESS, "Public"))
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ class Page(BaseModel):
|
|||||||
)
|
)
|
||||||
moved_to_page = models.UUIDField(null=True, blank=True)
|
moved_to_page = models.UUIDField(null=True, blank=True)
|
||||||
moved_to_project = models.UUIDField(null=True, blank=True)
|
moved_to_project = models.UUIDField(null=True, blank=True)
|
||||||
sort_order = models.FloatField(default=65535)
|
sort_order = models.FloatField(default=DEFAULT_SORT_ORDER)
|
||||||
|
|
||||||
external_id = models.CharField(max_length=255, null=True, blank=True)
|
external_id = models.CharField(max_length=255, null=True, blank=True)
|
||||||
external_source = models.CharField(max_length=255, null=True, blank=True)
|
external_source = models.CharField(max_length=255, null=True, blank=True)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ from django.db import models
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
from plane.db.models import BaseModel
|
from plane.db.models import BaseModel, ProjectBaseModel
|
||||||
|
|
||||||
|
|
||||||
def generate_token():
|
def generate_token():
|
||||||
@ -90,3 +90,24 @@ class WebhookLog(BaseModel):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.event_type} {str(self.webhook)}"
|
return f"{self.event_type} {str(self.webhook)}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectWebhook(ProjectBaseModel):
|
||||||
|
webhook = models.ForeignKey(
|
||||||
|
"db.Webhook", on_delete=models.CASCADE, related_name="project_webhooks"
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ["project", "webhook", "deleted_at"]
|
||||||
|
constraints = [
|
||||||
|
models.UniqueConstraint(
|
||||||
|
fields=["project", "webhook"],
|
||||||
|
condition=models.Q(deleted_at__isnull=True),
|
||||||
|
name="project_webhook_unique_project_webhook_when_deleted_at_null",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
verbose_name = "Project Webhook"
|
||||||
|
verbose_name_plural = "Project Webhooks"
|
||||||
|
db_table = "project_webhooks"
|
||||||
|
ordering = ("-created_at",)
|
||||||
@ -6,12 +6,14 @@ def get_inverse_relation(relation_type):
|
|||||||
"blocking": "blocked_by",
|
"blocking": "blocked_by",
|
||||||
"start_before": "start_after",
|
"start_before": "start_after",
|
||||||
"finish_before": "finish_after",
|
"finish_before": "finish_after",
|
||||||
|
"implemented_by": "implements",
|
||||||
|
"implements": "implemented_by",
|
||||||
}
|
}
|
||||||
return relation_mapping.get(relation_type, relation_type)
|
return relation_mapping.get(relation_type, relation_type)
|
||||||
|
|
||||||
|
|
||||||
def get_actual_relation(relation_type):
|
def get_actual_relation(relation_type):
|
||||||
# This function is used to get the actual relation type which is store in database
|
# This function is used to get the actual relation type which is stored in database
|
||||||
actual_relation = {
|
actual_relation = {
|
||||||
"start_after": "start_before",
|
"start_after": "start_before",
|
||||||
"finish_after": "finish_before",
|
"finish_after": "finish_before",
|
||||||
@ -19,6 +21,8 @@ def get_actual_relation(relation_type):
|
|||||||
"blocked_by": "blocked_by",
|
"blocked_by": "blocked_by",
|
||||||
"start_before": "start_before",
|
"start_before": "start_before",
|
||||||
"finish_before": "finish_before",
|
"finish_before": "finish_before",
|
||||||
|
"implemented_by": "implemented_by",
|
||||||
|
"implements": "implemented_by",
|
||||||
}
|
}
|
||||||
|
|
||||||
return actual_relation.get(relation_type, relation_type)
|
return actual_relation.get(relation_type, relation_type)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user