fix: make support replies finish promptly
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
@@ -134,6 +135,16 @@ class SupportService:
|
|||||||
email_auth_service=self.email_auth_service,
|
email_auth_service=self.email_auth_service,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _schedule_notification(coro, error_message: str, *error_args: Any) -> None:
|
||||||
|
async def _runner():
|
||||||
|
try:
|
||||||
|
await coro
|
||||||
|
except Exception:
|
||||||
|
logger.exception(error_message, *error_args)
|
||||||
|
|
||||||
|
asyncio.create_task(_runner(), name="support-notification")
|
||||||
|
|
||||||
async def _ensure_user_allowed(self, session, user_id: int) -> User:
|
async def _ensure_user_allowed(self, session, user_id: int) -> User:
|
||||||
user = await user_dal.get_user_by_id(session, user_id)
|
user = await user_dal.get_user_by_id(session, user_id)
|
||||||
if not user or user.is_banned or not self.settings.SUPPORT_TICKETS_ENABLED:
|
if not user or user.is_banned or not self.settings.SUPPORT_TICKETS_ENABLED:
|
||||||
@@ -218,8 +229,8 @@ class SupportService:
|
|||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
if notification_decision.send_telegram or notification_decision.send_email:
|
if notification_decision.send_telegram or notification_decision.send_email:
|
||||||
try:
|
self._schedule_notification(
|
||||||
await self.notification_service.notify_support_user_reply(
|
self.notification_service.notify_support_user_reply(
|
||||||
ticket,
|
ticket,
|
||||||
message,
|
message,
|
||||||
user,
|
user,
|
||||||
@@ -227,9 +238,10 @@ class SupportService:
|
|||||||
unread_count=int(ticket.unread_admin_count or 0),
|
unread_count=int(ticket.unread_admin_count or 0),
|
||||||
send_telegram=notification_decision.send_telegram,
|
send_telegram=notification_decision.send_telegram,
|
||||||
send_email=notification_decision.send_email,
|
send_email=notification_decision.send_email,
|
||||||
)
|
),
|
||||||
except Exception:
|
"Failed to notify about support user reply %s",
|
||||||
logger.exception("Failed to notify about support user reply %s", ticket_id)
|
ticket_id,
|
||||||
|
)
|
||||||
return ticket, message
|
return ticket, message
|
||||||
|
|
||||||
async def reply_as_admin(
|
async def reply_as_admin(
|
||||||
@@ -275,10 +287,11 @@ class SupportService:
|
|||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
||||||
if user and not is_internal_note:
|
if user and not is_internal_note:
|
||||||
try:
|
self._schedule_notification(
|
||||||
await self.notification_service.notify_support_admin_reply(ticket, message, user)
|
self.notification_service.notify_support_admin_reply(ticket, message, user),
|
||||||
except Exception:
|
"Failed to notify user about support admin reply %s",
|
||||||
logger.exception("Failed to notify user about support admin reply %s", ticket_id)
|
ticket_id,
|
||||||
|
)
|
||||||
return ticket, message
|
return ticket, message
|
||||||
|
|
||||||
async def change_status(self, admin_id: int, ticket_id: int, status: str) -> SupportTicket:
|
async def change_status(self, admin_id: int, ticket_id: int, status: str) -> SupportTicket:
|
||||||
|
|||||||
@@ -93,7 +93,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function send(body) {
|
async function send(body) {
|
||||||
await supportStore.sendReply(body);
|
const sent = await supportStore.sendReply(body);
|
||||||
|
if (!sent) return;
|
||||||
reply = "";
|
reply = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,17 +193,26 @@ export function createAdminSupportStore({ api, onToast, at }) {
|
|||||||
body: JSON.stringify({ body, is_internal_note: internal }),
|
body: JSON.stringify({ body, is_internal_note: internal }),
|
||||||
});
|
});
|
||||||
if (!res?.ok) throw res;
|
if (!res?.ok) throw res;
|
||||||
state.update((s) => ({
|
state.update((s) =>
|
||||||
...s,
|
s.openedTicketId === current
|
||||||
openedTicket: res.ticket
|
? {
|
||||||
? { ...s.openedTicket, ...res.ticket, user: res.ticket.user || s.openedTicket?.user }
|
...s,
|
||||||
: s.openedTicket,
|
openedTicket: res.ticket
|
||||||
messages: [...s.messages, res.message],
|
? {
|
||||||
}));
|
...s.openedTicket,
|
||||||
await loadList();
|
...res.ticket,
|
||||||
await loadStats();
|
user: res.ticket.user || s.openedTicket?.user,
|
||||||
|
}
|
||||||
|
: s.openedTicket,
|
||||||
|
messages: res.message ? [...s.messages, res.message] : s.messages,
|
||||||
|
}
|
||||||
|
: s
|
||||||
|
);
|
||||||
|
void Promise.allSettled([loadList({ silent: true }), loadStats()]);
|
||||||
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
onToast(error?.message || at("support_send_failed", {}, "Send failed"));
|
onToast(error?.message || at("support_send_failed", {}, "Send failed"));
|
||||||
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
state.update((s) => ({ ...s, sending: false }));
|
state.update((s) => ({ ...s, sending: false }));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,13 +258,19 @@ export function createSupportStore({ api, t, showToast }) {
|
|||||||
body: JSON.stringify({ body }),
|
body: JSON.stringify({ body }),
|
||||||
});
|
});
|
||||||
if (!res?.ok) throw res;
|
if (!res?.ok) throw res;
|
||||||
state.update((s) => ({
|
state.update((s) =>
|
||||||
...s,
|
s.openedTicketId === ticketId
|
||||||
openedTicket: res.ticket || s.openedTicket,
|
? {
|
||||||
messages: [...s.messages, res.message],
|
...s,
|
||||||
}));
|
openedTicket: res.ticket || s.openedTicket,
|
||||||
await refreshUnread();
|
messages: res.message ? [...s.messages, res.message] : s.messages,
|
||||||
await loadList({ silent: true, force: true });
|
}
|
||||||
|
: s
|
||||||
|
);
|
||||||
|
void Promise.allSettled([
|
||||||
|
refreshUnread({ silent: true }),
|
||||||
|
loadList({ silent: true, force: true }),
|
||||||
|
]);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast(error?.message || t("wa_support_send_failed"));
|
showToast(error?.message || t("wa_support_send_failed"));
|
||||||
|
|||||||
Reference in New Issue
Block a user