feat: add enterprise identity and channel integrations
This commit is contained in:
112
backend/apps/channels/migrations/0001_initial.py
Normal file
112
backend/apps/channels/migrations/0001_initial.py
Normal file
@@ -0,0 +1,112 @@
|
||||
# Generated by Django 5.2.8 on 2026-07-27
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("tickets", "0013_ticketsupportanalysis_applied_solution_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="ChannelEndpoint",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("public_id", models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||
("name", models.CharField(max_length=120, unique=True)),
|
||||
("adapter_type", models.CharField(default="generic_webhook", max_length=40)),
|
||||
("outbound_url", models.URLField(blank=True, max_length=500)),
|
||||
("webhook_secret_encrypted", models.TextField(blank=True)),
|
||||
("outbound_token_encrypted", models.TextField(blank=True)),
|
||||
("enabled", models.BooleanField(default=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("created_by", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="created_channel_endpoints", to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={"ordering": ["name"]},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ChannelConversation",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("public_id", models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||
("external_conversation_id", models.CharField(max_length=200)),
|
||||
("title", models.CharField(blank=True, max_length=200)),
|
||||
("participants", models.JSONField(blank=True, default=list)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("endpoint", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name="conversations", to="channels.channelendpoint")),
|
||||
("ticket", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="channel_conversations", to="tickets.ticket")),
|
||||
],
|
||||
options={"ordering": ["-updated_at"]},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ChannelMessage",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("public_id", models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
|
||||
("direction", models.CharField(max_length=16)),
|
||||
("external_message_id", models.CharField(blank=True, max_length=200)),
|
||||
("idempotency_key", models.CharField(blank=True, max_length=200)),
|
||||
("sender", models.CharField(blank=True, max_length=160)),
|
||||
("message_type", models.CharField(default="text", max_length=24)),
|
||||
("text", models.TextField(blank=True)),
|
||||
("payload", models.JSONField(blank=True, default=dict)),
|
||||
("status", models.CharField(max_length=24)),
|
||||
("error_message", models.TextField(blank=True)),
|
||||
("occurred_at", models.DateTimeField(blank=True, null=True)),
|
||||
("sent_at", models.DateTimeField(blank=True, null=True)),
|
||||
("delivered_at", models.DateTimeField(blank=True, null=True)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("conversation", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="messages", to="channels.channelconversation")),
|
||||
("created_by", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="created_channel_messages", to=settings.AUTH_USER_MODEL)),
|
||||
("endpoint", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name="messages", to="channels.channelendpoint")),
|
||||
("ticket", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="channel_messages", to="tickets.ticket")),
|
||||
],
|
||||
options={"ordering": ["-created_at"]},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ChannelReceipt",
|
||||
fields=[
|
||||
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||
("receipt_type", models.CharField(max_length=24)),
|
||||
("external_receipt_id", models.CharField(max_length=200)),
|
||||
("payload", models.JSONField(blank=True, default=dict)),
|
||||
("received_at", models.DateTimeField(auto_now_add=True)),
|
||||
("message", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name="receipts", to="channels.channelmessage")),
|
||||
],
|
||||
options={"ordering": ["received_at"]},
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="channelconversation",
|
||||
constraint=models.UniqueConstraint(fields=("endpoint", "external_conversation_id"), name="unique_channel_external_conversation"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="channelmessage",
|
||||
index=models.Index(fields=["endpoint", "direction", "created_at"], name="channels_ch_endpoin_30d460_idx"),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="channelmessage",
|
||||
index=models.Index(fields=["status", "created_at"], name="channels_ch_status_eeefec_idx"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="channelmessage",
|
||||
constraint=models.UniqueConstraint(condition=models.Q(("external_message_id__gt", "")), fields=("endpoint", "direction", "external_message_id"), name="unique_channel_external_message"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="channelmessage",
|
||||
constraint=models.UniqueConstraint(condition=models.Q(("idempotency_key__gt", "")), fields=("endpoint", "direction", "idempotency_key"), name="unique_channel_message_idempotency"),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="channelreceipt",
|
||||
constraint=models.UniqueConstraint(fields=("message", "receipt_type", "external_receipt_id"), name="unique_channel_message_receipt"),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,40 @@
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
from django.db.models import Q
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("channels", "0001_initial"),
|
||||
("tickets", "0014_customerreplytask_channel_approval"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="channelmessage",
|
||||
name="customer_reply_task",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="channel_messages",
|
||||
to="tickets.customerreplytask",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="channelmessage",
|
||||
name="reply_revision",
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name="channelmessage",
|
||||
constraint=models.UniqueConstraint(
|
||||
fields=("customer_reply_task", "reply_revision"),
|
||||
condition=Q(
|
||||
direction="outbound",
|
||||
customer_reply_task__isnull=False,
|
||||
),
|
||||
name="unique_channel_reply_revision",
|
||||
),
|
||||
),
|
||||
]
|
||||
1
backend/apps/channels/migrations/__init__.py
Normal file
1
backend/apps/channels/migrations/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user