Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env-sample
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ NOSTR_SK=''
# Number of currencies allowed in a community
COMMUNITY_CURRENCIES=20

# Max number of payment methods that can be configured in a community for wizzard selection
MAX_COMMUNITY_PAYMENT_METHODS=10

# List of relays to connect to
RELAYS='ws://localhost:7000,ws://localhost:8000,ws://localhost:9000'

Expand Down
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 = parseInt(process.env.MAX_COMMUNITY_PAYMENT_METHODS || '10');
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();
Comment thread
Luquitasjeffrey marked this conversation as resolved.
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
155 changes: 142 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,11 @@ 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, '');

const replaceRegex = /[&/\\#,+~%.'":*?<>{}]/g;
const paymentMethod = selectedMethods?.length
? selectedMethods.map(m => m.replace(replaceRegex, '')).join(', ')
: method.replace(replaceRegex, '');

const order = await ordersActions.createOrder(ctx.i18n, ctx, user, {
type,
Expand Down Expand Up @@ -145,19 +150,143 @@ 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;

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('enter_payment_method'));

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.selectedMethods = [];
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();
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.selectedMethods = [];
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;
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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)
}
await ctx.answerCbQuery();
return;
}

await ctx.answerCbQuery();
};

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 @@ -707,3 +707,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 @@ -712,3 +712,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 @@ -709,3 +709,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 @@ -806,3 +806,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 @@ -706,3 +706,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"
Loading
Loading