diff --git a/sql/update_2024-04-22_01.sql b/sql/update_2024-04-22_01.sql new file mode 100644 index 0000000..85187ef --- /dev/null +++ b/sql/update_2024-04-22_01.sql @@ -0,0 +1,2 @@ +ALTER TABLE `warns` ADD `status` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1 AFTER `reason`; +RENAME TABLE `warns` TO `warnings`; diff --git a/src/action/Greetings.ts b/src/action/Greetings.ts index ed8a32e..8c91472 100644 --- a/src/action/Greetings.ts +++ b/src/action/Greetings.ts @@ -147,8 +147,8 @@ export default class Greetings extends Action { const captchaButton: InlineKeyboardButton = { text: Lang.get("captchaButton"), callbackData: JSON.stringify({ - callback: "captchaconfirmation", - data: { + c: "captchaconfirmation", + d: { userId: this.context.newChatMember!.getId() } }) diff --git a/src/callback/Callback.ts b/src/callback/Callback.ts index 47bea8e..d66c28f 100644 --- a/src/callback/Callback.ts +++ b/src/callback/Callback.ts @@ -66,11 +66,11 @@ export default abstract class Callback { */ public isCalled(): boolean { - if (!this.context.callbackQuery?.callbackData || !this.context.callbackQuery?.callbackData.callback) { + if (!this.context.callbackQuery?.callbackData || !this.context.callbackQuery?.callbackData.c) { return false; } - return this.callbacks.includes(this.context.callbackQuery?.callbackData.callback); + return this.callbacks.includes(this.context.callbackQuery?.callbackData.c); } /** diff --git a/src/callback/CaptchaConfirmation.ts b/src/callback/CaptchaConfirmation.ts index 990814f..4c36821 100644 --- a/src/callback/CaptchaConfirmation.ts +++ b/src/callback/CaptchaConfirmation.ts @@ -40,7 +40,7 @@ export default class CaptchaConfirmation extends Callback { */ public async run(): Promise { - if (this.context.callbackQuery?.callbackData.data.userId !== this.context.user.getId()) { + if (this.context.callbackQuery?.callbackData.d.userId !== this.context.user.getId()) { return; } diff --git a/src/callback/Warning.ts b/src/callback/Warning.ts new file mode 100644 index 0000000..155b5f6 --- /dev/null +++ b/src/callback/Warning.ts @@ -0,0 +1,103 @@ +/** + * Ada Lovelace Telegram Bot + * + * This file is part of Ada Lovelace Telegram Bot. + * You are free to modify and share this project or its files. + * + * @package mslovelace_bot + * @author Marcos Leandro + * @license GPLv3 + */ + +import Callback from "./Callback.js"; +import Warnings from "../model/Warnings.js"; +import Context from "../library/telegram/context/Context.js"; +import UserHelper from "../helper/User.js"; +import ChatHelper from "../helper/Chat.js"; +import Lang from "../helper/Lang.js"; +import { parse } from "dotenv"; + +export default class CaptchaConfirmation extends Callback { + + /** + * The constructor. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param context + */ + public constructor(context: Context) { + super(context); + this.setCallbacks(["warning"]); + } + + /** + * Command main route. + * + * @author Marcos Leandro + * @since 2024-04-22 + */ + public async run(): Promise { + + const user = await UserHelper.getByTelegramId(this.context.user.getId()); + const chat = await ChatHelper.getByTelegramId(this.context.chat.getId()); + + if (!user || !chat) { + this.context.callbackQuery?.answer(Lang.get("adminOnlyAction")); + return; + } + + Lang.set(chat.language || "us"); + + if (!await this.context.user.isAdmin()) { + this.context.callbackQuery?.answer(Lang.get("adminOnlyAction")); + } + + const [userId, chatId, warningId] = this.context.callbackQuery?.callbackData?.d?.split(","); + this.context.callbackQuery?.answer("OK"); + this.context.message.delete(); + + const contextUser = await UserHelper.getByTelegramId(userId); + await this.remove(userId, chatId, warningId); + + let message = Lang.get(typeof warningId === "undefined" ? "warningAdminRemovedAll" : "warningAdminRemovedLast") + .replace("{userid}", contextUser.user_id) + .replace("{username}", contextUser.first_name || user.username) + .replace("{adminId}", this.context.user.getId()) + .replace("{adminUsername}", this.context.user.getFirstName() || this.context.user.getUsername()); + + this.context.chat.sendMessage(message, { parseMode: "HTML" }); + } + + /** + * Removes one or all the warnings. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param userId + * @param chatId + * @param warningId + */ + private async remove(userId: number, chatId: number, warningId: number|undefined = undefined): Promise { + + const user = await UserHelper.getByTelegramId(userId); + const chat = await ChatHelper.getByTelegramId(chatId); + + const warnings = new Warnings(); + const update = warnings.update(); + + update + .set("status", 0) + .where("user_id").equal(user!.id) + .and("chat_id").equal(chat!.id); + + if (typeof warningId !== "undefined") { + update.and("id").equal(warningId); + } + + await warnings.execute(); + } + +} diff --git a/src/callback/Yarn.ts b/src/callback/Yarn.ts index 7d5c464..eec5bce 100644 --- a/src/callback/Yarn.ts +++ b/src/callback/Yarn.ts @@ -37,12 +37,12 @@ export default class Yarn extends Callback { */ public async run(): Promise { - if (!this.context.callbackQuery?.callbackData.data.package) { + if (!this.context.callbackQuery?.callbackData.d.package) { return; } const yarnCommand = new YarnCommand(this.context); - await yarnCommand.getPackage(this.context.callbackQuery?.callbackData.data.package); - this.context.callbackQuery.answer(this.context.callbackQuery?.callbackData.data.package.toUpperCase()); + await yarnCommand.getPackage(this.context.callbackQuery?.callbackData.d.package); + this.context.callbackQuery.answer(this.context.callbackQuery?.callbackData.d.package.toUpperCase()); } } diff --git a/src/command/Warn.ts b/src/command/Warn.ts deleted file mode 100644 index 44e1dc5..0000000 --- a/src/command/Warn.ts +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Ada Lovelace Telegram Bot - * - * This file is part of Ada Lovelace Telegram Bot. - * You are free to modify and share this project or its files. - * - * @package mslovelace_bot - * @author Marcos Leandro - * @license GPLv3 - */ - -import Command from "./Command.js"; -import Context from "../library/telegram/context/Context.js"; -import CommandContext from "../library/telegram/context/Command.js"; -import User from "../library/telegram/context/User.js"; -import Message from "../library/telegram/context/Message.js"; -import ChatConfigs from "../model/ChatConfigs.js"; -import Warns from "../model/Warns.js"; -import UserHelper from "../helper/User.js"; -import ChatHelper from "../helper/Chat.js"; -import Lang from "../helper/Lang.js"; -import Log from "../helper/Log.js"; - -export default class Warn extends Command { - - /** - * Command context. - * - * @author Marcos Leandro - * @since 2023-06-14 - * - * @var {CommandContext} - */ - private command?: CommandContext; - - /** - * The constructor. - * - * @author Marcos Leandro - * @since 2022-09-12 - * - * @param app App instance. - */ - public constructor(context: Context) { - super(context); - this.setCommands(["warn"]); - } - - /** - * Executes the command. - * - * @author Marcos Leandro - * @since 2023-06-07 - * - * @param command - * - * @returns - */ - public async run(command: CommandContext): Promise { - - if (!await this.context.user.isAdmin()) { - return; - } - - if (this.context.chat.getType() === "private") { - return; - } - - this.command = command; - - const replyToMessage = this.context.message.getReplyToMessage(); - if (replyToMessage) { - this.warnByReply(replyToMessage); - return; - } - - const mentions = await this.context.message.getMentions(); - if (!mentions.length) { - return; - } - - for (const mention of mentions) { - this.warnByMention(mention); - } - } - - /** - * Warns an user by message reply. - * - * @author Marcos Leandro - * @since 2023-06-07 - * - * @returns void - */ - private async warnByReply(replyToMessage: Message): Promise { - - const params = this.command!.getParams(); - if (!params || !params.length) { - return; - } - - this.warn(replyToMessage.getUser(), params.join(" ")); - } - - /** - * Warns an user by mention reply. - * - * @author Marcos Leandro - * @since 2023-06-07 - * - * @returns void - */ - private async warnByMention(mention: User): Promise { - - const params = this.command!.getParams(); - if (!params || !params.length) { - return; - } - - params.shift(); - this.warn(mention, params.join(" ")); - } - - /** - * Saves the user warning. - * - * @author Marcos Leandro - * @since 2023-06-14 - * - * @param {User} contextUser - * @param {string} reason - */ - private async warn(contextUser: User, reason: string): Promise { - - const user = await UserHelper.getByTelegramId(contextUser.getId()); - const chat = await ChatHelper.getByTelegramId(this.context.chat.getId()); - - if (!user || !chat) { - return; - } - - Lang.set(chat.language || "us"); - - if (contextUser.getId() === parseInt(process.env.TELEGRAM_USER_ID!)) { - this.context.message.reply(Lang.get("selfWarnMessage")); - return; - } - - if (await contextUser.isAdmin()) { - this.context.message.reply(Lang.get("adminWarnMessage")); - return; - } - - this.context.message.delete(); - - const warn = new Warns(); - warn - .insert() - .set("user_id", user.id) - .set("chat_id", chat.id) - .set("date", Math.ceil(Date.now() / 1000)) - .set("reason", reason); - - try { - await warn.execute(); - this.reportWarnAndBan(contextUser, user, chat); - - } catch (error) { - Log.save(error.message, error.stack); - } - } - - /** - * Reports the warning and bans the user if necessary. - * - * @author Marcos Leandro - * @since 2023-06-14 - * - * @param {User} contextUser - * @param {Record} user - * @param {Record} chat - */ - private async reportWarnAndBan(contextUser: User, user: Record, chat: Record): Promise { - - const warn = new Warns(); - warn - .select() - .where("user_id").equal(user.id) - .and("chat_id").equal(chat.id) - .orderBy("date", "ASC"); - - const warns = await warn.execute(); - - const chatConfigs = new ChatConfigs(); - chatConfigs - .select() - .where("chat_id").equal(chat.id); - - const chatConfig = await chatConfigs.execute(); - const warnLimit = chatConfig[0].warn_limit || 3; - - const username = contextUser.getFirstName() || contextUser.getUsername(); - const langIndex = warns.length === 1 ? "warningSigleMessage" : "warningPluralMessage"; - - let message = Lang.get(langIndex) - .replace("{userid}", contextUser.getId()) - .replace("{username}", username) - .replace("{warns}", warns.length.toString() + "/" + warnLimit.toString()); - - if (warns.length >= warnLimit) { - contextUser.ban(); - message = Lang.get("warningBanMessage") - .replace("{userid}", contextUser.getId()) - .replace("{username}", username) - .replace("{warns}", warns.length.toString() + "/" + warnLimit.toString()); - } - - for (let i = 0, length = warns.length; i < length; i++) { - message += ` • ${warns[i].reason}\n`; - } - - this.context.chat.sendMessage(message, { parseMode: "HTML" }); - } -} diff --git a/src/command/Warning/Base.ts b/src/command/Warning/Base.ts new file mode 100644 index 0000000..ca767cf --- /dev/null +++ b/src/command/Warning/Base.ts @@ -0,0 +1,204 @@ +/** + * Ada Lovelace Telegram Bot + * + * This file is part of Ada Lovelace Telegram Bot. + * You are free to modify and share this project or its files. + * + * @package mslovelace_bot + * @author Marcos Leandro + * @license GPLv3 + */ + +import Command from "../Command.js"; +import Context from "../../library/telegram/context/Context.js"; +import User from "../../library/telegram/context/User.js"; +import { InlineKeyboardButton } from "../../library/telegram/type/InlineKeyboardButton.js"; +import { InlineKeyboardMarkup } from "../../library/telegram/type/InlineKeyboardMarkup.js"; +import ChatConfigs from "../../model/ChatConfigs.js"; +import WarningsModel from "../../model/Warnings.js"; +import UserHelper from "../../helper/User.js"; +import Lang from "../../helper/Lang.js"; + +export default class Base extends Command { + + /** + * The constructor. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param context + */ + public constructor(context: Context) { + super(context); + } + + /** + * Returns the group's warning limits. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param chat + * + * @return Warning limit. + */ + protected async getWarningLimit(chat: Record): Promise { + + const chatConfigs = new ChatConfigs(); + chatConfigs + .select() + .where("chat_id").equal(chat.id); + + const chatConfig = await chatConfigs.execute(); + const warningLimit = chatConfig[0].warn_limit; + + return warningLimit ? parseInt(warningLimit) : 3; + } + + /** + * Returns the user's warns. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param user + * @param chat + * + * @return Warnings length. + */ + protected async getWarnings(contextUser: User, chat: Record): Promise[]> { + + const user = await UserHelper.getByTelegramId(contextUser.getId()); + + if (!user || !chat) { + return Promise.resolve([]); + } + + const warnings = new WarningsModel(); + warnings + .select() + .where("user_id").equal(user.id) + .and("chat_id").equal(chat.id) + .and("status").equal(1) + .orderBy("date", "ASC"); + + return await warnings.execute(); + } + + /** + * Returns the warning message. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param contextUser + * @param warnings + * @param warningsLimit + * + * @return Warning message. + */ + protected async getWarningMessage(contextUser: User, warnings: Record[], warningsLimit: number): Promise { + + const username = contextUser.getFirstName() || contextUser.getUsername(); + + let langIndex = warnings.length === 1 ? "warningSigleMessage" : "warningPluralMessage"; + langIndex = warnings.length >= warningsLimit ? "warningBanMessage" : langIndex; + langIndex = warnings.length === 0 ? "warningNoneMessage" : langIndex; + + let message = Lang.get(langIndex) + .replace("{userid}", contextUser.getId()) + .replace("{username}", username) + .replace("{warns}", warnings.length.toString() + "/" + warningsLimit.toString()); + + for (let i = 0, length = warnings.length; i < length; i++) { + message += ` • ${warnings[i].reason}\n`; + } + + return Promise.resolve(message); + } + + /** + * Sends the warning messages. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param users + * @param chat + * + * @return + */ + protected async sendWarningMessages(users: User[], chat: Record): Promise { + + Lang.set(chat.language || "us"); + + const warnings = await this.getWarnings(users[0], chat); + const warningLimit = await this.getWarningLimit(chat); + const messages = []; + + for (let i = 0, length = users.length; i < length; i++) { + const contextUser = users[i]; + messages.push(await this.getWarningMessage(contextUser, warnings, warningLimit)); + } + + if (!messages.length) { + return Promise.resolve(); + } + + const message = messages.join("\n-----\n"); + const options = this.getMessageOptions(users, warnings); + + await this.context.chat.sendMessage(message, options); + } + + /** + * Returns the message options. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param users + * @param chat + * + * @returns + */ + private getMessageOptions(users: User[], warnings: Record[]): Record { + + const options: Record = { + parseMode: "HTML" + }; + + if (users.length !== 1) { + return options; + } + + if (!warnings.length) { + return options; + } + + const lastWarning: Record = warnings.at(-1)!; + const lastWarningRemowalButton: InlineKeyboardButton = { + text: Lang.get("lastWarningRemovalButton"), + callbackData: JSON.stringify({ + c: "warning", + d: `${users[0].getId()},${this.context.chat.getId()},${lastWarning.id}` + }) + }; + + const allWarningsRemowalButton: InlineKeyboardButton = { + text: Lang.get("warningsRemovalButton"), + callbackData: JSON.stringify({ + c: "warning", + d: `${users[0].getId()},${this.context.chat.getId()}` + }) + }; + + const markup: InlineKeyboardMarkup = { + inlineKeyboard: [[lastWarningRemowalButton], [allWarningsRemowalButton]] + }; + + options.replyMarkup = markup; + return options; + } +} diff --git a/src/command/Warning/Warn.ts b/src/command/Warning/Warn.ts new file mode 100644 index 0000000..e8877a0 --- /dev/null +++ b/src/command/Warning/Warn.ts @@ -0,0 +1,186 @@ +/** + * Ada Lovelace Telegram Bot + * + * This file is part of Ada Lovelace Telegram Bot. + * You are free to modify and share this project or its files. + * + * @package mslovelace_bot + * @author Marcos Leandro + * @license GPLv3 + */ + +import Context from "../../library/telegram/context/Context.js"; +import CommandContext from "../../library/telegram/context/Command.js"; +import User from "../../library/telegram/context/User.js"; +import Message from "../../library/telegram/context/Message.js"; +import ChatConfigs from "../../model/ChatConfigs.js"; +import WarningsModel from "../../model/Warnings.js"; +import WarningsBase from "./Base.js"; +import UserHelper from "../../helper/User.js"; +import ChatHelper from "../../helper/Chat.js"; +import Lang from "../../helper/Lang.js"; +import Log from "../../helper/Log.js"; + +export default class Warn extends WarningsBase { + + /** + * Command context. + * + * @author Marcos Leandro + * @since 2023-06-14 + * + * @var {CommandContext} + */ + private command?: CommandContext; + + /** + * The constructor. + * + * @author Marcos Leandro + * @since 2022-09-12 + * + * @param app App instance. + */ + public constructor(context: Context) { + super(context); + this.setCommands(["warn"]); + } + + /** + * Executes the command. + * + * @author Marcos Leandro + * @since 2023-06-07 + * + * @param command + * + * @returns + */ + public async run(command: CommandContext): Promise { + + if (!await this.context.user.isAdmin()) { + return; + } + + if (this.context.chat.getType() === "private") { + return; + } + + this.command = command; + + const chat = await ChatHelper.getByTelegramId(this.context.chat.getId()); + if (!chat) { + return; + } + + const params = this.command!.getParams(); + if (!params || !params.length) { + return; + } + + Lang.set(chat.language || "us"); + + const users = []; + const warningLimit = await this.getWarningLimit(chat); + const replyToMessage = this.context.message.getReplyToMessage(); + + if (replyToMessage) { + users.push(replyToMessage.getUser()); + } + + const mentions = await this.context.message.getMentions() || []; + for (const mention of mentions) { + users.push(mention); + params.shift(); + } + + if (!users.length) { + return; + } + + for (let i = 0, length = users.length; i < length; i++) { + const contextUser = users[i]; + await this.warn(contextUser, chat, warningLimit, params.join(" ")); + } + + this.sendWarningMessages(users, chat); + } + + /** + * Saves the user warning. + * + * @author Marcos Leandro + * @since 2023-06-14 + * + * @param contextUser + * @param chat + * @param warningLimit + * @param reason + */ + private async warn(contextUser: User, chat: Record, warningLimit: number, reason: string): Promise { + + if (contextUser.getId() === parseInt(process.env.TELEGRAM_USER_ID!)) { + this.context.message.reply(Lang.get("selfWarnMessage")); + return; + } + + if (await contextUser.isAdmin()) { + this.context.message.reply(Lang.get("adminWarnMessage")); + return; + } + + const user = await UserHelper.getByTelegramId(contextUser.getId()); + if (!user) { + return; + } + + this.context.message.delete(); + + const warn = new WarningsModel(); + warn + .insert() + .set("user_id", user.id) + .set("chat_id", chat.id) + .set("date", Math.ceil(Date.now() / 1000)) + .set("reason", reason); + + try { + + await warn.execute(); + this.checkBan(contextUser, user, chat, warningLimit); + + } catch (error: any) { + Log.save(error.message, error.stack); + } + } + + /** + * Bans the user if necessary. + * + * @author Marcos Leandro + * @since 2023-06-14 + * + * @param contextUser + * @param user + * @param chat + * @param warningLimit + */ + private async checkBan(contextUser: User, user: Record, chat: Record, warningLimit: number): Promise { + + const warnings = new WarningsModel(); + warnings + .select() + .where("user_id").equal(user.id) + .and("chat_id").equal(chat.id) + .and("status").equal(1) + .orderBy("date", "ASC"); + + const results = await warnings.execute(); + + if (results.length >= warningLimit) { + contextUser.ban(); + } + + return Promise.resolve(); + } +} diff --git a/src/command/Warning/Warnings.ts b/src/command/Warning/Warnings.ts new file mode 100644 index 0000000..ff26dfe --- /dev/null +++ b/src/command/Warning/Warnings.ts @@ -0,0 +1,82 @@ +/** + * Ada Lovelace Telegram Bot + * + * This file is part of Ada Lovelace Telegram Bot. + * You are free to modify and share this project or its files. + * + * @package mslovelace_bot + * @author Marcos Leandro + * @license GPLv3 + */ + +import Context from "../../library/telegram/context/Context.js"; +import CommandContext from "../../library/telegram/context/Command.js"; +import User from "../../library/telegram/context/User.js"; +import WarningsBase from "./Base.js"; +import ChatHelper from "../../helper/Chat.js"; +import Lang from "../../helper/Lang.js"; + +export default class Warnings extends WarningsBase { + + /** + * Command context. + * + * @author Marcos Leandro + * @since 2023-06-14 + * + * @var {CommandContext} + */ + private command?: CommandContext; + + /** + * The constructor. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param app App instance. + */ + public constructor(context: Context) { + super(context); + this.setCommands(["warnings", "warns"]); + } + + /** + * Executes the command. + * + * @author Marcos Leandro + * @since 2023-06-07 + * + * @param command + * + * @returns + */ + public async run(command: CommandContext): Promise { + + if (!await this.context.user.isAdmin()) { + return; + } + + if (this.context.chat.getType() === "private") { + return; + } + + const chat = await ChatHelper.getByTelegramId(this.context.chat.getId()); + if (!chat) { + return; + } + + const users = []; + const replyToMessage = this.context.message.getReplyToMessage(); + if (replyToMessage) { + users.push(replyToMessage.getUser()); + } + + const mentions = await this.context.message.getMentions() || []; + for (const mention of mentions) { + users.push(mention); + } + + this.sendWarningMessages(users, chat); + } +} diff --git a/src/config/callbacks.ts b/src/config/callbacks.ts index f936af2..a04f500 100644 --- a/src/config/callbacks.ts +++ b/src/config/callbacks.ts @@ -10,9 +10,11 @@ */ import CaptchaConfirmationCallback from "../callback/CaptchaConfirmation.js"; +import Warning from "../callback/Warning.js"; import YarnCallback from "../callback/Yarn.js"; export const callbacks = [ CaptchaConfirmationCallback, + Warning, YarnCallback ]; diff --git a/src/config/commands.ts b/src/config/commands.ts index 054cd46..bdb7215 100644 --- a/src/config/commands.ts +++ b/src/config/commands.ts @@ -25,7 +25,8 @@ import Restrict from "../command/Restrict.js"; import Send from "../command/Send.js"; import Start from "../command/Start.js"; import Unban from "../command/Unban.js"; -import Warn from "../command/Warn.js"; +import Warn from "../command/Warning/Warn.js"; +import Warnings from "../command/Warning/Warnings.js"; import Yarn from "../command/Yarn.js"; export const commands = [ @@ -46,5 +47,6 @@ export const commands = [ Start, Unban, Warn, + Warnings, Yarn ]; diff --git a/src/controller/Controller.ts b/src/controller/Controller.ts index 84b2f32..1f9e216 100644 --- a/src/controller/Controller.ts +++ b/src/controller/Controller.ts @@ -225,6 +225,7 @@ export default class Controller { private executeCallback(callback: Callback): void { try { + !callback.isCalled() || callback.run(); } catch (error: any) { diff --git a/src/helper/YarnPackage.ts b/src/helper/YarnPackage.ts index f033a25..fcd53bc 100644 --- a/src/helper/YarnPackage.ts +++ b/src/helper/YarnPackage.ts @@ -64,8 +64,8 @@ export default class YarnPackage extends JsPackage { const button: InlineKeyboardButton = { text : `${key} ${this.package.data.dependencies[key]}`, callbackData : JSON.stringify({ - callback : "yarn", - data : { + c : "yarn", + d : { package : key } }) diff --git a/src/lang/br.ts b/src/lang/br.ts index 7f90249..09c589c 100644 --- a/src/lang/br.ts +++ b/src/lang/br.ts @@ -55,9 +55,12 @@ export default { adminReportMessage: "Por que eu reportaria um administrador?", selfWarnMessage: "Por que eu me daria advertência?", adminWarnMessage: "Por que eu daria advertência em um administrador?", + warningNoneMessage: "✔ {username} não tem advertências.", warningSigleMessage: "⚠️ {username} tem {warns} advertências.\n\nMotivo:\n", warningPluralMessage: "⚠️ {username} tem {warns} advertências.\n\nMotivos:\n", warningBanMessage: "❌ {username} levou ban por ter {warns} advertências.\n\nMotivos:\n", + warningAdminRemovedLast: "Última advertência de {username} removida por {adminUsername}.", + warningAdminRemovedAll: "Todas as advertências de {username} foram removidas por {adminUsername}.", reportMessage: "Reportado aos administradores.", federationCreateOnlyPrivate: "Me chame no privado pra criar uma federação.", federationCreateSuccess: "Federação {name} criada com sucesso!\nVocê já pode adicionar grupos usando o comando /fjoin {hash}", @@ -91,4 +94,7 @@ export default { macroAlreadyExists: "A macro {macro} já existe.", macroAddError: "Ocorreu um erro ao adicionar a macro. Por favor, tente novamente mais tarde.", macroRemoveError: "Ocorreu um erro ao remover a macro. Por favor, tente novamente mais tarde.", + lastWarningRemovalButton: "Remover Advertência (somente admins)", + warningsRemovalButton: "Remover todas as advertências (somente admins)", + adminOnlyAction: "Esta ação só pode ser executada por administradores." }; diff --git a/src/lang/us.ts b/src/lang/us.ts index ce25fde..59f1948 100644 --- a/src/lang/us.ts +++ b/src/lang/us.ts @@ -55,9 +55,12 @@ export default { adminReportMessage: "Why would I report an admin?", selfWarnMessage: "Why would I warn myself?", adminWarnMessage: "Why would I warn an admin?", + warningNoneMessage: "✔ {username} has no warnings.", warningSigleMessage: "⚠️ {username} has {warns} warnings.\n\nReason:\n", warningPluralMessage: "⚠️ {username} has {warns} warnings.\n\nReasons:\n", warningBanMessage: "❌ {username} has {warns} warnings and has been banned.\n\nReasons:\n", + warningAdminRemovedLast: "Last warning of {username} removed by {adminUsername}.", + warningAdminRemovedAll: "All warnings of {username} removed by {adminUsername}.", reportMessage: "Reported to the admins.", federationCreateOnlyPrivate: "PM me if you want to create a federation.", federationCreateSuccess: "Federation {name} successfully created.\nYou can now add groups to your federation using the command /fjoin {hash}.", @@ -91,4 +94,7 @@ export default { macroAlreadyExists: "The macro {macro} already exists.", macroAddError: "An error occurred while adding the macro. Please try again later.", macroRemoveError: "An error occurred while removing the macro. Please try again later.", + lastWarningRemovalButton: "Remove warning (admin only)", + warningsRemovalButton: "Remove all warnings (admin only)", + adminOnlyAction: "This action can only be performed by admins." }; diff --git a/src/library/telegram/context/CallbackQuery.ts b/src/library/telegram/context/CallbackQuery.ts index 0554bf1..056e16a 100644 --- a/src/library/telegram/context/CallbackQuery.ts +++ b/src/library/telegram/context/CallbackQuery.ts @@ -69,7 +69,7 @@ export default class CallbackQuery { const answer = new AnswerCallbackQuery(); answer .setCallbackQueryId(this.payload.callbackQuery.id) - .setText(this.callbackData.data.package.toUpperCase()); + .setText(content); return answer .post() diff --git a/src/library/telegram/context/Chat.ts b/src/library/telegram/context/Chat.ts index 7ca36ae..26c6e77 100644 --- a/src/library/telegram/context/Chat.ts +++ b/src/library/telegram/context/Chat.ts @@ -422,6 +422,10 @@ export default class Chat { .setChatId(this.context.chat.id) .setText(text); + if (typeof this.context.messageThreadId !== "undefined") { + sendMessage.setThreadId(this.context.messageThreadId); + } + if (options) { sendMessage.setOptions(options); } diff --git a/src/library/telegram/context/Message.ts b/src/library/telegram/context/Message.ts index e85d798..5ff8a8a 100644 --- a/src/library/telegram/context/Message.ts +++ b/src/library/telegram/context/Message.ts @@ -443,6 +443,10 @@ export default class Message { return; } + if (this.context.replyToMessage.messageId === this.context.messageThreadId) { + return; + } + this.replyToMessage = new Message(this.context.replyToMessage); } diff --git a/src/library/telegram/resource/SendMessage.ts b/src/library/telegram/resource/SendMessage.ts index 51ed83a..4701f0c 100644 --- a/src/library/telegram/resource/SendMessage.ts +++ b/src/library/telegram/resource/SendMessage.ts @@ -66,6 +66,21 @@ export default class SendMessage extends TelegramBotApi { return this; } + /** + * Sets the thread id. + * + * @author Marcos Leandro + * @since 2024-04-22 + * + * @param threadId + * + * @return + */ + public setThreadId(threadId: number): SendMessage { + this.payload.messageThreadId = threadId; + return this; + } + /** * Sets the message content. * diff --git a/src/model/Warns.ts b/src/model/Warnings.ts similarity index 86% rename from src/model/Warns.ts rename to src/model/Warnings.ts index 98d6332..0a1219a 100644 --- a/src/model/Warns.ts +++ b/src/model/Warnings.ts @@ -11,7 +11,7 @@ import DefaultModel from "./Model.js"; -export default class Warns extends DefaultModel { +export default class Warnings extends DefaultModel { /** * The constructor. @@ -20,6 +20,6 @@ export default class Warns extends DefaultModel { * @since 2023-06-14 */ public constructor() { - super("warns"); + super("warnings"); } }