diff --git a/bot/messages.ts b/bot/messages.ts index 076ca17d..95b6c4f7 100644 --- a/bot/messages.ts +++ b/bot/messages.ts @@ -755,6 +755,28 @@ const bannedUserErrorMessage = async (ctx: MainContext, user: UserDocument) => { } }; +const userOrderIsBlockedByUserTaker = async (ctx: MainContext, user: UserDocument) => { + try { + await ctx.telegram.sendMessage( + user.tg_id, + ctx.i18n.t('user_order_is_blocked_by_user_taker') + ); + } catch (error) { + logger.error(error); + } +}; + +const userTakerIsBlockedByUserOrder = async (ctx: MainContext, user: UserDocument) => { + try { + await ctx.telegram.sendMessage( + user.tg_id, + ctx.i18n.t('user_taker_is_blocked_by_user_order') + ); + } catch (error) { + logger.error(error); + } +}; + const fiatSentMessages = async (ctx: MainContext, buyer: UserDocument, seller: UserDocument, i18nBuyer: I18nContext, i18nSeller: I18nContext) => { try { await ctx.telegram.sendMessage( @@ -1734,4 +1756,6 @@ export { showConfirmationButtons, counterPartyCancelOrderMessage, checkInvoiceMessage, + userTakerIsBlockedByUserOrder, + userOrderIsBlockedByUserTaker }; diff --git a/bot/modules/block/commands.js b/bot/modules/block/commands.js new file mode 100644 index 00000000..7a8f9fcf --- /dev/null +++ b/bot/modules/block/commands.js @@ -0,0 +1,67 @@ +const { User, Block, Order } = require('../../../models'); +const messages = require('./messages'); +const globalMessages = require('../../messages'); + +const block = async (ctx, username) => { + const userToBlock = await User.findOne({ username }); + const user = ctx.user; + + if (!userToBlock) { + await globalMessages.notFoundUserMessage(ctx); + return; + } + + const areExistingOrders = await Order.exists({ + $or: [ + { seller_id: user.id, buyer_id: userToBlock.id }, + { seller_id: userToBlock.id, buyer_id: user.id } + ], + status: { $nin: ["PENDING", "CLOSED", "CANCELED_BY_ADMIN", "EXPIRED", "COMPLETED_BY_ADMIN"] } + }); + + if(areExistingOrders) { + await messages.ordersInProcess(ctx); + return; + } + + const isAlreadyBlocked = await Block.exists({blocker_tg_id: user.tg_id, blocked_tg_id: userToBlock.tg_id}) + if (isAlreadyBlocked) { + await messages.userAlreadyBlocked(ctx); + return; + } + + const block = new Block({ + blocker_tg_id: user.tg_id, + blocked_tg_id: userToBlock.tg_id, + }); + await block.save(); + await messages.userBlocked(ctx); +}; + +const unblock = async (ctx, username) => { + const userToUnblock = await User.findOne({ username }); + const user = ctx.user; + + const result = await Block.deleteOne({blocker_tg_id: user.tg_id, blocked_tg_id: userToUnblock.tg_id}) + + if (result.deletedCount === 1) { + await messages.userUnblocked(ctx); + } else { + await globalMessages.notFoundUserMessage(ctx); + } +}; + +const blocklist = async ctx => { + const blocks = await Block.find({ blocker_tg_id: ctx.user.tg_id }); + const tgIdBlocks = blocks.map(blocked => blocked.blocked_tg_id) + + if (!tgIdBlocks.length) { + await messages.blocklistEmptyMessage(ctx) + return; + } + + const usersBlocked = await User.find({tg_id: { $in: tgIdBlocks}}); + await messages.blocklistMessage(ctx, usersBlocked) +}; + +module.exports = { block, unblock, blocklist }; diff --git a/bot/modules/block/index.js b/bot/modules/block/index.js new file mode 100644 index 00000000..3476c79b --- /dev/null +++ b/bot/modules/block/index.js @@ -0,0 +1,17 @@ +const commands = require('./commands'); +const { userMiddleware } = require('../../middleware/user'); + +exports.configure = bot => { + bot.command('block', userMiddleware, async (ctx, next) => { + const args = ctx.message.text.split(' '); + if (args.length !== 2) return next(); + commands.block(ctx, args[1]); + }); + + bot.command('unblock', userMiddleware, async (ctx, next) => { + const args = ctx.message.text.split(' '); + if (args.length !== 2) return next(); + commands.unblock(ctx, args[1]); + }); + bot.command('blocklist', userMiddleware, commands.blocklist); +}; diff --git a/bot/modules/block/messages.js b/bot/modules/block/messages.js new file mode 100644 index 00000000..7df63a66 --- /dev/null +++ b/bot/modules/block/messages.js @@ -0,0 +1,53 @@ +const { logger } = require('../../../logger'); + + +const ordersInProcess = async ctx => { + try { + ctx.reply(ctx.i18n.t('orders_in_process')); + } catch (error) { + logger.error(error); + } +}; + +const userAlreadyBlocked = async ctx => { + try { + ctx.reply(ctx.i18n.t('user_already_blocked')); + } catch (error) { + logger.error(error); + } +}; + +const userBlocked = async ctx => { + try { + ctx.reply(ctx.i18n.t('user_blocked')); + } catch (error) { + logger.error(error); + } +}; + +const userUnblocked = async ctx => { + try { + ctx.reply(ctx.i18n.t('user_unblocked')); + } catch (error) { + logger.error(error); + } +}; + +const blocklistMessage = async (ctx, usersBlocked) => { + try { + const userList = usersBlocked.map(block => block.username); + ctx.reply(userList.join('\n')); + } catch (error) { + logger.error(error); + } +}; + +const blocklistEmptyMessage = async (ctx) => { + try { + ctx.reply(ctx.i18n.t('blocklist_empty')); + } catch (error) { + logger.error(error); + } +}; + +module.exports = { userAlreadyBlocked, userBlocked, userUnblocked, blocklistMessage, blocklistEmptyMessage, ordersInProcess } \ No newline at end of file diff --git a/bot/modules/orders/takeOrder.js b/bot/modules/orders/takeOrder.js index 03a175f3..5a06cbd5 100644 --- a/bot/modules/orders/takeOrder.js +++ b/bot/modules/orders/takeOrder.js @@ -1,6 +1,6 @@ // @ts-check const { logger } = require('../../../logger'); -const { Order } = require('../../../models'); +const { Order, Block, User } = require('../../../models'); const { deleteOrderFromChannel } = require('../../../util'); const messages = require('../../messages'); const { @@ -48,6 +48,18 @@ exports.takebuy = async (ctx, bot, orderId) => { if (!(await validateObjectId(ctx, orderId))) return; const order = await Order.findOne({ _id: orderId }); if (!order) return; + + const userOffer = await User.findOne({_id: order.buyer_id}); + + const userOfferIsBlocked = await Block.exists({ blocker_tg_id: user.tg_id, blocked_tg_id: userOffer.tg_id }); + const takerIsBlocked = await Block.exists({blocker_tg_id: userOffer.tg_id, blocked_tg_id: user.tg_id}); + + if (userOfferIsBlocked) + return await messages.userOrderIsBlockedByUserTaker(ctx, user); + + if (takerIsBlocked) + return await messages.userTakerIsBlockedByUserOrder(ctx, user); + // We verify if the user is not banned on this community if (await isBannedFromCommunity(user, order.community_id)) return await messages.bannedUserErrorMessage(ctx, user); @@ -74,6 +86,17 @@ exports.takesell = async (ctx, bot, orderId) => { if (!orderId) return; const order = await Order.findOne({ _id: orderId }); if (!order) return; + const seller = await User.findOne({_id: order.seller_id}); + + const sellerIsBlocked = await Block.exists({ blocker_tg_id: user.tg_id, blocked_tg_id: seller.tg_id }); + const buyerIsBlocked = await Block.exists({blocker_tg_id: seller.tg_id, blocked_tg_id: user.tg_id}); + + if (sellerIsBlocked) + return await messages.userOrderIsBlockedByUserTaker(ctx, user); + + if (buyerIsBlocked) + return await messages.userTakerIsBlockedByUserOrder(ctx, user); + // We verify if the user is not banned on this community if (await isBannedFromCommunity(user, order.community_id)) return await messages.bannedUserErrorMessage(ctx, user); diff --git a/bot/start.ts b/bot/start.ts index 876d4278..1bcc8255 100644 --- a/bot/start.ts +++ b/bot/start.ts @@ -29,6 +29,7 @@ const NostrModule = require('./modules/nostr'); const OrdersModule = require('./modules/orders'); const UserModule = require('./modules/user'); const DisputeModule = require('./modules/dispute'); +const BlockModule = require('./modules/block'); const { rateUser, cancelAddInvoice, @@ -257,6 +258,7 @@ const initialize = (botToken: string, options: Partial { try { diff --git a/locales/de.yaml b/locales/de.yaml index d3182561..5b16244e 100644 --- a/locales/de.yaml +++ b/locales/de.yaml @@ -634,3 +634,10 @@ privacy: | *2. Wie wir die Informationen verwenden:* - _Reputationssystem:_ Um das Reputationssystem für jeden Benutzer aufzubauen und zu pflegen. - _Streitbeilegung:_ Im Falle eines Streits stellen wir dem Mediator (Löser) die folgenden Informationen zur Verfügung: Ihren Benutzernamen, Ihre Telegram-ID, die Anzahl der abgeschlossenen Transaktionen, die Bewertung des Gegenübers, die Anzahl der Tage, an denen Sie den Bot verwendet haben, und die Anzahl der angesammelten Streitfälle. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/en.yaml b/locales/en.yaml index a9d73982..aeaf4dab 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -635,3 +635,10 @@ privacy: | *2. How We Use the Information:* - _Reputation System:_ To build and maintain the reputation system for each user. - _Dispute Resolution:_ In case of a dispute, we provide the mediator (solver) with the following information: your username, Telegram ID, number of completed transactions, counterpart's rating, number of days using the bot, and the number of accumulated disputes. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/es.yaml b/locales/es.yaml index 26cbc22a..a71c1ab1 100644 --- a/locales/es.yaml +++ b/locales/es.yaml @@ -634,3 +634,10 @@ privacy: | *2. Cómo Utilizamos la Información:* - _Sistema de Reputación:_ Para construir y mantener el sistema de reputación de cada usuario. - _Resolución de Disputas:_ En caso de una disputa, proporcionamos al mediador (solver) la siguiente información: tu nombre de usuario, ID de Telegram, número de transacciones concretadas, calificación de la contraparte, cantidad de días usando el bot y el número de disputas acumuladas. +user_already_blocked: El usuario ya está bloqueado +user_blocked: Usuario bloqueado correctamente +user_unblocked: Usuario desbloqueado correctamente +blocklist_empty: No tienes ningun usuario bloqueado +orders_in_process: Hay ordenes en proceso con este usuario +user_order_is_blocked_by_user_taker: No puedes aceptar esta oferta porque has bloqueado a su creador +user_taker_is_blocked_by_user_order: No puedes aceptar esta oferta porque su creador te ha bloqueado diff --git a/locales/fa.yaml b/locales/fa.yaml index 64fa703a..b1db3f52 100644 --- a/locales/fa.yaml +++ b/locales/fa.yaml @@ -633,3 +633,10 @@ privacy: | *۲. نحوه استفاده ما از اطلاعات:* - _سیستم اعتبار:_ برای ایجاد و حفظ سیستم اعتبار برای هر کاربر. - _حل اختلافات:_ در صورت بروز اختلاف، اطلاعات زیر را در اختیار میانجی (حل‌کننده) قرار می‌دهیم: نام کاربری شما، شناسه تلگرام، تعداد تراکنش‌های انجام شده، امتیاز طرف مقابل، تعداد روزهایی که از ربات استفاده کرده‌اید و تعداد اختلافات جمع شده. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/fr.yaml b/locales/fr.yaml index 7fe68d21..de705839 100644 --- a/locales/fr.yaml +++ b/locales/fr.yaml @@ -633,3 +633,10 @@ privacy: | *2. Comment nous utilisons les informations:* - _Système de réputation:_ Pour construire et maintenir le système de réputation de chaque utilisateur. - _Résolution des litiges:_ En cas de litige, nous fournissons au médiateur (solver) les informations suivantes : votre nom d'utilisateur, votre identifiant Telegram, le nombre de transactions effectuées, la note de la contrepartie, le nombre de jours d'utilisation du bot et le nombre de litiges accumulés. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/it.yaml b/locales/it.yaml index b46301fe..ee649976 100644 --- a/locales/it.yaml +++ b/locales/it.yaml @@ -631,3 +631,10 @@ privacy: | *2. Come utilizziamo le informazioni:* - _Sistema di reputazione:_ Per costruire e mantenere il sistema di reputazione di ciascun utente. - _Risoluzione delle controversie:_ In caso di controversia, forniamo al mediatore (solver) le seguenti informazioni: il tuo nome utente, ID Telegram, numero di transazioni completate, valutazione della controparte, numero di giorni di utilizzo del bot e numero di controversie accumulate. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/ko.yaml b/locales/ko.yaml index cd019dab..440ff445 100644 --- a/locales/ko.yaml +++ b/locales/ko.yaml @@ -629,3 +629,10 @@ privacy: | *2. 정보 사용 방법:* - _평판 시스템:_ 각 사용자의 평판 시스템을 구축하고 유지하기 위해 사용됩니다. - _분쟁 해결:_ 분쟁이 발생할 경우, 중재자(해결자)에게 사용자 이름, Telegram ID, 완료된 거래 수, 상대방의 평가, 봇 사용 일수, 누적된 분쟁 수와 같은 정보를 제공합니다. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/pt.yaml b/locales/pt.yaml index 21c518e0..f4e888c5 100644 --- a/locales/pt.yaml +++ b/locales/pt.yaml @@ -631,3 +631,10 @@ privacy: | *2. Como Usamos as Informações:* - _Sistema de Reputação:_ Para construir e manter o sistema de reputação de cada usuário. - _Resolução de Disputas:_ Em caso de uma disputa, fornecemos ao mediador (solver) as seguintes informações: seu nome de usuário, ID do Telegram, número de transações concluídas, classificação da contraparte, número de dias usando o bot e o número de disputas acumuladas. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/ru.yaml b/locales/ru.yaml index 32c5c2d2..3dd6fa58 100644 --- a/locales/ru.yaml +++ b/locales/ru.yaml @@ -634,3 +634,10 @@ privacy: | *2. Как мы используем информацию:* - _Система репутации:_ Для создания и поддержания системы репутации каждого пользователя. - _Разрешение споров:_ В случае спора мы предоставляем медиатору (решателю) следующую информацию: ваше имя пользователя, ID Telegram, количество завершенных транзакций, рейтинг контрагента, количество дней использования бота и количество накопленных споров. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/locales/uk.yaml b/locales/uk.yaml index 60ef8e2c..37b364d8 100644 --- a/locales/uk.yaml +++ b/locales/uk.yaml @@ -630,3 +630,10 @@ privacy: | *2. Як ми використовуємо інформацію:* - _Система репутації:_ Для створення та підтримки системи репутації для кожного користувача. - _Розв'язання спорів:_ У разі спору ми надаємо медіатору (розв'язувачу) наступну інформацію: ваше ім’я користувача, ID Telegram, кількість завершених транзакцій, рейтинг контрагента, кількість днів використання бота та кількість накопичених спорів. +user_already_blocked: User is already blocked +user_blocked: User successfully blocked +user_unblocked: User successfully unblocked +blocklist_empty: You do not have any blocked user +orders_in_process: There are orders in process with this user +user_order_is_blocked_by_user_taker: You can't take this order because you blocked its maker +user_taker_is_blocked_by_user_order: You can't take this order because its maker blocked you diff --git a/models/block.ts b/models/block.ts new file mode 100644 index 00000000..6243cb53 --- /dev/null +++ b/models/block.ts @@ -0,0 +1,15 @@ +import mongoose, { Document, Schema } from 'mongoose'; + +export interface IBlock extends Document { + blocker_tg_id: string; + blocked_tg_id: string; + created_at: Date; +} + +const blockSchema = new Schema({ + blocker_tg_id: { type: String }, + blocked_tg_id: { type: String }, + created_at: { type: Date, default: Date.now }, +}); + +export default mongoose.model('Block', blockSchema); diff --git a/models/index.ts b/models/index.ts index 6fd610a7..e05db538 100644 --- a/models/index.ts +++ b/models/index.ts @@ -4,6 +4,7 @@ import PendingPayment from './pending_payment' import Community from './community' import Dispute from './dispute' import Config from './config' +import Block from './block' export { User, @@ -12,4 +13,5 @@ export { Community, Dispute, Config, + Block };