Skip to content

Commit

Permalink
Add random image after order creation
Browse files Browse the repository at this point in the history
The seller receives an image once an order is created. They will also receive the same image when paying the invoice.

This way, they can verify that the invoice originates from the bot.

Signed-off-by: ndungudedan <[email protected]>
  • Loading branch information
ndungudedan committed Dec 21, 2024
1 parent 4b278ce commit 8bee9f5
Show file tree
Hide file tree
Showing 17 changed files with 97 additions and 24 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
.env
admin.macaroon
tls.cert
dist/
dist/
.history/
3 changes: 2 additions & 1 deletion bot/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,8 @@ const showHoldInvoice = async (ctx, bot, order) => {
request,
amount,
order.fiat_code,
order.fiat_amount
order.fiat_amount,
order.random_image
);
} catch (error) {
logger.error(`Error in showHoldInvoice: ${error}`);
Expand Down
50 changes: 34 additions & 16 deletions bot/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,14 @@ const invoicePaymentRequestMessage = async (
rate,
days: ageInDays,
});
await ctx.telegram.sendMessage(user.tg_id, message);

await ctx.telegram.sendMediaGroup(user.tg_id, [{
type: 'photo',
media: { source: Buffer.from(order.random_image, 'base64') },
caption: `${message}`,
}]
);

// Create QR code
const qrBytes = await QR.toBuffer(request);
// Send payment request in QR and text
Expand All @@ -107,13 +114,17 @@ const pendingSellMessage = async (ctx: Telegraf<MainContext>, user: UserDocument
try {
const orderExpirationWindow =
Number(process.env.ORDER_PUBLISHED_EXPIRATION_WINDOW) / 60 / 60;
await ctx.telegram.sendMessage(
user.tg_id,
i18n.t('pending_sell', {

await ctx.telegram.sendMediaGroup(user.tg_id, [{
type: 'photo',
media: { source: Buffer.from(order.random_image, 'base64') },
caption: `${i18n.t('pending_sell', {
channel,
orderExpirationWindow: Math.round(orderExpirationWindow),
})
})}`,
}]
);

await ctx.telegram.sendMessage(
user.tg_id,
i18n.t('cancel_order_cmd', { orderId: order._id }),
Expand Down Expand Up @@ -318,10 +329,14 @@ const beginTakeBuyMessage = async (ctx: MainContext, bot: Telegraf<MainContext>,
try {
const expirationTime =
Number(process.env.HOLD_INVOICE_EXPIRATION_WINDOW) / 60;
await bot.telegram.sendMessage(
seller.tg_id,
ctx.i18n.t('begin_take_buy', { expirationTime })

await bot.telegram.sendMediaGroup(seller.tg_id, [{
type: 'photo',
media: { source: Buffer.from(order.random_image, 'base64') },
caption: `${ctx.i18n.t('begin_take_buy', { expirationTime })}`,
}]
);

await bot.telegram.sendMessage(seller.tg_id, order._id, {
reply_markup: {
inline_keyboard: [
Expand All @@ -348,21 +363,25 @@ const showHoldInvoiceMessage = async (
request: string,
amount: number,
fiatCode: IOrder["fiat_code"],
fiatAmount: IOrder["fiat_amount"]
fiatAmount: IOrder["fiat_amount"],
randomImage: IOrder["random_image"]
) => {
try {
let currency = getCurrency(fiatCode);
currency =
!!currency && !!currency.symbol_native
? currency.symbol_native
: fiatCode;
await ctx.reply(
ctx.i18n.t('pay_invoice', {
await ctx.replyWithMediaGroup([{
type: 'photo',
media: { source: Buffer.from(randomImage, 'base64') },
caption: `${ctx.i18n.t('pay_invoice', {
amount: numberFormat(fiatCode, amount),
fiatAmount: numberFormat(fiatCode, fiatAmount),
currency,
})
);
})}`,
}]);

// Create QR code
const qrBytes = await QR.toBuffer(request);
// Send payment request in QR and text
Expand Down Expand Up @@ -1597,9 +1616,8 @@ const showConfirmationButtons = async (ctx: MainContext, orders: Array<IOrder>,
};
})
.map(ord => ({
text: `${ord._id.slice(0, 2)}..${ord._id.slice(-2)} - ${ord.type} - ${
ord.fiat
} ${ord.amount}`,
text: `${ord._id.slice(0, 2)}..${ord._id.slice(-2)} - ${ord.type} - ${ord.fiat
} ${ord.amount}`,
callback_data: `${commandString}_${ord._id}`,
}));
inlineKeyboard.push(lineBtn);
Expand Down
5 changes: 5 additions & 0 deletions bot/ordersActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
getFee,
getUserAge,
getStars,
generateRandomImage,
} = require('../util');
const { logger } = require('../logger');

Expand Down Expand Up @@ -99,6 +100,10 @@ const createOrder = async (
}
await order.save();

const randomImage = await generateRandomImage(order._id);
order.random_image = randomImage;
await order.save();

if (order.status !== 'PENDING') {
OrderEvents.orderUpdated(order);
}
Expand Down
Binary file added images/bible.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/blue_car.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cave.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cup.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/desert.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/flower.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/grapes.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/hay.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/river.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/road.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 13 additions & 2 deletions locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,16 @@ invoice_payment_request: |

Buyer Reputation: ${rate}, days using the bot: ${days}

Note: Confirm that the attached image matches the one sent during order creation before paying the invoice

Please pay this invoice to start up your selling process, it will expire in ${expirationTime} minutes
pending_sell: |
📝 Your offer has been published in the ${channel} channel

You have to wait until another user picks your order, it will be available for ${orderExpirationWindow} hours in the channel

Note: You will see this same image at the time of paying the invoice

You can cancel this order before another user picks it up by executing the command 👇
cancel_order_cmd: |
/cancel ${orderId}
Expand Down Expand Up @@ -101,10 +105,17 @@ order_already_taken: This order has already been taken by another user.
order_already_settled: This order has already been settled.
invalid_data: You have sent invalid data, try again.
begin_take_buy: |
🤖 Press Continue to take the offer, if you press Cancel, you will be released from the order and it will be republished. You have ${expirationTime} minutes before this order expires. 👇
🤖 Press Continue to take the offer, if you press Cancel, you will be released from the order and it will be republished.

Note: You will see this same image at the time of paying the invoice

You have ${expirationTime} minutes before this order expires. 👇
continue: Continue
cancel: Cancel
pay_invoice: Please pay this invoice of ${amount} sats for ${currency} ${fiatAmount} to start the operation.
pay_invoice: |
Note: Confirm that the attached image matches the one sent during order creation before paying the invoice

Please pay this invoice of ${amount} sats for ${currency} ${fiatAmount} to start the operation
payment_received: |
🤑 Payment received!

Expand Down
2 changes: 2 additions & 0 deletions models/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface IOrder extends Document {
community_id: string;
is_frozen: boolean;
is_public: boolean;
random_image: string;
}

const orderSchema = new Schema<IOrder>({
Expand Down Expand Up @@ -138,6 +139,7 @@ const orderSchema = new Schema<IOrder>({
community_id: { type: String },
is_public: { type: Boolean, default: true },
is_frozen: { type: Boolean, default: false },
random_image: { type: String },
});

export default mongoose.model<IOrder>('Order', orderSchema);
43 changes: 39 additions & 4 deletions util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import fiatJson from './fiat.json';
import languagesJson from './languages.json';
import { Order, Community } from "../models";
import { logger } from "../logger";
const fs = require('fs').promises;
const path = require('path');
const { I18n } = require('@grammyjs/i18n');
// ISO 639-1 language codes

Expand Down Expand Up @@ -225,7 +227,7 @@ const decimalRound = (value: number, exp: number): number => {

const extractId = (text: string): (string | null) => {
const matches = text.match(/:([a-f0-9]{24}):$/);
if (matches !== null){
if (matches !== null) {
return matches?.[1];
}
return null;
Expand Down Expand Up @@ -380,8 +382,8 @@ const getDetailedOrder = (i18n: I18nContext, order: IOrder, buyer: UserDocument,
const fee = order.fee ? sanitizeMD(Number(order.fee)) : '';
const creator =
order.creator_id === buyerId ? buyerUsername : sellerUsername;
const buyerAge = buyer? getUserAge(buyer) : '';
const sellerAge = seller? getUserAge(seller) : '';
const buyerAge = buyer ? getUserAge(buyer) : '';
const sellerAge = seller ? getUserAge(seller) : '';
const buyerTrades = buyer ? buyer.trades_completed : 0;
const sellerTrades = seller ? seller.trades_completed : 0;
const message = i18n.t('order_detail', {
Expand Down Expand Up @@ -525,6 +527,38 @@ export const removeLightningPrefix = (invoice: string) => {
return invoice;
};

const generateRandomImage = async (nonce: string) => {
let randomImage = '';
try {
let url = `https://picsum.photos/seed/${nonce}/400/200`;
const response = await axios({
url,
method: 'GET',
responseType: 'arraybuffer'
});

randomImage = Buffer.from(response.data, 'binary').toString('base64');

} catch (error) {
logger.error(error);

try {
const files = await fs.readdir('images');
const imageFiles = files.filter(file =>
['.jpg', '.jpeg', '.png'].includes(path.extname(file).toLowerCase())
);

const randomFile = imageFiles[Math.floor(Math.random() * imageFiles.length)];
const fallbackImage = await fs.readFile(`images/${randomFile}`);

randomImage = Buffer.from(fallbackImage, 'binary').toString('base64');
} catch (fallbackError) {
logger.error(fallbackError);
}
}
return randomImage;
}

export {
isIso4217,
plural,
Expand Down Expand Up @@ -555,5 +589,6 @@ export {
getUserAge,
getTimeToExpirationOrder,
toKebabCase,
isOrderCreator
isOrderCreator,
generateRandomImage
};

0 comments on commit 8bee9f5

Please sign in to comment.