feat: Add Discord and Telegram ratebot plugins to send level rating n…#6
feat: Add Discord and Telegram ratebot plugins to send level rating n…#6TurboRigby merged 2 commits intofeat/eventhooksfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the ОбзорДобавлены два новых модуля Discord и Telegram rate bot для сервера. Оба плагина прослушивают события Изменения
Диаграмма последовательностиsequenceDiagram
participant Client
participant ActionController
participant DiscordPlugin as Discord Plugin
participant LevelController
participant DiscordAPI as Discord Webhook
Client->>ActionController: level_rate action
ActionController->>DiscordPlugin: trigger level_rate event
DiscordPlugin->>DiscordPlugin: validate action type<br/>(must start with "Rate:")
DiscordPlugin->>DiscordPlugin: check config<br/>(discord_ratebot enabled)
DiscordPlugin->>LevelController: fetch level data
LevelController-->>DiscordPlugin: level data
DiscordPlugin->>DiscordPlugin: build webhook payload<br/>(difficulty, epic, coins, etc.)
DiscordPlugin->>DiscordAPI: POST webhook URL<br/>(embed message)
DiscordAPI-->>DiscordPlugin: response
DiscordPlugin-->>Client: log success/error
sequenceDiagram
participant Client
participant ActionController
participant TelegramPlugin as Telegram Plugin
participant LevelController
participant TelegramAPI as Telegram Bot API
Client->>ActionController: level_rate action
ActionController->>TelegramPlugin: trigger level_rate event
TelegramPlugin->>TelegramPlugin: validate action type<br/>(must start with "Rate:")
TelegramPlugin->>TelegramPlugin: check config<br/>(telegram_ratebot enabled,<br/>botToken, chatId present)
TelegramPlugin->>LevelController: fetch level data
LevelController-->>TelegramPlugin: level data
TelegramPlugin->>TelegramPlugin: build Telegram message<br/>(moderator, level details,<br/>difficulty, stats)
TelegramPlugin->>TelegramAPI: send message<br/>(botToken, chatId, text)
TelegramAPI-->>TelegramPlugin: response
TelegramPlugin-->>Client: log success/error
Оценка трудоёмкости проверки кода🎯 3 (Умеренная) | ⏱️ ~25 минут
Связанные pull requests
Рекомендуемые рецензенты
Стихотворение
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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. Comment |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
server/plugins/plugin-telegram-ratebot.ts (2)
66-73: Рекомендуется добавить таймаут для запроса к Telegram API.Отсутствие таймаута может привести к зависанию запроса при проблемах с сетью или недоступности Telegram API.
try { await $fetch(`${telegramBase}/bot${moduleConfig.botToken}/sendMessage`, { method: "POST" as any, - body + body, + timeout: 10000 }) } catch (error) {
146-152: Логика formatCoins отличается от Discord-плагина.В Telegram плагине используется формат
${verified}/${userCoins} подтверждены, а в Discord —${verified}/${userCoins} verified. Приverified >= userCoinsтакже различается вывод. Рекомендуется унифицировать логику.server/plugins/plugin-discord-ratebot.ts (2)
75-82: Рекомендуется добавить таймаут для запроса к Discord API.Аналогично Telegram-плагину, отсутствие таймаута может привести к зависанию.
try { await $fetch(moduleConfig.webhookUrl, { method: "POST" as any, - body: webhookBody + body: webhookBody, + timeout: 10000 }) } catch (error) {
136-156: Недостижимый код в resolveDifficulty.Строка 155 (
return { label: \${stars}★`, color: difficultyPalette.normal }`) недостижима — все значения stars уже обработаны в предыдущих условиях.if (stars >= 10) { const demonLabel = resolveDemon(demonDifficulty) return { label: demonLabel, color: difficultyPalette.demon } } - return { label: `${stars}★`, color: difficultyPalette.normal } + // Все значения stars обработаны выше + return { label: "Unknown", color: difficultyPalette.normal } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
server/plugins/plugin-discord-ratebot.ts(1 hunks)server/plugins/plugin-telegram-ratebot.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
server/plugins/plugin-telegram-ratebot.ts (5)
server/utils/useSDK.ts (1)
useSDK(11-11)drizzle/actions.ts (1)
ActionData(55-57)server/utils/useLogger.ts (1)
useLogger(11-11)controller/LevelController.ts (1)
LevelController(9-187)controller/Level.ts (1)
LevelWithUser(9-11)
server/plugins/plugin-discord-ratebot.ts (5)
server/utils/useSDK.ts (1)
useSDK(11-11)drizzle/actions.ts (1)
ActionData(55-57)server/utils/useLogger.ts (1)
useLogger(11-11)controller/LevelController.ts (1)
LevelController(9-187)controller/Level.ts (1)
LevelWithUser(9-11)
🔇 Additional comments (2)
server/plugins/plugin-telegram-ratebot.ts (1)
19-27: Обработка ошибок выглядит хорошо.Плагин корректно оборачивает вызов в try-catch и логирует предупреждение при ошибке. Структура соответствует аналогичному Discord-плагину.
server/plugins/plugin-discord-ratebot.ts (1)
85-134: Функция createWebhookBody реализована корректно.Хорошо структурированный embed с полями, условное исключение Epic Tier, поддержка опциональных настроек (mention, username, avatar).
| if (!moduleConfig.webhookUrl.startsWith("http")) | ||
| throw new Error("Webhook URL must be absolute") |
There was a problem hiding this comment.
Слабая валидация URL вебхука.
Проверка startsWith("http") пропустит как http://, так и https://. Discord вебхуки должны использовать HTTPS. Также стоит проверить, что URL ведёт на домен Discord.
- if (!moduleConfig.webhookUrl.startsWith("http"))
- throw new Error("Webhook URL must be absolute")
+ if (!moduleConfig.webhookUrl.startsWith("https://discord.com/api/webhooks/") &&
+ !moduleConfig.webhookUrl.startsWith("https://discordapp.com/api/webhooks/"))
+ throw new Error("Invalid Discord webhook URL")🤖 Prompt for AI Agents
In server/plugins/plugin-discord-ratebot.ts around lines 57-58, the current
check only uses startsWith("http") which allows non-HTTPS and non-Discord URLs;
replace with robust validation: parse the URL using the URL constructor, ensure
protocol === "https:", validate hostname is a Discord webhook host (e.g.,
endsWith("discord.com") or endsWith("discordapp.com")), and optionally verify
the pathname matches the webhook pattern (contains "/api/webhooks/"); if any
check fails, throw a clear Error("Invalid Discord webhook URL: must be an
https:// Discord webhook URL").
| const resolveDemon = (value: number) => { | ||
| switch (value) { | ||
| case 0: | ||
| return "Easy Demon" | ||
| case 1: | ||
| return "Medium Demon" | ||
| case 2: | ||
| return "Hard Demon" | ||
| case 4: | ||
| return "Extreme Demon" | ||
| default: | ||
| return "Insane Demon" | ||
| } | ||
| } |
There was a problem hiding this comment.
Маппинг демонов отличается от Telegram-плагина.
Discord использует case 0 → Easy Demon, а Telegram использует 0 → Hard Demon. Это критическое расхождение, которое нужно исправить в одном из плагинов (см. комментарий в Telegram-плагине).
🤖 Prompt for AI Agents
In server/plugins/plugin-discord-ratebot.ts around lines 158–171, the demon
difficulty mapping currently uses case 0 → "Easy Demon" which differs from the
Telegram plugin (where 0 → "Hard Demon"); update the switch so the Discord
plugin uses the same numeric→label mapping as the Telegram plugin (i.e., change
the case labels/returns to match Telegram’s mapping), run/adjust any tests or
consumers that depend on these labels, and add a brief inline comment noting
that this mapping must stay consistent across Discord and Telegram plugins.
| const describeDifficulty = (stars: number, demonDifficulty: number): DifficultyDescriptor => { | ||
| if (!stars) | ||
| return { name: "Unrated", stars: 0 } | ||
| if (stars === 1) | ||
| return { name: "Auto", stars } | ||
| if (stars === 2) | ||
| return { name: "Easy", stars } | ||
| if (stars === 3) | ||
| return { name: "Normal", stars } | ||
| if (stars === 4 || stars === 5) | ||
| return { name: "Hard", stars } | ||
| if (stars === 6 || stars === 7) | ||
| return { name: "Harder", stars } | ||
| if (stars === 8 || stars === 9) | ||
| return { name: "Insane", stars } | ||
| if (stars >= 10) | ||
| return { name: resolveDemonLabel(demonDifficulty), stars } | ||
| return { name: `${stars}★`, stars } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n server/plugins/plugin-telegram-ratebot.ts | sed -n '102,135p'Repository: RigbyHost/NitroCore
Length of output: 1346
🏁 Script executed:
fd -e ts -name "*discord*" -path "*/plugins/*"Repository: RigbyHost/NitroCore
Length of output: 293
🏁 Script executed:
fd -e ts -name "*.ts" -path "*/plugins/*" | head -20Repository: RigbyHost/NitroCore
Length of output: 293
🏁 Script executed:
fd -type f -name "*discord*" server/plugins/Repository: RigbyHost/NitroCore
Length of output: 233
🏁 Script executed:
ls -la server/plugins/Repository: RigbyHost/NitroCore
Length of output: 686
🏁 Script executed:
cat -n server/plugins/plugin-discord-ratebot.tsRepository: RigbyHost/NitroCore
Length of output: 7525
🏁 Script executed:
rg "demonDifficulty" server/plugins/ -C 2Repository: RigbyHost/NitroCore
Length of output: 2615
Remove unreachable code and align demon difficulty mapping with Discord plugin.
Line 119 is unreachable—all star values from 0 to 10+ are handled by the preceding conditions. Additionally, resolveDemonLabel uses inconsistent demon difficulty mappings compared to the Discord plugin's resolveDemon:
- Telegram:
0 → Hard Demon,3 → Easy Demon,4 → Medium Demon,6 → Extreme Demon - Discord:
0 → Easy Demon,1 → Medium Demon,2 → Hard Demon,4 → Extreme Demon
This causes the same difficulty level to display differently across channels.
Update the function to remove the unreachable fallback and align the mapping:
const describeDifficulty = (stars: number, demonDifficulty: number): DifficultyDescriptor => {
if (!stars)
return { name: "Unrated", stars: 0 }
if (stars === 1)
return { name: "Auto", stars }
if (stars === 2)
return { name: "Easy", stars }
if (stars === 3)
return { name: "Normal", stars }
if (stars === 4 || stars === 5)
return { name: "Hard", stars }
if (stars === 6 || stars === 7)
return { name: "Harder", stars }
if (stars === 8 || stars === 9)
return { name: "Insane", stars }
- if (stars >= 10)
- return { name: resolveDemonLabel(demonDifficulty), stars }
- return { name: `${stars}★`, stars }
+ return { name: resolveDemonLabel(demonDifficulty), stars }
}
const resolveDemonLabel = (value: number) => {
- const map: Record<number, string> = {
- 3: "Easy Demon",
- 4: "Medium Demon",
- 0: "Hard Demon",
- 5: "Insane Demon",
- 6: "Extreme Demon",
- }
- return map[value] || "Insane Demon"
+ switch (value) {
+ case 0:
+ return "Easy Demon"
+ case 1:
+ return "Medium Demon"
+ case 2:
+ return "Hard Demon"
+ case 4:
+ return "Extreme Demon"
+ default:
+ return "Insane Demon"
+ }
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In server/plugins/plugin-telegram-ratebot.ts around lines 102 to 120, remove the
unreachable final fallback and update the demon-label mapping to match the
Discord plugin: ensure stars 0→Unrated, 1→Auto, 2→Easy, 3→Normal, 4-5→Hard,
6-7→Harder, 8-9→Insane, and for stars >=10 call resolveDemonLabel but change
resolveDemonLabel to map demonDifficulty 0→Easy Demon, 1→Medium Demon, 2→Hard
Demon, 4→Extreme Demon (matching Discord); delete the unreachable return and
ensure no star values are left unhandled.
…otifications.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.