Закрыты задачи бэклога по неочевидному поведению UI при ошибках отправки сообщений и блокировках со стороны Message-safety + добалено ограничение на размер сообщения
This commit is contained in:
@@ -14,6 +14,7 @@ from sqlalchemy.dialects.postgresql import insert
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.auth import Principal
|
||||
from app.chat_settings import CHAT_MESSAGE_MAX_LENGTH_KEY, validate_chat_settings
|
||||
from app.db import (
|
||||
AppSetting,
|
||||
AuditEvent,
|
||||
@@ -52,6 +53,26 @@ from app.schemas import (
|
||||
)
|
||||
from app.settings import Settings
|
||||
|
||||
MESSAGE_SAFETY_REPLIES = {
|
||||
"text": (
|
||||
"К сожалению, ваше сообщение не соответствует правилам данного чата "
|
||||
"и не может быть отправлено. Попробуйте переформулировать."
|
||||
),
|
||||
"file": "К сожалению, ваш документ не прошел проверку и не может быть доставлен.",
|
||||
}
|
||||
|
||||
|
||||
def safety_reply_message(dialog_id: uuid.UUID, content_kind: str) -> Message:
|
||||
return Message(
|
||||
dialog_id=dialog_id,
|
||||
sender_type="company",
|
||||
content_kind="text",
|
||||
text=MESSAGE_SAFETY_REPLIES[content_kind],
|
||||
safety_status="allowed",
|
||||
delivery_status="delivered",
|
||||
occurred_at=datetime.now(UTC),
|
||||
)
|
||||
|
||||
|
||||
class DomainError(Exception):
|
||||
def __init__(self, code: str, status: int, message: str, details: dict[str, Any] | None = None):
|
||||
@@ -100,6 +121,7 @@ REQUIRED_SETTINGS = {
|
||||
"rate_limit.notifications_action.per_user",
|
||||
"rate_limit.notification_upload.per_user",
|
||||
"rate_limit.notifications_public.per_ip",
|
||||
CHAT_MESSAGE_MAX_LENGTH_KEY,
|
||||
} | OTP_SETTING_KEYS
|
||||
|
||||
|
||||
@@ -168,11 +190,12 @@ async def load_settings(session: AsyncSession) -> SettingsSnapshot:
|
||||
f"OTP settings must have integer type and be private: {invalid_metadata}"
|
||||
)
|
||||
validate_otp_settings(values)
|
||||
validate_chat_settings(values)
|
||||
except ValueError as error:
|
||||
raise DomainError(
|
||||
"dependency_unavailable",
|
||||
503,
|
||||
"OTP settings are invalid",
|
||||
"Application settings are invalid",
|
||||
{"reason": str(error)},
|
||||
) from error
|
||||
version = hashlib.sha256(json.dumps(values, sort_keys=True).encode()).hexdigest()[:24]
|
||||
@@ -749,6 +772,7 @@ async def send_message(
|
||||
body: MessageRequest,
|
||||
idem_key: str,
|
||||
context: AuditContext,
|
||||
business: SettingsSnapshot,
|
||||
settings: Settings,
|
||||
safety: SafetyClient,
|
||||
openlines: OpenLinesClient,
|
||||
@@ -823,6 +847,14 @@ async def send_message(
|
||||
text, kind = "", "file"
|
||||
else:
|
||||
text, kind = unicodedata.normalize("NFKC", body.text).strip(), "text"
|
||||
max_length = business.integer(CHAT_MESSAGE_MAX_LENGTH_KEY)
|
||||
if len(text) > max_length:
|
||||
raise DomainError(
|
||||
"message_too_long",
|
||||
422,
|
||||
"Message exceeds the configured maximum length",
|
||||
{"max_length": max_length},
|
||||
)
|
||||
message = Message(
|
||||
id=message_id,
|
||||
dialog_id=dialog_id,
|
||||
@@ -891,6 +923,9 @@ async def send_message(
|
||||
message.text = ""
|
||||
message.safety_status = "blocked"
|
||||
message.delivery_status = "rejected"
|
||||
reply = safety_reply_message(dialog_id, kind)
|
||||
session.add(reply)
|
||||
dialog.last_message_at = reply.occurred_at
|
||||
if attachment and attachment.quarantine_object_key:
|
||||
attachment.scan_status = "infected"
|
||||
await s3.delete_quarantine(attachment.quarantine_object_key)
|
||||
@@ -915,6 +950,8 @@ async def send_message(
|
||||
}
|
||||
await session.commit()
|
||||
await publish_message_status(fanout, message, settings)
|
||||
await publish_message(fanout, reply, settings)
|
||||
await publish_dialog_status(fanout, dialog)
|
||||
raise DomainError("message_blocked", 422, "Message was blocked by safety policy")
|
||||
if verdict["_status"] != 200:
|
||||
raise DependencyFailure()
|
||||
|
||||
Reference in New Issue
Block a user