feat: init commint

This commit is contained in:
2026-09-18 15:26:19 +08:00
parent 3b61a767a0
commit 9f47dbb5cc
95 changed files with 7712 additions and 1137 deletions

View File

@@ -1,4 +1,3 @@
from django.db import transaction
from ninja import Router
from ninja.errors import HttpError
@@ -18,6 +17,7 @@ from apps.channels.services import (
ingest_inbound_message,
queue_outbound_message,
record_channel_receipt,
retry_outbound_message,
verify_webhook_signature,
)
from apps.modelhub.crypto import encrypt_secret
@@ -182,18 +182,10 @@ def retry_channel_message(request, public_id: str):
)
if message is None:
raise HttpError(404, "出站消息不存在")
if message.status != "failed":
raise HttpError(409, "仅失败消息可以重试")
message.status = "queued"
message.error_message = ""
message.save(update_fields=["status", "error_message", "updated_at"])
def enqueue_delivery():
from apps.channels.tasks import deliver_channel_message_task
deliver_channel_message_task.delay(message.id)
transaction.on_commit(enqueue_delivery)
try:
message = retry_outbound_message(message, actor=request.user)
except ChannelError as error:
raise HttpError(409, str(error)) from error
return serialize_message(message)

View File

@@ -96,6 +96,21 @@ def ingest_inbound_message(endpoint: ChannelEndpoint, payload: dict) -> ChannelM
},
result="success",
)
if message.ticket_id:
message_id = message.id
def process_ticket_feedback() -> None:
from apps.tickets.automation import handle_customer_feedback
inbound = ChannelMessage.objects.get(id=message_id)
handle_customer_feedback(
inbound.ticket_id,
inbound.text,
channel_message_id=inbound.id,
)
transaction.on_commit(process_ticket_feedback)
return message
@@ -185,6 +200,13 @@ def deliver_outbound_message(message_id: int) -> ChannelMessage:
message.save()
if message.status == "delivered":
_confirm_delivered_reply(message)
elif message.status == "failed" and message.customer_reply_task_id:
from apps.tickets.automation import handle_customer_reply_delivery_failed
handle_customer_reply_delivery_failed(
message.customer_reply_task_id,
message.error_message,
)
OperationAuditLog.objects.create(
user=message.created_by,
module="channels",
@@ -201,6 +223,35 @@ def deliver_outbound_message(message_id: int) -> ChannelMessage:
return message
@transaction.atomic
def retry_outbound_message(message: ChannelMessage, *, actor=None) -> ChannelMessage:
"""重新投递同一条失败消息,复用原幂等键和冻结回复版本。"""
message = ChannelMessage.objects.select_for_update(of=("self",)).get(id=message.id)
if message.direction != "outbound" or message.status != "failed":
raise ChannelError("仅失败的出站消息可以重试")
message.status = "queued"
message.error_message = ""
message.save(update_fields=["status", "error_message", "updated_at"])
OperationAuditLog.objects.create(
user=actor,
module="channels",
action="message_delivery_retried",
target_type="channel_message",
target_id=str(message.public_id),
request_snapshot={"idempotency_key": message.idempotency_key},
result="success",
)
def enqueue_delivery() -> None:
from apps.channels.tasks import deliver_channel_message_task
deliver_channel_message_task.delay(message.id)
transaction.on_commit(enqueue_delivery)
return message
@transaction.atomic
def queue_outbound_message(
endpoint: ChannelEndpoint,
@@ -372,4 +423,11 @@ def record_channel_receipt(endpoint: ChannelEndpoint, payload: dict) -> ChannelR
message.save()
if message.status == "delivered":
_confirm_delivered_reply(message)
elif message.status == "failed" and message.customer_reply_task_id:
from apps.tickets.automation import handle_customer_reply_delivery_failed
handle_customer_reply_delivery_failed(
message.customer_reply_task_id,
message.error_message,
)
return receipt