feat: add enterprise identity and channel integrations

This commit is contained in:
hailin
2026-07-27 19:03:42 +08:00
parent d93cb75c10
commit e69368a2f3
44 changed files with 5045 additions and 69 deletions

View 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"),
),
]

View File

@@ -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",
),
),
]

View File

@@ -0,0 +1 @@