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

View File

@ -1,64 +1,70 @@
import { getStrings } from '../plugins/checklang';
import { isOnSpamWatch } from '../spamwatch/spamwatch';
import spamwatchMiddlewareModule from '../spamwatch/Middleware';
import { Context, Telegraf } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
async function getUserInfo(ctx) {
const Strings = getStrings(ctx.from.language_code);
let lastName = ctx.from.last_name;
async function getUserInfo(ctx: Context & { message: { text: string } }) {
const Strings = getStrings(ctx.from?.language_code || 'en');
let lastName = ctx.from?.last_name;
if (lastName === undefined) {
lastName = " ";
}
const userInfo = Strings.userInfo
.replace('{userName}', `${ctx.from.first_name} ${lastName}` || Strings.varStrings.varUnknown)
.replace('{userId}', ctx.from.id || Strings.varStrings.varUnknown)
.replace('{userHandle}', ctx.from.username ? `@${ctx.from.username}` : Strings.varStrings.varNone)
.replace('{userPremium}', ctx.from.is_premium ? Strings.varStrings.varYes : Strings.varStrings.varNo)
.replace('{userLang}', ctx.from.language_code || Strings.varStrings.varUnknown);
.replace('{userName}', `${ctx.from?.first_name} ${lastName}` || Strings.varStrings.varUnknown)
.replace('{userId}', ctx.from?.id || Strings.varStrings.varUnknown)
.replace('{userHandle}', ctx.from?.username ? `@${ctx.from?.username}` : Strings.varStrings.varNone)
.replace('{userPremium}', ctx.from?.is_premium ? Strings.varStrings.varYes : Strings.varStrings.varNo)
.replace('{userLang}', ctx.from?.language_code || Strings.varStrings.varUnknown);
return userInfo;
}
async function getChatInfo(ctx) {
const Strings = getStrings(ctx.from.language_code);
if (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup') {
async function getChatInfo(ctx: Context & { message: { text: string } }) {
const Strings = getStrings(ctx.from?.language_code || 'en');
if (ctx.chat?.type === 'group' || ctx.chat?.type === 'supergroup') {
const chatInfo = Strings.chatInfo
.replace('{chatId}', ctx.chat.id || Strings.varStrings.varUnknown)
.replace('{chatName}', ctx.chat.title || Strings.varStrings.varUnknown)
.replace('{chatHandle}', ctx.chat.username ? `@${ctx.chat.username}` : Strings.varStrings.varNone)
.replace('{chatMembersCount}', await ctx.getChatMembersCount(ctx.chat.id || Strings.varStrings.varUnknown))
.replace('{chatType}', ctx.chat.type || Strings.varStrings.varUnknown)
.replace('{isForum}', ctx.chat.is_forum ? Strings.varStrings.varYes : Strings.varStrings.varNo);
.replace('{chatId}', ctx.chat?.id || Strings.varStrings.varUnknown)
.replace('{chatName}', ctx.chat?.title || Strings.varStrings.varUnknown)
// @ts-ignore
.replace('{chatHandle}', ctx.chat?.username ? `@${ctx.chat?.username}` : Strings.varStrings.varNone)
.replace('{chatMembersCount}', await ctx.getChatMembersCount())
.replace('{chatType}', ctx.chat?.type || Strings.varStrings.varUnknown)
// @ts-ignore
.replace('{isForum}', ctx.chat?.is_forum ? Strings.varStrings.varYes : Strings.varStrings.varNo);
return chatInfo;
} else {
return ctx.reply(
Strings.groupOnly, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
}
export default (bot) => {
bot.command('chatinfo', spamwatchMiddleware, async (ctx) => {
export default (bot: Telegraf<Context>) => {
bot.command('chatinfo', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const chatInfo = await getChatInfo(ctx);
ctx.reply(
chatInfo, {
parse_mode: 'Markdown',
// @ts-ignore
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);
ctx.reply(
userInfo, {
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 axios from 'axios';
import verifyInput from '../plugins/verifyInput';
import { Telegraf, Context } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
@ -50,19 +51,20 @@ function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
export default (bot) => {
bot.command("mlp", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
export default (bot: Telegraf<Context>) => {
bot.command("mlp", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from?.language_code || 'en');
ctx.reply(Strings.ponyApi.helpDesc, {
parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id
});
});
bot.command("mlpchar", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
bot.command("mlpchar", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+");
const { noCharName } = Strings.ponyApi
@ -116,12 +118,14 @@ export default (bot) => {
ctx.replyWithPhoto(charactersArray[0].image[0], {
caption: `${result}`,
parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id
});
} else {
ctx.reply(Strings.ponyApi.noCharFound, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
};
@ -129,13 +133,14 @@ export default (bot) => {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
};
});
bot.command("mlpep", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
bot.command("mlpep", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+");
const { noEpisodeNum } = Strings.ponyApi
@ -184,12 +189,14 @@ export default (bot) => {
ctx.replyWithPhoto(episodeArray[0].image, {
caption: `${result}`,
parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id
});
} else {
ctx.reply(Strings.ponyApi.noEpisodeFound, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
};
@ -197,13 +204,14 @@ export default (bot) => {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
};
});
bot.command("mlpcomic", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
bot.command("mlpcomic", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from?.language_code || 'en');
const userInput = ctx.message.text.split(' ').slice(1).join(' ').replace(" ", "+");
const { noComicName } = Strings.ponyApi
@ -257,12 +265,14 @@ export default (bot) => {
ctx.replyWithPhoto(comicArray[0].image, {
caption: `${result}`,
parse_mode: 'Markdown',
// @ts-ignore
disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id
});
} else {
ctx.reply(Strings.ponyApi.noComicFound, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
};
@ -270,6 +280,7 @@ export default (bot) => {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
// @ts-ignore
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 spamwatchMiddlewareModule from '../spamwatch/Middleware';
import axios from 'axios';
import { Telegraf, Context } from 'telegraf';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
export default (bot) => {
bot.command(["rpony", "randompony", "mlpart"], spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
export default (bot: Telegraf<Context>) => {
// TODO: this would greatly benefit from a loading message
bot.command(["rpony", "randompony", "mlpart"], spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const Strings = getStrings(ctx.from?.language_code || 'en');
try {
const response = await axios(Resources.randomPonyApi);
let tags: string[] = [];
@ -24,12 +26,14 @@ export default (bot) => {
ctx.replyWithPhoto(response.data.pony.representations.full, {
caption: `${response.data.pony.sourceURL}\n\n${tags.length > 0 ? tags.join(', ') : ''}`,
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
const message = Strings.ponyApi.apiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
// @ts-ignore
reply_to_message_id: ctx.message.message_id
});
return;

View File

@ -21,10 +21,10 @@ const statusEmojis = {
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) {
const fahrenheitCountries = ['US', 'BS', 'BZ', 'KY', 'LR'];
function getLocaleUnit(countryCode: string) {
const fahrenheitCountries: string[] = ['US', 'BS', 'BZ', 'KY', 'LR'];
if (fahrenheitCountries.includes(countryCode)) {
return { temperatureUnit: 'F', speedUnit: 'mph', apiUnit: 'e' };
@ -44,10 +44,18 @@ export default (bot) => {
return;
}
const location = userInput;
const apiKey = process.env.weatherKey;
const location: string = userInput;
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 {
// TODO: this also needs to be sanitized and validated
const locationResponse = await axios.get(`${Resources.weatherApi}/location/search`, {
params: {
apiKey: apiKey,

View File

@ -49,7 +49,8 @@
"provideLocation": "*Please provide a location.*",
"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}`",
"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",
"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.*",
"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}`",
"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",
"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'
};
function getStrings(languageCode) {
const filePath = languageFiles[languageCode] || languageFiles['en'];
function getStrings(languageCode: string) {
const filePath: string = languageFiles[languageCode] || languageFiles['en'];
try {
return require(filePath);
} catch (error) {