feat/fix/rf: add types, no api key handling in weather cmd, misc fixes

This commit is contained in:
Aidan 2025-04-29 20:02:18 -04:00
parent 19ce5295b1
commit 8de4f4067e
8 changed files with 84 additions and 47 deletions

View File

@ -4,12 +4,13 @@ import { isOnSpamWatch } from '../spamwatch/spamwatch';
import spamwatchMiddlewareModule from '../spamwatch/Middleware'; import spamwatchMiddlewareModule from '../spamwatch/Middleware';
import axios from 'axios'; import axios from 'axios';
import verifyInput from '../plugins/verifyInput'; import verifyInput from '../plugins/verifyInput';
import { Context, Telegraf } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch); const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
export default (bot) => { export default (bot: Telegraf<Context>) => {
bot.command("http", spamwatchMiddleware, async (ctx) => { bot.command("http", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ')[1]; const userInput = ctx.message.text.split(' ')[1];
const apiUrl = Resources.httpApi; const apiUrl = Resources.httpApi;
const { invalidCode } = Strings.httpCodes const { invalidCode } = Strings.httpCodes
@ -31,11 +32,13 @@ export default (bot) => {
.replace("{description}", codeInfo.description); .replace("{description}", codeInfo.description);
await ctx.reply(message, { await ctx.reply(message, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} else { } else {
await ctx.reply(Strings.httpCodes.notFound, { await ctx.reply(Strings.httpCodes.notFound, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
@ -43,13 +46,14 @@ export default (bot) => {
const message = Strings.httpCodes.fetchErr.replace("{error}", error); const message = Strings.httpCodes.fetchErr.replace("{error}", error);
ctx.reply(message, { ctx.reply(message, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
}); });
bot.command("httpcat", spamwatchMiddleware, async (ctx) => { bot.command("httpcat", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(/\s+/g, ''); const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(/\s+/g, '');
const { invalidCode } = Strings.httpCodes const { invalidCode } = Strings.httpCodes
@ -63,11 +67,13 @@ export default (bot) => {
await ctx.replyWithPhoto(apiUrl, { await ctx.replyWithPhoto(apiUrl, {
caption: `🐱 ${apiUrl}`, caption: `🐱 ${apiUrl}`,
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} catch (error) { } catch (error) {
ctx.reply(Strings.catImgErr, { ctx.reply(Strings.catImgErr, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} }

View File

@ -1,64 +1,70 @@
import { getStrings } from '../plugins/checklang'; import { getStrings } from '../plugins/checklang';
import { isOnSpamWatch } from '../spamwatch/spamwatch'; import { isOnSpamWatch } from '../spamwatch/spamwatch';
import spamwatchMiddlewareModule from '../spamwatch/Middleware'; import spamwatchMiddlewareModule from '../spamwatch/Middleware';
import { Context, Telegraf } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch); const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
async function getUserInfo(ctx) { async function getUserInfo(ctx: Context & { message: { text: string } }) {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
let lastName = ctx.from.last_name; let lastName = ctx.from?.last_name;
if (lastName === undefined) { if (lastName === undefined) {
lastName = " "; lastName = " ";
} }
const userInfo = Strings.userInfo const userInfo = Strings.userInfo
.replace('{userName}', `${ctx.from.first_name} ${lastName}` || Strings.varStrings.varUnknown) .replace('{userName}', `${ctx.from?.first_name} ${lastName}` || Strings.varStrings.varUnknown)
.replace('{userId}', ctx.from.id || Strings.varStrings.varUnknown) .replace('{userId}', ctx.from?.id || Strings.varStrings.varUnknown)
.replace('{userHandle}', ctx.from.username ? `@${ctx.from.username}` : Strings.varStrings.varNone) .replace('{userHandle}', ctx.from?.username ? `@${ctx.from?.username}` : Strings.varStrings.varNone)
.replace('{userPremium}', ctx.from.is_premium ? Strings.varStrings.varYes : Strings.varStrings.varNo) .replace('{userPremium}', ctx.from?.is_premium ? Strings.varStrings.varYes : Strings.varStrings.varNo)
.replace('{userLang}', ctx.from.language_code || Strings.varStrings.varUnknown); .replace('{userLang}', ctx.from?.language_code || Strings.varStrings.varUnknown);
return userInfo; return userInfo;
} }
async function getChatInfo(ctx) { async function getChatInfo(ctx: Context & { message: { text: string } }) {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
if (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup') { if (ctx.chat?.type === 'group' || ctx.chat?.type === 'supergroup') {
const chatInfo = Strings.chatInfo const chatInfo = Strings.chatInfo
.replace('{chatId}', ctx.chat.id || Strings.varStrings.varUnknown) .replace('{chatId}', ctx.chat?.id || Strings.varStrings.varUnknown)
.replace('{chatName}', ctx.chat.title || Strings.varStrings.varUnknown) .replace('{chatName}', ctx.chat?.title || Strings.varStrings.varUnknown)
.replace('{chatHandle}', ctx.chat.username ? `@${ctx.chat.username}` : Strings.varStrings.varNone) // @ts-ignore
.replace('{chatMembersCount}', await ctx.getChatMembersCount(ctx.chat.id || Strings.varStrings.varUnknown)) .replace('{chatHandle}', ctx.chat?.username ? `@${ctx.chat?.username}` : Strings.varStrings.varNone)
.replace('{chatType}', ctx.chat.type || Strings.varStrings.varUnknown) .replace('{chatMembersCount}', await ctx.getChatMembersCount())
.replace('{isForum}', ctx.chat.is_forum ? Strings.varStrings.varYes : Strings.varStrings.varNo); .replace('{chatType}', ctx.chat?.type || Strings.varStrings.varUnknown)
// @ts-ignore
.replace('{isForum}', ctx.chat?.is_forum ? Strings.varStrings.varYes : Strings.varStrings.varNo);
return chatInfo; return chatInfo;
} else { } else {
return ctx.reply( return ctx.reply(
Strings.groupOnly, { Strings.groupOnly, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} }
} }
export default (bot) => { export default (bot: Telegraf<Context>) => {
bot.command('chatinfo', spamwatchMiddleware, async (ctx) => { bot.command('chatinfo', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const chatInfo = await getChatInfo(ctx); const chatInfo = await getChatInfo(ctx);
ctx.reply( ctx.reply(
chatInfo, { chatInfo, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
} }
); );
}); });
bot.command('userinfo', spamwatchMiddleware, async (ctx) => { bot.command('userinfo', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const userInfo = await getUserInfo(ctx); const userInfo = await getUserInfo(ctx);
ctx.reply( ctx.reply(
userInfo, { userInfo, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
reply_to_message_id: ctx.message.message_id, // @ts-ignore
reply_to_message_id: ctx.message.message_id
} }
); );
}); });

View File

@ -4,6 +4,7 @@ import { isOnSpamWatch } from '../spamwatch/spamwatch';
import spamwatchMiddlewareModule from '../spamwatch/Middleware'; import spamwatchMiddlewareModule from '../spamwatch/Middleware';
import axios from 'axios'; import axios from 'axios';
import verifyInput from '../plugins/verifyInput'; import verifyInput from '../plugins/verifyInput';
import { Telegraf, Context } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch); const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
@ -50,19 +51,20 @@ function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1); return string.charAt(0).toUpperCase() + string.slice(1);
} }
export default (bot) => { export default (bot: Telegraf<Context>) => {
bot.command("mlp", spamwatchMiddleware, async (ctx) => { bot.command("mlp", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
ctx.reply(Strings.ponyApi.helpDesc, { ctx.reply(Strings.ponyApi.helpDesc, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true, disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}); });
bot.command("mlpchar", spamwatchMiddleware, async (ctx) => { bot.command("mlpchar", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+"); const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+");
const { noCharName } = Strings.ponyApi const { noCharName } = Strings.ponyApi
@ -116,12 +118,14 @@ export default (bot) => {
ctx.replyWithPhoto(charactersArray[0].image[0], { ctx.replyWithPhoto(charactersArray[0].image[0], {
caption: `${result}`, caption: `${result}`,
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true, disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} else { } else {
ctx.reply(Strings.ponyApi.noCharFound, { ctx.reply(Strings.ponyApi.noCharFound, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
@ -129,13 +133,14 @@ export default (bot) => {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message); const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, { ctx.reply(message, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
}); });
bot.command("mlpep", spamwatchMiddleware, async (ctx) => { bot.command("mlpep", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+"); const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+");
const { noEpisodeNum } = Strings.ponyApi const { noEpisodeNum } = Strings.ponyApi
@ -184,12 +189,14 @@ export default (bot) => {
ctx.replyWithPhoto(episodeArray[0].image, { ctx.replyWithPhoto(episodeArray[0].image, {
caption: `${result}`, caption: `${result}`,
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true, disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} else { } else {
ctx.reply(Strings.ponyApi.noEpisodeFound, { ctx.reply(Strings.ponyApi.noEpisodeFound, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
@ -197,13 +204,14 @@ export default (bot) => {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message); const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, { ctx.reply(message, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
}); });
bot.command("mlpcomic", spamwatchMiddleware, async (ctx) => { bot.command("mlpcomic", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from.language_code); const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+"); const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+");
const { noComicName } = Strings.ponyApi const { noComicName } = Strings.ponyApi
@ -257,12 +265,14 @@ export default (bot) => {
ctx.replyWithPhoto(comicArray[0].image, { ctx.replyWithPhoto(comicArray[0].image, {
caption: `${result}`, caption: `${result}`,
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true, disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} else { } else {
ctx.reply(Strings.ponyApi.noComicFound, { ctx.reply(Strings.ponyApi.noComicFound, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };
@ -270,6 +280,7 @@ export default (bot) => {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message); const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, { ctx.reply(message, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
}; };

View File

@ -3,12 +3,14 @@ import { getStrings } from '../plugins/checklang';
import { isOnSpamWatch } from '../spamwatch/spamwatch'; import { isOnSpamWatch } from '../spamwatch/spamwatch';
import spamwatchMiddlewareModule from '../spamwatch/Middleware'; import spamwatchMiddlewareModule from '../spamwatch/Middleware';
import axios from 'axios'; import axios from 'axios';
import { Telegraf, Context } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch); const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
export default (bot) => { export default (bot: Telegraf<Context>) => {
bot.command(["rpony", "randompony", "mlpart"], spamwatchMiddleware, async (ctx) => { // TODO: this would greatly benefit from a loading message
const Strings = getStrings(ctx.from.language_code); bot.command(["rpony", "randompony", "mlpart"], spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from?.language_code || 'en');
try { try {
const response = await axios(Resources.randomPonyApi); const response = await axios(Resources.randomPonyApi);
let tags: string[] = []; let tags: string[] = [];
@ -24,12 +26,14 @@ export default (bot) => {
ctx.replyWithPhoto(response.data.pony.representations.full, { ctx.replyWithPhoto(response.data.pony.representations.full, {
caption: `${response.data.pony.sourceURL}\n\n${tags.length > 0 ? tags.join(', ') : ''}`, caption: `${response.data.pony.sourceURL}\n\n${tags.length > 0 ? tags.join(', ') : ''}`,
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
} catch (error) { } catch (error) {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message); const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, { ctx.reply(message, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id reply_to_message_id: ctx.message.message_id
}); });
return; return;

View File

@ -21,10 +21,10 @@ const statusEmojis = {
43: '❄️', 44: 'n/a', 45: '🌧', 46: '🌨', 47: '🌩' 43: '❄️', 44: 'n/a', 45: '🌧', 46: '🌨', 47: '🌩'
}; };
const getStatusEmoji = (statusCode) => statusEmojis[statusCode] || 'n/a'; const getStatusEmoji = (statusCode: number) => statusEmojis[statusCode] || 'n/a';
function getLocaleUnit(countryCode) { function getLocaleUnit(countryCode: string) {
const fahrenheitCountries = ['US', 'BS', 'BZ', 'KY', 'LR']; const fahrenheitCountries: string[] = ['US', 'BS', 'BZ', 'KY', 'LR'];
if (fahrenheitCountries.includes(countryCode)) { if (fahrenheitCountries.includes(countryCode)) {
return { temperatureUnit: 'F', speedUnit: 'mph', apiUnit: 'e' }; return { temperatureUnit: 'F', speedUnit: 'mph', apiUnit: 'e' };
@ -44,10 +44,18 @@ export default (bot) => {
return; return;
} }
const location = userInput; const location: string = userInput;
const apiKey = process.env.weatherKey; const apiKey: string = process.env.weatherKey || '';
if (!apiKey || apiKey === "InsertYourWeatherDotComApiKeyHere") {
return ctx.reply(Strings.weatherStatus.apiKeyErr, {
parse_mode: "Markdown",
reply_to_message_id: ctx.message.message_id
});
}
try { try {
// TODO: this also needs to be sanitized and validated
const locationResponse = await axios.get(`${Resources.weatherApi}/location/search`, { const locationResponse = await axios.get(`${Resources.weatherApi}/location/search`, {
params: { params: {
apiKey: apiKey, apiKey: apiKey,

View File

@ -49,7 +49,8 @@
"provideLocation": "*Please provide a location.*", "provideLocation": "*Please provide a location.*",
"invalidLocation": "*Invalid location. Try again.*", "invalidLocation": "*Invalid location. Try again.*",
"resultMsg": "*Weather in {addressFirst}:*\n\n*Status:* `{getStatusEmoji(iconCode)} {wxPhraseLong}`\n*Temperature:* `{temperature} °{temperatureUnit}`\n*Feels like:* `{temperatureFeelsLike} °{temperatureUnit2}`\n*Humidity:* `{relativeHumidity}%`\n*Wind speed:* `{windSpeed} {speedUnit}`", "resultMsg": "*Weather in {addressFirst}:*\n\n*Status:* `{getStatusEmoji(iconCode)} {wxPhraseLong}`\n*Temperature:* `{temperature} °{temperatureUnit}`\n*Feels like:* `{temperatureFeelsLike} °{temperatureUnit2}`\n*Humidity:* `{relativeHumidity}%`\n*Wind speed:* `{windSpeed} {speedUnit}`",
"apiErr": "*An error occurred while retrieving the weather. Please try again later.*\n\n`{error}`" "apiErr": "*An error occurred while retrieving the weather. Please try again later.*\n\n`{error}`",
"apiKeyErr": "*An API key was not set by the bot owner. Please try again later.*"
}, },
"mainCommands": "Main commands", "mainCommands": "Main commands",
"mainCommandsDesc": "*Main commands*\n\n- /help: Show bot's help\n- /start: Start the bot\n- /privacy: Read the bot's Privacy Policy", "mainCommandsDesc": "*Main commands*\n\n- /help: Show bot's help\n- /start: Start the bot\n- /privacy: Read the bot's Privacy Policy",

View File

@ -49,7 +49,8 @@
"provideLocation": "*Por favor, forneça uma localização.*", "provideLocation": "*Por favor, forneça uma localização.*",
"invalidLocation": "*Localização inválida. Tente novamente.*", "invalidLocation": "*Localização inválida. Tente novamente.*",
"resultMsg": "*Clima em {addressFirst}:*\n\n*Estado:* `{getStatusEmoji(iconCode)} {wxPhraseLong}`\n*Temperatura:* `{temperature} °{temperatureUnit}`\n*Sensação térmica:* `{temperatureFeelsLike} °{temperatureUnit2}`\n*Umidade:* `{relativeHumidity}%`\n*Velocidade do vento:* `{windSpeed} {speedUnit}`", "resultMsg": "*Clima em {addressFirst}:*\n\n*Estado:* `{getStatusEmoji(iconCode)} {wxPhraseLong}`\n*Temperatura:* `{temperature} °{temperatureUnit}`\n*Sensação térmica:* `{temperatureFeelsLike} °{temperatureUnit2}`\n*Umidade:* `{relativeHumidity}%`\n*Velocidade do vento:* `{windSpeed} {speedUnit}`",
"apiErr": "*Ocorreu um erro ao obter o clima. Tente novamente mais tarde.*\n\n`{error}`" "apiErr": "*Ocorreu um erro ao obter o clima. Tente novamente mais tarde.*\n\n`{error}`",
"apiKeyErr": "*Uma chave de API não foi definida pelo proprietário do bot. Tente novamente mais tarde.*"
}, },
"mainCommands": "Comandos principais", "mainCommands": "Comandos principais",
"mainCommandsDesc": "*Comandos principais*\n\n- /help: Exibe a ajuda do bot\n- /start: Inicia o bot\n- /privacy: Leia a política de privacidade do bot", "mainCommandsDesc": "*Comandos principais*\n\n- /help: Exibe a ajuda do bot\n- /start: Inicia o bot\n- /privacy: Leia a política de privacidade do bot",

View File

@ -7,8 +7,8 @@ const languageFiles = {
'en-gb': '../locales/english.json' 'en-gb': '../locales/english.json'
}; };
function getStrings(languageCode) { function getStrings(languageCode: string) {
const filePath = languageFiles[languageCode] || languageFiles['en']; const filePath: string = languageFiles[languageCode] || languageFiles['en'];
try { try {
return require(filePath); return require(filePath);
} catch (error) { } catch (error) {