Skip to content

Feat/ratebot#4

Merged
TurboRigby merged 10 commits intomainfrom
feat/ratebot
Nov 20, 2025
Merged

Feat/ratebot#4
TurboRigby merged 10 commits intomainfrom
feat/ratebot

Conversation

@TurboRigby
Copy link
Member

@TurboRigby TurboRigby commented Nov 20, 2025

Summary by CodeRabbit

Новое в этом релизе

  • New Features
    • Добавлена интеграция с Discord для отправки уведомлений о рейтингах уровней
    • Добавлена интеграция с Telegram для отправки уведомлений о рейтингах уровней
    • Реализована система событий для отслеживания действий в приложении

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
nitrocore Ready Ready Preview Comment Nov 20, 2025 11:54am

@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Обзор

Реализована система хуков для событий действий (action hooks) с добавлением типа ActionHookPayload в ActionController и диспетчеризацией событий "action:registered" и "action:level_rate". Добавлены два новых плагина Nitro для отправки уведомлений о рейтингах уровней в Discord и Telegram. Обновлены типы Nitro и внесено незначительное исправление SQL-запроса в фильтре уровней.

Изменения

Когорта / Файл(ы) Описание
Ядро системы хуков
controller/ActionController.ts, types.d.ts
Добавлена типизация ActionHookPayload и логика диспетчеризации хуков "action:registered" и "action:level_rate" после вставки действия в БД. Расширен модуль nitropack интерфейсом NitroRuntimeHooks.
Плагины уведомлений
server/plugins/plugin-discord-ratebot.ts, server/plugins/plugin-telegram-ratebot.ts
Добавлены два новых плагина, прослушивающих хук "action:level_rate" и отправляющих форматированные уведомления в Discord и Telegram с метаданными уровня и информацией о модератора.
Оптимизация запросов
controller/LevelFilter.ts
Изменена SQL-логика в case "sent": прямая ссылка на rateQueueTable.levelId вместо подзапроса на таблицу rateQueue.

Диаграмма последовательности

sequenceDiagram
    participant Client
    participant AC as ActionController
    participant DB as Database
    participant Nitro
    participant Discord
    participant Telegram

    Client->>AC: Запрос действия (например, рейтинг)
    AC->>DB: Вставка действия
    DB-->>AC: Подтверждение
    
    rect rgb(240, 248, 255)
    Note over AC,Nitro: Диспетчеризация хуков (новое)
    AC->>Nitro: dispatch("action:registered", ActionHookPayload)
    alt action === "level_rate"
        AC->>Nitro: dispatch("action:level_rate", ActionHookPayload)
    end
    end
    
    par Уведомления
        Nitro->>Discord: Отправка вебхука с информацией о рейтинге
        Discord-->>Nitro: OK
    and
        Nitro->>Telegram: Отправка сообщения в чат
        Telegram-->>Nitro: OK
    end
    
    AC-->>Client: Ответ
Loading

Оценка трудозатрат на рецензию

🎯 3 (Средний) | ⏱️ ~25 минут

Области, требующие повышенного внимания:

  • Логика обработки ошибок в обоих плагинах (plugin-discord-ratebot.ts и plugin-telegram-ratebot.ts) — валидация конфигурации, обработка сбоев API и гарантии безопасности (абсолютный URL вебхука, наличие данных уровня)
  • Корректность построения полезной нагрузки хука ActionHookPayload в ActionController (особенно deep-clone данных и правильная последовательность отправки событий)
  • Изменение SQL-логики в LevelFilter.ts — убедиться, что семантика запроса сохранена и нет регрессий в упорядочении результатов

Возможно связанные PR

  • Telegram and Discord rate bots #2 — Основной PR и полученный PR вводят одинаковые добавления кода (ActionHookPayload, диспетчеризацию хуков "action:registered"/"action:level_rate" в ActionController, новые плагины Discord/Telegram и типизацию хуков nitropack).
  • unemployed #3 — Оба PR изменяют файлы плагинов (plugin-discord-ratebot.ts и plugin-telegram-ratebot.ts), основной PR добавляет интеграцию с хуками и типизацией, полученный PR локализует реализацию плагинов на русский язык.

Рекомендуемые рецензенты

  • m41denx

Поэма

🐰✨ Хуки в системе запрыгали с радостью,
Рейтинги скачут в Discord и Telegram!
Действия ловятся в полёте свободно—
От Discord до Telegram, как по волшебству! 🚀
Плагины танцуют в гармонии строго,
Уведомленья летят в добрый час! 🌟

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive Заголовок PR 'Feat/ratebot' слишком расплывчатый и не раскрывает суть изменений; используется лишь обобщающий термин без конкретного описания функциональности. Переформулируйте заголовок, чтобы ясно описать основное изменение, например: 'Add Discord and Telegram ratebot plugins with action hooks' или 'Implement ratebot notification system for level ratings'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ratebot

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ac8888 and 041c3a4.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • controller/ActionController.ts (2 hunks)
  • controller/LevelFilter.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • controller/LevelFilter.ts
  • controller/ActionController.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
types.d.ts (1)

2-26: Расширение NitroRuntimeHooks типизировано корректно, есть замечание по export default

Подключение ActionHookPayload в декларации nitropack даёт хорошую связку типов между контроллером действий и нитро‑хуками, сами сигнатуры "action:registered" / "action:level_rate" выглядят корректно. Единственное, в конце файла в .d.ts обычно безопаснее использовать export {} вместо export default {}, чтобы не объявлять фиктивный default‑экспорт модуля и оставить файл исключительно как носитель деклараций.

controller/LevelFilter.ts (1)

173-181: Новый фильтр для режима sent семантически корректен, стоит лишь проверить план запроса

Переход на сырой SQL‑фильтр

levels.id IN (SELECT rateQueue.levelId FROM rateQueue)

даёт тот же результат, что и EXISTS‑подзапрос, с учётом того, что rateQueueTable.levelId может содержать дубликаты (они не меняют семантику IN). Код выглядит корректно и хорошо вписывается в существующий пайплайн filters. На больших объёмах данных имеет смысл посмотреть EXPLAIN/EXPLAIN ANALYZE, чтобы убедиться, что план запроса не стал хуже относительно предыдущего варианта.

Also applies to: 387-388

controller/ActionController.ts (2)

121-152: Интеграция Nitro‑хуков выглядит аккуратно, проверьте влияние на рантайм и structuredClone

Блок с useNitroApp и защитой через typeof useNitroApp === "function" + безопасный вызов useEvent() хорошо позволяет использовать контроллер и вне контекста Nitro (тесты, скрипты). Отдельно плюс за structuredClone(data) перед отправкой в хук — это защищает логированное действие от побочных мутаций в плагинах. При этом:

  • structuredClone зависит от реализации рантайма (Node/Bun); если где‑то ещё используется более старый Node/Bun, лучше явно брать его из node:util или предусмотреть фоллбек, иначе при отсутствии глобальной функции этот участок упадёт раньше, чем дойдёт до useLogger().warn(...).
  • Вызовы nitroApp.hooks.callHook(...) сейчас ожидаются (await), поэтому сетевые операции в плагинах (Discord/Telegram rate‑bot) напрямую увеличат время выполнения registerAction. Если латентность маршрутов критична, можно в будущем подумать о fire‑and‑forget/очереди для внешних уведомлений, оставив хук максимально лёгким.

36-38: Уточните семантику isModAction в ActionHookPayload — сейчас она привязана к targetId

Поле isModAction заполняется из isMod = user.$.roleId > 0, где user берётся через getOneUser({ uid: targetId }). При этом в ActionHookPayload это поле может восприниматься подписчиками как «действие совершено модератором (инициатором)». Если в вызывателях registerAction параметр uid — это именно инициатор, а targetId — объект действия (уровень, лист, пользователь и т.п.), то сейчас isModAction фактически отражает статус целевого пользователя/объекта, а не инициатора. Это может путать будущие плагины, потребляющие ActionHookPayload. Имеет смысл пересмотреть логику и, при необходимости, вычислять мод‑флаг по uid, чтобы контракт хука был однозначным.

Also applies to: 111-119, 199-210

server/plugins/plugin-discord-ratebot.ts (1)

1-233: Discord rate‑bot плагин выглядит продуманно, с хорошей защитой и логированием; есть мелкие идеи по доработке

Нравится, что вы: фильтруете только Rate:* события, ранним return отбрасывая нерелевантные/reset; аккуратно вытаскиваете srvid и конфиг (с fallback на useServerConfig), проверяете включённость модуля и обязательный абсолютный webhookUrl; оборачиваете сетевые вызовы $fetch в try/catch с логированием через useLogger(). Хелперы resolveDifficulty/resolveDemon/resolveEpic/formatCoins/translateAction тоже выглядят консистентно и дают понятный embed. Из необязательных улучшений: можно логировать что‑нибудь на debug‑уровне при отключённом модуле/отсутствии уровня, чтобы проще было диагностировать «молчание» бота, и, при желании, либо перестать отфильтровывать Rate:reset (у вас уже есть перевод в translateAction), либо удалить этот кейс из маппинга, чтобы не поддерживать мёртвый код.

server/plugins/plugin-telegram-ratebot.ts (1)

29-56: Обработка payload и конфигурации в целом удачная, но есть пара мест, где стоит чуть усилить защиту

  1. Фильтрация по Rate: и Rate:reset
    Логика с actionType.startsWith("Rate:") и suffix === "reset" достаточно прозрачна и даёт ранний выход для нерелейтивантных действий — это плюс.

  2. Разбор srvid и работа без HTTP‑контекста
    Связка tryGetEvent() + приоритет payload.srvid + fallback к getRouterParam и useServerConfig(srvid) выглядит надёжно и хорошо документирует приоритеты источников serverId; аккуратный try/catch в tryGetEvent позволяет безопасно жить в non‑request контексте.

  3. Доступ к config.ServerConfig
    Сейчас вы предполагаете, что config.ServerConfig всегда существует, и сразу обращаетесь к вложенным полям:

    if (!config.ServerConfig.EnableModules?.["telegram_ratebot"])
        return
    
    const moduleConfig = config.ServerConfig.ModuleConfig?.["telegram_ratebot"] as MaybeUndefined<TelegramRateBotConfig>

    Если когда‑то в хранилище окажется частично битый конфиг (или структура эволюционирует), это место превратится в TypeError: Cannot read properties of undefined (reading 'EnableModules'|'ModuleConfig'). Чтобы сделать код более устойчивым к таким ситуациям, можно добавить optional chaining на уровне ServerConfig:

  • if (!config.ServerConfig.EnableModules?.["telegram_ratebot"])
  •    return
    
  • const moduleConfig = config.ServerConfig.ModuleConfig?.["telegram_ratebot"] as MaybeUndefined
  • if (!config.ServerConfig?.EnableModules?.["telegram_ratebot"])
  •    return
    
  • const moduleConfig = config.ServerConfig?.ModuleConfig?.["telegram_ratebot"] as MaybeUndefined

Функциональное поведение не меняется, но вероятность падения на неожиданном формате конфига уменьшается.

4. Тихие early‑return’ы при невалидном moduleConfig  
При отсутствии `botToken`/`chatId` вы просто делаете `return`. Это безопасно, но отладка может быть неочевидной. Опционально можно добавить `warn` при включённом модуле и битом конфиге (например, логировать один раз при старте или с троттлингом), но это скорее вкусовой момент.

5. Вызов Telegram API  
Вызов `$fetch` с POST и телом‑объектом вполне ок для Telegram Bot API, ошибки корректно логируются через `useLogger().error`, так что с точки зрения устойчивости всё хорошо.





Also applies to: 38-48, 50-55, 57-84, 164-170

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used**: CodeRabbit UI

**Review profile**: CHILL

**Plan**: Pro

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9b80654e28b27b97b0d92035a8e93f099fe4a7f6 and 0ac8888ca6efd29b032ade83b97a2691a6e20506.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `bun.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `controller/ActionController.ts` (2 hunks)
* `controller/LevelFilter.ts` (2 hunks)
* `package.json` (1 hunks)
* `server/plugins/plugin-discord-ratebot.ts` (1 hunks)
* `server/plugins/plugin-telegram-ratebot.ts` (1 hunks)
* `types.d.ts` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code graph analysis (5)</summary>

<details>
<summary>types.d.ts (1)</summary><blockquote>

<details>
<summary>controller/ActionController.ts (1)</summary>

* `ActionHookPayload` (201-210)

</details>

</blockquote></details>
<details>
<summary>controller/LevelFilter.ts (2)</summary><blockquote>

<details>
<summary>drizzle/levels.ts (1)</summary>

* `levelsTable` (8-64)

</details>
<details>
<summary>drizzle/rate_queue.ts (1)</summary>

* `rateQueueTable` (6-14)

</details>

</blockquote></details>
<details>
<summary>controller/ActionController.ts (3)</summary><blockquote>

<details>
<summary>drizzle/actions.ts (2)</summary>

* `ActionData` (55-57)
* `ActionVariant` (11-11)

</details>
<details>
<summary>server/utils/useLogger.ts (1)</summary>

* `useLogger` (11-11)

</details>
<details>
<summary>server/utils/useDrizzle.ts (1)</summary>

* `Database` (67-67)

</details>

</blockquote></details>
<details>
<summary>server/plugins/plugin-telegram-ratebot.ts (5)</summary><blockquote>

<details>
<summary>controller/ActionController.ts (1)</summary>

* `ActionHookPayload` (201-210)

</details>
<details>
<summary>server/utils/useLogger.ts (1)</summary>

* `useLogger` (11-11)

</details>
<details>
<summary>server/utils/useServerConfig.ts (1)</summary>

* `useServerConfig` (5-15)

</details>
<details>
<summary>controller/LevelController.ts (1)</summary>

* `LevelController` (9-187)

</details>
<details>
<summary>controller/Level.ts (1)</summary>

* `LevelWithUser` (9-11)

</details>

</blockquote></details>
<details>
<summary>server/plugins/plugin-discord-ratebot.ts (5)</summary><blockquote>

<details>
<summary>controller/ActionController.ts (1)</summary>

* `ActionHookPayload` (201-210)

</details>
<details>
<summary>server/utils/useLogger.ts (1)</summary>

* `useLogger` (11-11)

</details>
<details>
<summary>server/utils/useServerConfig.ts (1)</summary>

* `useServerConfig` (5-15)

</details>
<details>
<summary>controller/LevelController.ts (1)</summary>

* `LevelController` (9-187)

</details>
<details>
<summary>controller/Level.ts (1)</summary>

* `LevelWithUser` (9-11)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (2)</summary><blockquote>

<details>
<summary>package.json (1)</summary><blockquote>

`22-48`: **Проверьте совместимость обновлённых версий зависимостей**

Вы обновили несколько ключевых пакетов (drizzle-kit / drizzle-orm, nitropack, @vercel/edge-config, testcontainers и т.п.). На уровне `package.json` всё выглядит нормально, но такие апдейты часто тянут мелкие breaking‑changes, поэтому имеет смысл прогнать полный тестовый прогон и миграции на всех целевых окружениях и, при необходимости, свериться с changelog‑ами этих библиотек.

</blockquote></details>
<details>
<summary>server/plugins/plugin-telegram-ratebot.ts (1)</summary><blockquote>

`19-27`: **Инициализация Nitro‑плагина и регистрация hook‑а выглядят корректно**

Подключение к `action:level_rate` с асинхронным обработчиком и обёрткой в `try/catch` выглядит аккуратно: ошибки внутри нотификаций не «роняют» основной flow, логируются через `useLogger().warn`. Никаких проблем по структуре или семантике здесь не вижу.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@TurboRigby TurboRigby merged commit ef27ff1 into main Nov 20, 2025
5 checks passed
@TurboRigby TurboRigby deleted the feat/ratebot branch November 20, 2025 22:51
@m41denx m41denx restored the feat/ratebot branch December 10, 2025 11:04
@coderabbitai coderabbitai bot mentioned this pull request Dec 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants