feat(vpn): монитор актуальности Яндекс Телемост + инструкция про выход из встречи
- INSTRUCTIONS_TEXT: добавлено требование выйти из встречи, а не завершать её - vpn.db.ts: findAllActiveVpnTasks для поиска активных VPN-задач - vpn.service.ts: checkVpnRoomsValidity — периодическая проверка комнат, concurrency=5 - vpn-bot.service.ts: findVpnBotConversationId и notifyVpnRoomExpired - server/index.ts: worker каждые 6 часов, уведомление пользователю о протухшей ссылке
This commit is contained in:
@@ -2,7 +2,7 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import { db } from "../db";
|
||||
import { conversationMessages, conversationMembers, bots, type Bot, type User } from "@shared/schema";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { eq, and, sql } from "drizzle-orm";
|
||||
import { eventBus } from "../routes/shared";
|
||||
import { enrichMessage, getMembersForSSE } from "../routes/messenger.helpers";
|
||||
import { notificationService } from "../services/notification.service";
|
||||
@@ -20,7 +20,8 @@ const INSTRUCTIONS_TEXT = `Привет! Для получения корпор
|
||||
|
||||
1. Открой Яндекс Телемост (приложение или https://telemost.yandex.ru).
|
||||
2. Создай новую видеовстречу.
|
||||
3. Пришли сюда ссылку на встречу. Примеры того, что подходит:
|
||||
3. **Важно:** после создания **выйди** из встречи, а не **завершай** её. Тогда ссылка останется активной и будет работать для VPN.
|
||||
4. Пришли сюда ссылку на встречу. Примеры того, что подходит:
|
||||
|
||||
• https://telemost.yandex.ru/j/abc123def456
|
||||
• telemost.yandex.ru/j/abc123def456
|
||||
@@ -316,3 +317,46 @@ export async function handleVpnBotCallback({
|
||||
organizationId,
|
||||
);
|
||||
}
|
||||
|
||||
// ── Room expiry notifications ─────────────────────────────────────────────────
|
||||
|
||||
async function findVpnBotConversationId(
|
||||
organizationId: number,
|
||||
userId: number,
|
||||
): Promise<number | null> {
|
||||
const botId = await getVpnBotId(organizationId);
|
||||
if (!botId) return null;
|
||||
|
||||
const rows = await db.execute(sql`
|
||||
SELECT c.id
|
||||
FROM conversations c
|
||||
JOIN conversation_members cm ON cm.conversation_id = c.id
|
||||
WHERE c.type = 'bot_direct'
|
||||
AND c.bot_id = ${botId}
|
||||
AND c.organization_id = ${organizationId}
|
||||
AND cm.user_id = ${userId}
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
interface Row { id: number }
|
||||
const row = rows.rows[0] as unknown as Row | undefined;
|
||||
return row?.id ?? null;
|
||||
}
|
||||
|
||||
export async function notifyVpnRoomExpired(
|
||||
organizationId: number,
|
||||
userId: number,
|
||||
roomUrl: string,
|
||||
): Promise<void> {
|
||||
const conversationId = await findVpnBotConversationId(organizationId, userId);
|
||||
if (!conversationId) {
|
||||
console.warn(`[VPN Bot] no bot_direct conversation found for user ${userId} in org ${organizationId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await sendVpnBotMessage(
|
||||
conversationId,
|
||||
`⚠️ Ссылка на встречу Яндекс Телемост больше недействительна:\n${roomUrl}\n\nСоздайте новую встречу в Яндекс Телемост (выйдите из неё, не завершая) и пришлите новую ссылку.`,
|
||||
organizationId,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user