Skip to content
1 change: 1 addition & 0 deletions bot/middleware/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const stageMiddleware = () => {
CommunityModule.Scenes.updateFeeCommunityWizard,
CommunityModule.Scenes.updateDisputeChannelCommunityWizard,
CommunityModule.Scenes.updateLanguageCommunityWizard,
CommunityModule.Scenes.updatePaymentMethodsCommunityWizard,
CommunityModule.Scenes.addEarningsInvoiceWizard,
addInvoicePHIWizard,
OrdersModule.Scenes.createOrder,
Expand Down
6 changes: 6 additions & 0 deletions bot/modules/community/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ export const updateCommunity = async (
user,
community,
});
} else if (field === 'payment_methods') {
ctx.scene.enter('UPDATE_PAYMENT_METHODS_COMMUNITY_WIZARD_SCENE_ID', {
id,
user,
community,
});
}
} catch (error) {
logger.error(error);
Expand Down
1 change: 1 addition & 0 deletions bot/modules/community/communityContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface CommunityWizardState {
seller: UserDocument;
type: string;
method: string;
selectedMethods: string[];
bot: CommunityContext;
message: Message.TextMessage | undefined;
error?: any;
Expand Down
7 changes: 7 additions & 0 deletions bot/modules/community/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ export const configure = (bot: Telegraf<CommunityContext>) => {
bot.action(/^editLanguageBtn_([0-9a-f]{24})$/, userMiddleware, async ctx => {
await commands.updateCommunity(ctx, ctx.match[1], 'language');
});
bot.action(
/^editPaymentMethodsBtn_([0-9a-f]{24})$/,
userMiddleware,
async ctx => {
await commands.updateCommunity(ctx, ctx.match[1], 'payment_methods');
},
);

bot.command('findcomms', userMiddleware, commands.findCommunity);
bot.action(
Expand Down
6 changes: 6 additions & 0 deletions bot/modules/community/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ export const updateCommunityMessage = async (ctx: MainContext) => {
callback_data: `editLanguageBtn_${id}`,
},
],
[
{
text: '✏️ ' + ctx.i18n.t('community_payment_methods'),
callback_data: `editPaymentMethodsBtn_${id}`,
},
],
[
{
text: '💰 ' + ctx.i18n.t('earnings'),
Expand Down
63 changes: 63 additions & 0 deletions bot/modules/community/scenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,69 @@ export const updateLanguageCommunityWizard = new Scenes.WizardScene(
},
);

export const updatePaymentMethodsCommunityWizard = new Scenes.WizardScene(
'UPDATE_PAYMENT_METHODS_COMMUNITY_WIZARD_SCENE_ID',
async (ctx: CommunityContext) => {
try {
const { community } = ctx.wizard.state;
const current = community.payment_methods?.join(', ') || '';
let message = current
? ctx.i18n.t('current_payment_methods', { methods: current }) + '\n\n'
: '';
message += ctx.i18n.t('enter_community_payment_methods') + '\n\n';
message += ctx.i18n.t('payment_methods_wizard_commands');
await ctx.reply(message);
return ctx.wizard.next();
} catch (error) {
logger.error(error);
ctx.scene.leave();
}
},
async (ctx: CommunityContext) => {
try {
if (ctx.message === undefined) return ctx.scene.leave();
if (!('text' in ctx.message)) return;

const text = ctx.message.text.trim();
const methods = text
.split(',')
.map(m => m.trim())
.filter(m => m.length > 0);

const max = 20;
if (methods.length > max) {
return await ctx.reply(ctx.i18n.t('max_allowed', { max }));
}

const { community } = ctx.wizard.state;
community.payment_methods = methods;
await community.save();
await ctx.reply(ctx.i18n.t('payment_methods_saved'));

return ctx.scene.leave();
} catch (error) {
logger.error(error);
ctx.scene.leave();
}
},
);

updatePaymentMethodsCommunityWizard.command(
'reset',
async (ctx: CommunityContext) => {
try {
const { community } = ctx.wizard.state;
community.payment_methods = [];
await community.save();
await ctx.reply(ctx.i18n.t('payment_methods_reset'));
return ctx.scene.leave();
} catch (error) {
logger.error(error);
ctx.scene.leave();
}
},
);

export const addEarningsInvoiceWizard = new Scenes.WizardScene(
'ADD_EARNINGS_INVOICE_WIZARD_SCENE_ID',
async (ctx: CommunityContext) => {
Expand Down
152 changes: 139 additions & 13 deletions bot/modules/orders/scenes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Scenes, Markup } from 'telegraf';
import { logger } from '../../../logger';
import { getCurrency } from '../../../util';
import { Community } from '../../../models';
import * as ordersActions from '../../ordersActions';
import {
publishBuyOrderMessage,
Expand Down Expand Up @@ -30,6 +31,7 @@ export const createOrder = new Scenes.WizardScene(
sats,
priceMargin,
method,
selectedMethods,
} = ctx.wizard.state;
if (!statusMessage) {
const { text } = messages.createOrderWizardStatus(
Expand Down Expand Up @@ -64,8 +66,10 @@ export const createOrder = new Scenes.WizardScene(
if (undefined === priceMargin && sats === 0)
return createOrderSteps.priceMargin(ctx);
if (undefined === method) return createOrderSteps.method(ctx);
// We remove all special characters from the payment method
const paymentMethod = method.replace(/[&/\\#,+~%.'":*?<>{}]/g, '');
let paymentMethod = selectedMethods?.length
? selectedMethods.join(', ')
: method;
paymentMethod = paymentMethod.replace(/[&/\\#,+~%.'":*?<>{}]/g, '');

Comment thread
Luquitasjeffrey marked this conversation as resolved.
const order = await ordersActions.createOrder(ctx.i18n, ctx, user, {
type,
Expand Down Expand Up @@ -145,19 +149,141 @@ const createOrderSteps = {
return ctx.wizard.next();
},
async method(ctx: CommunityContext) {
ctx.wizard.state.handler = async ctx => {
if (ctx.message === undefined) return ctx.scene.leave();
const { text } = ctx.message;
if (!text) return;
ctx.wizard.state.method = text;
await ctx.wizard.state.updateUI();
await ctx.deleteMessage();
return await ctx.telegram.deleteMessage(
prompt.chat.id,
prompt.message_id,
const { user } = ctx.wizard.state;
const stateComm = ctx.wizard.state.community;
const loadedComm =
!stateComm && user?.default_community_id
? await Community.findById(user.default_community_id)
: null;
const community = stateComm ?? loadedComm;
if (loadedComm) ctx.wizard.state.community = loadedComm;
const paymentMethods = community?.payment_methods;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if (!paymentMethods || paymentMethods.length === 0) {
ctx.wizard.state.handler = async ctx => {
if (ctx.message === undefined) return ctx.scene.leave();
if (!('text' in ctx.message)) return;
const { text } = ctx.message;
if (!text) return;
ctx.wizard.state.method = text;
await ctx.wizard.state.updateUI();
await ctx.deleteMessage();
return await ctx.telegram.deleteMessage(
prompt.chat.id,
prompt.message_id,
);
};
const prompt = await ctx.reply(ctx.i18n.t('enter_payment_method'));
return ctx.wizard.next();
}

ctx.wizard.state.selectedMethods = [];
const i18n = ctx.i18n;

const buildKeyboard = (selected: string[]) => {
const buttons = paymentMethods.map((m, i) =>
Markup.button.callback(
(selected.includes(m) ? '✓ ' : '') + m,
`pm_toggle_${i}`,
),
);
const rows = [];
for (let i = 0; i < buttons.length; i += 2) {
rows.push(buttons.slice(i, i + 2));
}
rows.push([
Markup.button.callback(i18n.t('confirm_payment_methods'), 'pm_confirm'),
]);
rows.push([
Markup.button.callback(i18n.t('custom_payment_method'), 'pm_custom'),
]);
return Markup.inlineKeyboard(rows);
};

const prompt = await ctx.reply(
ctx.i18n.t('select_payment_methods'),
buildKeyboard([]),
);

ctx.wizard.state.handler = async ctx => {
if (!ctx.callbackQuery) {
if (ctx.message === undefined || !('text' in ctx.message)) return;
const { text } = ctx.message;
if (!text) return;
ctx.wizard.state.method = text;
await ctx.wizard.state.updateUI();
await ctx.deleteMessage();
await ctx.telegram.deleteMessage(prompt.chat.id, prompt.message_id);
return true;
}

const data = (ctx.callbackQuery as any).data as string;

if (data === 'pm_confirm') {
const selected = ctx.wizard.state.selectedMethods || [];
if (selected.length === 0) {
await ctx.answerCbQuery(ctx.i18n.t('no_payment_method_selected'));
return;
}
ctx.wizard.state.method = selected.join(', ');
await ctx.wizard.state.updateUI();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
await ctx.telegram.deleteMessage(prompt.chat.id, prompt.message_id);
await ctx.answerCbQuery();
return true;
}

if (data === 'pm_custom') {
await ctx.telegram.deleteMessage(prompt.chat.id, prompt.message_id);
await ctx.answerCbQuery();
const textPrompt = await ctx.reply(ctx.i18n.t('enter_payment_method'));
ctx.wizard.state.handler = async ctx => {
if (ctx.message === undefined || !('text' in ctx.message)) return;
const { text } = ctx.message;
if (!text) return;
ctx.wizard.state.method = text;
await ctx.wizard.state.updateUI();
await ctx.deleteMessage();
await ctx.telegram.deleteMessage(
textPrompt.chat.id,
textPrompt.message_id,
);
return true;
};
return;
}

if (data.startsWith('pm_toggle_')) {
const methodIdx = parseInt(data.slice('pm_toggle_'.length), 10);
const m = paymentMethods[methodIdx];
if (m === undefined) {
await ctx.answerCbQuery();
return;
}
const selected = ctx.wizard.state.selectedMethods || [];
const idx = selected.indexOf(m);
if (idx >= 0) {
selected.splice(idx, 1);
} else {
selected.push(m);
}
ctx.wizard.state.selectedMethods = selected;
try {
await ctx.telegram.editMessageReplyMarkup(
prompt.chat.id,
prompt.message_id,
undefined,
buildKeyboard(selected).reply_markup,
);
} catch (_err) {
// ignore transient errors (e.g. "message is not modified" on rapid taps)
}
Comment thread
Luquitasjeffrey marked this conversation as resolved.
await ctx.answerCbQuery();
return;
}

await ctx.answerCbQuery();
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const prompt = await ctx.reply(ctx.i18n.t('enter_payment_method'));

return ctx.wizard.next();
},
async priceMargin(ctx: CommunityContext) {
Expand Down
10 changes: 10 additions & 0 deletions locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -706,3 +706,13 @@ unblock_failed: "Fehler beim Freigeben des Benutzers"
check_solvers: Ihre Community ${communityName} hat keine Solver. Bitte fügen Sie innerhalb von ${remainingDays} Tagen mindestens einen hinzu, um zu verhindern, dass die Community deaktiviert wird.
check_solvers_last_warning: Ihre Community ${communityName} hat keine Solver. Bitte fügen Sie noch heute mindestens einen hinzu, um zu verhindern, dass die Community deaktiviert wird.
image_processing_error: Wir hatten einen Fehler beim Verarbeiten des Bildes, bitte warten Sie ein paar Minuten und versuchen Sie es erneut.
community_payment_methods: "Zahlungsmethoden"
enter_community_payment_methods: "Gib die in deiner Community akzeptierten Zahlungsmethoden ein, getrennt durch Kommas (z.B.: Banküberweisung, Bargeld, PayPal)"
current_payment_methods: "Aktuelle Zahlungsmethoden: ${methods}"
select_payment_methods: "Wähle eine oder mehrere Zahlungsmethoden:"
confirm_payment_methods: "✅ Bestätigen"
no_payment_method_selected: "Bitte wähle mindestens eine Zahlungsmethode aus"
payment_methods_saved: "Zahlungsmethoden gespeichert ✅"
custom_payment_method: "✍️ Benutzerdefinierte Zahlungsmethode"
payment_methods_reset: "Zahlungsmethoden entfernt. Benutzer können jetzt beliebige Zahlungsmethoden frei eingeben."
payment_methods_wizard_commands: "/reset — alle Zahlungsmethoden entfernen und Standardverhalten wiederherstellen\n/exit — ohne Speichern beenden"
10 changes: 10 additions & 0 deletions locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -711,3 +711,13 @@ unblock_failed: "Error unblocking the user"
check_solvers: Your community ${communityName} does not have any solvers. Please add at least one within ${remainingDays} days to prevent the community from being disabled.
check_solvers_last_warning: Your community ${communityName} does not have any solvers. Please add at least one today to prevent the community from being disabled.
image_processing_error: We had an error processing the image, please wait a few minutes and try again
community_payment_methods: "Payment methods"
enter_community_payment_methods: "Enter the payment methods accepted in your community, separated by commas (e.g.: Bank transfer, Cash, PayPal)"
current_payment_methods: "Current payment methods: ${methods}"
select_payment_methods: "Select one or more payment methods:"
confirm_payment_methods: "✅ Confirm"
no_payment_method_selected: "Please select at least one payment method"
payment_methods_saved: "Payment methods saved ✅"
custom_payment_method: "✍️ Custom payment method"
payment_methods_reset: "Payment methods removed. Users can now enter any payment method freely."
payment_methods_wizard_commands: "/reset — remove all payment methods and restore default behavior\n/exit — exit without saving"
10 changes: 10 additions & 0 deletions locales/es.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,13 @@ unblock_failed: "Error al desbloquear al usuario"
image_processing_error: Hemos tenido un error procesando la imagen, por favor espera unos minutos y vuelve a intentarlo.
check_solvers: Tu comunidad ${communityName} no tiene ningún solucionador. Agregue al menos uno dentro de ${remainingDays} días para evitar que se deshabilite la comunidad.
check_solvers_last_warning: Tu comunidad ${communityName} no tiene ningún solucionador. Agregue al menos uno hoy para evitar que la comunidad quede inhabilitada.
community_payment_methods: "Métodos de pago"
enter_community_payment_methods: "Ingresa los métodos de pago aceptados en tu comunidad, separados por comas (ej.: Transferencia bancaria, Efectivo, PayPal)"
current_payment_methods: "Métodos de pago actuales: ${methods}"
select_payment_methods: "Selecciona uno o más métodos de pago:"
confirm_payment_methods: "✅ Confirmar"
no_payment_method_selected: "Por favor selecciona al menos un método de pago"
payment_methods_saved: "Métodos de pago guardados ✅"
custom_payment_method: "✍️ Método de pago personalizado"
payment_methods_reset: "Métodos de pago eliminados. Los usuarios ahora pueden ingresar cualquier método de pago libremente."
payment_methods_wizard_commands: "/reset — eliminar todos los métodos de pago y restaurar el comportamiento predeterminado\n/exit — salir sin guardar"
10 changes: 10 additions & 0 deletions locales/fa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -805,3 +805,13 @@ unblock_failed: "خطا در رفع مسدودیت کاربر"
check_solvers: اجتماع شما ${communityName} هیچ داوری ندارد. لطفاً برای جلوگیری از غیرفعال شدن اجتماع، تا ${remainingDays} روز آینده حداقل یک داور به آن اضافه کنید.
check_solvers_last_warning: اجتماع شما ${communityName} هیچ داوری ندارد. برای جلوگیری از غیرفعال شدن اجتماع، امروز حداقل یک داور به آن اضافه کنید.
image_processing_error: هنگام پردازش تصویر با خطایی مواجه شدیم، لطفاً چند دقیقه صبر کرده و دوباره امتحان کنید.
community_payment_methods: "روش‌های پرداخت"
enter_community_payment_methods: "روش‌های پرداخت پذیرفته‌شده در اجتماع خود را با کاما از هم جدا کرده وارد کنید (مثال: انتقال بانکی، نقد، PayPal)"
current_payment_methods: "روش‌های پرداخت فعلی: ${methods}"
select_payment_methods: "یک یا چند روش پرداخت انتخاب کنید:"
confirm_payment_methods: "✅ تأیید"
no_payment_method_selected: "لطفاً حداقل یک روش پرداخت انتخاب کنید"
payment_methods_saved: "روش‌های پرداخت ذخیره شد ✅"
custom_payment_method: "✍️ روش پرداخت سفارشی"
payment_methods_reset: "روش‌های پرداخت حذف شدند. کاربران اکنون می‌توانند هر روش پرداختی را آزادانه وارد کنند."
payment_methods_wizard_commands: "/reset — حذف همه روش‌های پرداخت و بازگرداندن رفتار پیش‌فرض\n/exit — خروج بدون ذخیره"
10 changes: 10 additions & 0 deletions locales/fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -705,3 +705,13 @@ unblock_failed: "Erreur lors du déblocage de l'utilisateur"
check_solvers: Votre communauté ${communityName} ne possède aucun solveur. Veuillez en ajouter au moins un dans les ${remainingDays} jours pour éviter que la communauté ne soit désactivée.
check_solvers_last_warning: Votre communauté ${communityName} ne possède aucun solveur. Veuillez en ajouter au moins un aujourd'hui pour éviter que la communauté ne soit désactivée.
image_processing_error: Nous avons eu une erreur lors du traitement de l'image, veuillez attendre quelques minutes et réessayer.
community_payment_methods: "Méthodes de paiement"
enter_community_payment_methods: "Entrez les méthodes de paiement acceptées dans votre communauté, séparées par des virgules (ex. : Virement bancaire, Espèces, PayPal)"
current_payment_methods: "Méthodes de paiement actuelles : ${methods}"
select_payment_methods: "Sélectionnez une ou plusieurs méthodes de paiement :"
confirm_payment_methods: "✅ Confirmer"
no_payment_method_selected: "Veuillez sélectionner au moins une méthode de paiement"
payment_methods_saved: "Méthodes de paiement enregistrées ✅"
custom_payment_method: "✍️ Méthode de paiement personnalisée"
payment_methods_reset: "Méthodes de paiement supprimées. Les utilisateurs peuvent désormais saisir n'importe quelle méthode de paiement librement."
payment_methods_wizard_commands: "/reset — supprimer toutes les méthodes de paiement et restaurer le comportement par défaut\n/exit — quitter sans enregistrer"
10 changes: 10 additions & 0 deletions locales/it.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -703,3 +703,13 @@ unblock_failed: "Errore nello sbloccare l'utente"
check_solvers: La tua community ${communityName} non ha risolutori. Aggiungine almeno uno entro ${remainingDays} giorni per evitare che la community venga disabilitata.
check_solvers_last_warning: La tua community ${communityName} non ha risolutori. Per favore aggiungine almeno uno oggi per evitare che la community venga disabilitata.
image_processing_error: Abbiamo avuto un errore nel processare l'immagine, per favore attendi qualche minuto e prova di nuovo.
community_payment_methods: "Metodi di pagamento"
enter_community_payment_methods: "Inserisci i metodi di pagamento accettati nella tua community, separati da virgole (es.: Bonifico bancario, Contanti, PayPal)"
current_payment_methods: "Metodi di pagamento attuali: ${methods}"
select_payment_methods: "Seleziona uno o più metodi di pagamento:"
confirm_payment_methods: "✅ Conferma"
no_payment_method_selected: "Seleziona almeno un metodo di pagamento"
payment_methods_saved: "Metodi di pagamento salvati ✅"
custom_payment_method: "✍️ Metodo di pagamento personalizzato"
payment_methods_reset: "Metodi di pagamento rimossi. Gli utenti possono ora inserire qualsiasi metodo di pagamento liberamente."
payment_methods_wizard_commands: "/reset — rimuovere tutti i metodi di pagamento e ripristinare il comportamento predefinito\n/exit — uscire senza salvare"
Loading
Loading