Merge pull request 'main' (#24) from main into feature/user-section
Reviewed-on: https://git.softuniq.eu/Telegram-Market/telegram-shop/pulls/24
This commit is contained in:
commit
626435a3de
1175
package-lock.json
generated
1175
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,10 +7,12 @@
|
|||||||
"dev": "nodemon src/index.js"
|
"dev": "nodemon src/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"archiver": "^7.0.1",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"bip39": "^3.1.0",
|
"bip39": "^3.1.0",
|
||||||
"bitcoinjs-lib": "^6.1.6",
|
"bitcoinjs-lib": "^6.1.6",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
|
"decompress": "^4.2.1",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"ecpair": "^2.1.0",
|
"ecpair": "^2.1.0",
|
||||||
"ethereumjs-util": "^7.1.5",
|
"ethereumjs-util": "^7.1.5",
|
||||||
|
143
src/handlers/adminDumpHandler.js
Normal file
143
src/handlers/adminDumpHandler.js
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import config from '../config/config.js';
|
||||||
|
import fs from "fs";
|
||||||
|
import db from "../config/database.js";
|
||||||
|
import archiver from "archiver";
|
||||||
|
import decompress from "decompress";
|
||||||
|
|
||||||
|
export default class AdminDumpHandler {
|
||||||
|
constructor(bot) {
|
||||||
|
this.bot = bot;
|
||||||
|
this.userStates = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin(userId) {
|
||||||
|
return config.ADMIN_IDS.includes(userId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleDump(msg) {
|
||||||
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
|
const keyboard = {
|
||||||
|
inline_keyboard: [
|
||||||
|
[
|
||||||
|
{text: '📥 Import dump', callback_data: 'import_database'},
|
||||||
|
{text: '📤 Export dump', callback_data: 'export_database'},
|
||||||
|
],
|
||||||
|
[{text: '« Back', callback_data: 'admin_menu'}]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.bot.sendMessage(chatId, 'Choose an option', {reply_markup: keyboard});
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleExportDatabase(callbackQuery) {
|
||||||
|
const chatId = callbackQuery.message.chat.id;
|
||||||
|
|
||||||
|
const tables = [
|
||||||
|
"categories",
|
||||||
|
"crypto_wallets",
|
||||||
|
"locations",
|
||||||
|
"products",
|
||||||
|
"purchases",
|
||||||
|
"transactions",
|
||||||
|
"users"
|
||||||
|
]
|
||||||
|
|
||||||
|
const dumpPath = "./dump"
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.rmdirSync(dumpPath, {recursive: true, force: true});
|
||||||
|
fs.rmSync(`${dumpPath}/dump.zip`);
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.mkdirSync(dumpPath);
|
||||||
|
|
||||||
|
for (const table of tables) {
|
||||||
|
const result = await db.allAsync(`SELECT * FROM ${table}`);
|
||||||
|
const tableData = JSON.stringify(result);
|
||||||
|
fs.writeFileSync(`${dumpPath}/${table}.json`, tableData);
|
||||||
|
}
|
||||||
|
|
||||||
|
const archive = archiver('zip', {zlib: { level: 9 } });
|
||||||
|
archive.directory(dumpPath, false);
|
||||||
|
|
||||||
|
const output = fs.createWriteStream('./dump.zip');
|
||||||
|
archive.pipe(output);
|
||||||
|
|
||||||
|
await archive.finalize();
|
||||||
|
|
||||||
|
output.on('close', () => {
|
||||||
|
this.bot.sendDocument(chatId, './dump.zip', {caption: 'Database dump'});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleImportDatabase(callbackQuery) {
|
||||||
|
const chatId = callbackQuery.message.chat.id;
|
||||||
|
|
||||||
|
this.userStates.set(chatId, { action: 'upload_database_dump' });
|
||||||
|
|
||||||
|
await this.bot.editMessageText(
|
||||||
|
'Please upload database dump',
|
||||||
|
{
|
||||||
|
chat_id: chatId,
|
||||||
|
message_id: callbackQuery.message.message_id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDumpStatistic() {
|
||||||
|
const tables = [
|
||||||
|
"categories",
|
||||||
|
"crypto_wallets",
|
||||||
|
"locations",
|
||||||
|
"products",
|
||||||
|
"purchases",
|
||||||
|
"transactions",
|
||||||
|
"users"
|
||||||
|
]
|
||||||
|
|
||||||
|
const stat = {}
|
||||||
|
|
||||||
|
for (const table of tables) {
|
||||||
|
const jsonContent = await fs.readFileSync(`./dump/${table}.json`, 'utf8');
|
||||||
|
const data = JSON.parse(jsonContent);
|
||||||
|
stat[table] = data.length
|
||||||
|
}
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleDumpImport(msg) {
|
||||||
|
const chatId = msg.chat.id;
|
||||||
|
const state = this.userStates.get(chatId);
|
||||||
|
|
||||||
|
if (!state || state.action !== 'upload_database_dump') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.document) {
|
||||||
|
if (!msg.document.file_name.endsWith('.zip')) {
|
||||||
|
await this.bot.sendMessage(chatId, 'Please upload a .zip file.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = await this.bot.getFile(msg.document.file_id);
|
||||||
|
const fileContent = await this.bot.downloadFile(file.file_id, '.');
|
||||||
|
|
||||||
|
await decompress(fileContent, './dump');
|
||||||
|
|
||||||
|
const statistics = await this.getDumpStatistic()
|
||||||
|
await this.bot.sendMessage(chatId, JSON.stringify(statistics, null, 2));
|
||||||
|
} else {
|
||||||
|
await this.bot.sendMessage(chatId, 'Please upload a valid .zip file.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async confirmImport(callbackQuery) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -398,7 +398,10 @@ export default class AdminProductHandler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
keyboard.inline_keyboard.push([
|
keyboard.inline_keyboard.push([
|
||||||
{text: `«`, callback_data: `list_products_${locationId}_${categoryId}_${subcategoryId}_${previousPage}`},
|
{
|
||||||
|
text: `«`,
|
||||||
|
callback_data: `list_products_${locationId}_${categoryId}_${subcategoryId}_${previousPage}`
|
||||||
|
},
|
||||||
{text: `»`, callback_data: `list_products_${locationId}_${categoryId}_${subcategoryId}_${nextPage}`},
|
{text: `»`, callback_data: `list_products_${locationId}_${categoryId}_${subcategoryId}_${nextPage}`},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -422,6 +425,18 @@ export default class AdminProductHandler {
|
|||||||
const messageId = callbackQuery.message.message_id;
|
const messageId = callbackQuery.message.message_id;
|
||||||
const [locationId, categoryId, subcategoryId] = callbackQuery.data.replace('prod_subcategory_', '').split('_');
|
const [locationId, categoryId, subcategoryId] = callbackQuery.data.replace('prod_subcategory_', '').split('_');
|
||||||
|
|
||||||
|
const state = this.userStates.get(chatId)
|
||||||
|
|
||||||
|
for (const msgId of state?.msgToDelete || []) {
|
||||||
|
try {
|
||||||
|
await this.bot.deleteMessage(chatId, msgId);
|
||||||
|
} catch (e) {
|
||||||
|
// ignore if can't delete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userStates.delete(chatId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {text, markup} = await this.viewProductsPage(locationId, categoryId, subcategoryId, 0);
|
const {text, markup} = await this.viewProductsPage(locationId, categoryId, subcategoryId, 0);
|
||||||
|
|
||||||
@ -603,6 +618,97 @@ export default class AdminProductHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleProductEditImport(msg) {
|
||||||
|
const chatId = msg.chat.id;
|
||||||
|
const state = this.userStates.get(chatId);
|
||||||
|
|
||||||
|
if (!state || state.action !== 'edit_product') return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let product;
|
||||||
|
let jsonContent;
|
||||||
|
|
||||||
|
// Handle file upload
|
||||||
|
if (msg.document) {
|
||||||
|
if (!msg.document.file_name.endsWith('.json')) {
|
||||||
|
await this.bot.sendMessage(chatId, 'Please upload a .json file.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = await this.bot.getFile(msg.document.file_id);
|
||||||
|
|
||||||
|
const fileContent = await this.bot.downloadFile(file.file_id, '.');
|
||||||
|
jsonContent = await fs.readFile(fileContent, 'utf8');
|
||||||
|
await fs.rm(fileContent);
|
||||||
|
|
||||||
|
} else if (msg.text) {
|
||||||
|
jsonContent = msg.text;
|
||||||
|
} else {
|
||||||
|
await this.bot.sendMessage(chatId, 'Please send either a JSON file or JSON text.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
product = JSON.parse(jsonContent);
|
||||||
|
} catch (e) {
|
||||||
|
await this.bot.sendMessage(chatId, 'Invalid JSON format. Please check the format and try again.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.runAsync('BEGIN TRANSACTION');
|
||||||
|
|
||||||
|
await db.runAsync(
|
||||||
|
`UPDATE products SET
|
||||||
|
location_id = ?,
|
||||||
|
category_id = ?,
|
||||||
|
subcategory_id = ?,
|
||||||
|
name = ?,
|
||||||
|
price = ?,
|
||||||
|
description = ?,
|
||||||
|
private_data = ?,
|
||||||
|
quantity_in_stock = ?,
|
||||||
|
photo_url = ?,
|
||||||
|
hidden_photo_url = ?,
|
||||||
|
hidden_coordinates = ?,
|
||||||
|
hidden_description = ?
|
||||||
|
WHERE
|
||||||
|
id = ?
|
||||||
|
`,
|
||||||
|
[
|
||||||
|
state.locationId, state.categoryId, state.subcategoryId,
|
||||||
|
product.name, product.price, product.description, product.private_data,
|
||||||
|
product.quantity_in_stock, product.photo_url, product.hidden_photo_url,
|
||||||
|
product.hidden_coordinates, product.hidden_description, state.productId
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
await db.runAsync('COMMIT');
|
||||||
|
|
||||||
|
await this.bot.sendMessage(
|
||||||
|
chatId,
|
||||||
|
`✅ Successfully edited!`,
|
||||||
|
{
|
||||||
|
reply_markup: {
|
||||||
|
inline_keyboard: [[
|
||||||
|
{
|
||||||
|
text: '« Back to Products',
|
||||||
|
callback_data: `prod_subcategory_${state.locationId}_${state.categoryId}_${state.subcategoryId}`
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.userStates.delete(chatId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error importing products:', error);
|
||||||
|
await this.bot.sendMessage(chatId, 'Error importing products. Please check the data and try again.');
|
||||||
|
await db.runAsync('ROLLBACK');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async handleViewProduct(callbackQuery) {
|
async handleViewProduct(callbackQuery) {
|
||||||
const chatId = callbackQuery.message.chat.id;
|
const chatId = callbackQuery.message.chat.id;
|
||||||
const messageId = callbackQuery.message.message_id;
|
const messageId = callbackQuery.message.message_id;
|
||||||
@ -654,22 +760,29 @@ Coordinates: ${product.hidden_coordinates}
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let photoMessage;
|
||||||
|
let hiddenPhotoMessage;
|
||||||
|
|
||||||
// Send product photos
|
// Send product photos
|
||||||
if (product.photo_url) {
|
if (product.photo_url) {
|
||||||
try {
|
try {
|
||||||
await this.bot.sendPhoto(chatId, product.photo_url, {caption: 'Public photo'});
|
photoMessage = await this.bot.sendPhoto(chatId, product.photo_url, {caption: 'Public photo'});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await this.bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Public photo'})
|
photoMessage = await this.bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Public photo'})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (product.hidden_photo_url) {
|
if (product.hidden_photo_url) {
|
||||||
try {
|
try {
|
||||||
await this.bot.sendPhoto(chatId, product.hidden_photo_url, {caption: 'Hidden photo'});
|
hiddenPhotoMessage = await this.bot.sendPhoto(chatId, product.hidden_photo_url, {caption: 'Hidden photo'});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await this.bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Hidden photo'})
|
hiddenPhotoMessage = await this.bot.sendPhoto(chatId, "./corrupt-photo.jpg", {caption: 'Hidden photo'})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.userStates.set(chatId, {
|
||||||
|
msgToDelete: [photoMessage.message_id, hiddenPhotoMessage.message_id]
|
||||||
|
})
|
||||||
|
|
||||||
await this.bot.deleteMessage(chatId, messageId);
|
await this.bot.deleteMessage(chatId, messageId);
|
||||||
await this.bot.sendMessage(chatId, message, {reply_markup: keyboard});
|
await this.bot.sendMessage(chatId, message, {reply_markup: keyboard});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -678,6 +791,73 @@ Coordinates: ${product.hidden_coordinates}
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleProductEdit(callbackQuery) {
|
||||||
|
const chatId = callbackQuery.message.chat.id;
|
||||||
|
const messageId = callbackQuery.message.message_id;
|
||||||
|
const productId = callbackQuery.data.replace('edit_product_', '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const product = await db.getAsync(
|
||||||
|
`SELECT p.*, c.name as category_name, s.name as subcategory_name,
|
||||||
|
l.country, l.city, l.district
|
||||||
|
FROM products p
|
||||||
|
JOIN categories c ON p.category_id = c.id
|
||||||
|
JOIN subcategories s ON p.subcategory_id = s.id
|
||||||
|
JOIN locations l ON p.location_id = l.id
|
||||||
|
WHERE p.id = ?`,
|
||||||
|
[productId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!product) {
|
||||||
|
throw new Error('Product not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const locationId = product.location_id;
|
||||||
|
const categoryId = product.category_id;
|
||||||
|
const subcategoryId = product.subcategory_id;
|
||||||
|
|
||||||
|
const sampleProduct = {
|
||||||
|
name: "Sample Product 1",
|
||||||
|
price: 100,
|
||||||
|
description: "Product description",
|
||||||
|
private_data: "Hidden details about the product",
|
||||||
|
quantity_in_stock: 10,
|
||||||
|
photo_url: "https://example.com/photo.jpg",
|
||||||
|
hidden_photo_url: "https://example.com/hidden.jpg",
|
||||||
|
hidden_coordinates: "40.7128,-74.0060",
|
||||||
|
hidden_description: "Secret location details"
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonExample = JSON.stringify(sampleProduct, null, 2);
|
||||||
|
const message = `To edit product, send a JSON file with product in the following format:\n\n<pre>${jsonExample}</pre>\n\nProduct must have all the fields shown above.\n\nYou can either:\n1. Send the JSON as text\n2. Upload a .json file`;
|
||||||
|
|
||||||
|
this.userStates.set(chatId, {
|
||||||
|
action: 'edit_product',
|
||||||
|
locationId,
|
||||||
|
categoryId,
|
||||||
|
subcategoryId,
|
||||||
|
productId
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.bot.editMessageText(message, {
|
||||||
|
chat_id: chatId,
|
||||||
|
message_id: messageId,
|
||||||
|
parse_mode: 'HTML',
|
||||||
|
reply_markup: {
|
||||||
|
inline_keyboard: [[
|
||||||
|
{
|
||||||
|
text: '❌ Cancel',
|
||||||
|
callback_data: `prod_subcategory_${locationId}_${categoryId}_${subcategoryId}`
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in handleViewProduct:', error);
|
||||||
|
await this.bot.sendMessage(chatId, 'Error loading product details. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async handleProductDelete(callbackQuery) {
|
async handleProductDelete(callbackQuery) {
|
||||||
if (!this.isAdmin(callbackQuery.from.id)) return;
|
if (!this.isAdmin(callbackQuery.from.id)) return;
|
||||||
|
|
||||||
@ -704,7 +884,10 @@ Coordinates: ${product.hidden_coordinates}
|
|||||||
inline_keyboard: [
|
inline_keyboard: [
|
||||||
[
|
[
|
||||||
{text: '✅ Confirm Delete', callback_data: `confirm_delete_product_${productId}`},
|
{text: '✅ Confirm Delete', callback_data: `confirm_delete_product_${productId}`},
|
||||||
{text: '❌ Cancel', callback_data: `prod_subcategory_${product.location_id}_${product.category_id}_${product.subcategory_id}`}
|
{
|
||||||
|
text: '❌ Cancel',
|
||||||
|
callback_data: `prod_subcategory_${product.location_id}_${product.category_id}_${product.subcategory_id}`
|
||||||
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@ -779,5 +962,4 @@ Coordinates: ${product.hidden_coordinates}
|
|||||||
await this.bot.sendMessage(chatId, 'Error deleting product. Please try again.');
|
await this.bot.sendMessage(chatId, 'Error deleting product. Please try again.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
28
src/index.js
28
src/index.js
@ -11,6 +11,7 @@ import AdminProductHandler from './handlers/adminProductHandler.js';
|
|||||||
import ErrorHandler from './utils/errorHandler.js';
|
import ErrorHandler from './utils/errorHandler.js';
|
||||||
import User from './models/User.js';
|
import User from './models/User.js';
|
||||||
import AdminUserLocationHandler from "./handlers/adminUserLocationHandler.js";
|
import AdminUserLocationHandler from "./handlers/adminUserLocationHandler.js";
|
||||||
|
import AdminDumpHandler from "./handlers/adminDumpHandler.js";
|
||||||
|
|
||||||
// Debug logging function
|
// Debug logging function
|
||||||
const logDebug = (action, functionName) => {
|
const logDebug = (action, functionName) => {
|
||||||
@ -39,6 +40,7 @@ const adminUserHandler = new AdminUserHandler(bot);
|
|||||||
const adminLocationHandler = new AdminLocationHandler(bot);
|
const adminLocationHandler = new AdminLocationHandler(bot);
|
||||||
const adminUserLocationHandler = new AdminUserLocationHandler(bot);
|
const adminUserLocationHandler = new AdminUserLocationHandler(bot);
|
||||||
const adminProductHandler = new AdminProductHandler(bot);
|
const adminProductHandler = new AdminProductHandler(bot);
|
||||||
|
const adminDumpHandler = new AdminDumpHandler(bot);
|
||||||
|
|
||||||
// Start command - Create user profile
|
// Start command - Create user profile
|
||||||
bot.onText(/\/start/, async (msg) => {
|
bot.onText(/\/start/, async (msg) => {
|
||||||
@ -100,6 +102,16 @@ bot.on('message', async (msg) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for product edition
|
||||||
|
if (await adminProductHandler.handleProductEditImport(msg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for database dump import
|
||||||
|
if (await adminDumpHandler.handleDumpImport(msg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logDebug(msg.text, 'handleMessage');
|
logDebug(msg.text, 'handleMessage');
|
||||||
|
|
||||||
switch (msg.text) {
|
switch (msg.text) {
|
||||||
@ -130,6 +142,11 @@ bot.on('message', async (msg) => {
|
|||||||
await adminLocationHandler.handleViewLocations(msg);
|
await adminLocationHandler.handleViewLocations(msg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '💾 Database Backup':
|
||||||
|
if (adminHandler.isAdmin(msg.from.id)) {
|
||||||
|
await adminDumpHandler.handleDump(msg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await ErrorHandler.handleError(bot, msg.chat.id, error, 'message handler');
|
await ErrorHandler.handleError(bot, msg.chat.id, error, 'message handler');
|
||||||
@ -278,6 +295,9 @@ bot.on('callback_query', async (callbackQuery) => {
|
|||||||
} else if (action.startsWith('view_product_')) {
|
} else if (action.startsWith('view_product_')) {
|
||||||
logDebug(action, 'handleViewProduct');
|
logDebug(action, 'handleViewProduct');
|
||||||
await adminProductHandler.handleViewProduct(callbackQuery);
|
await adminProductHandler.handleViewProduct(callbackQuery);
|
||||||
|
} else if (action.startsWith('edit_product_')) {
|
||||||
|
logDebug(action, 'handleProductEdit');
|
||||||
|
await adminProductHandler.handleProductEdit(callbackQuery)
|
||||||
} else if (action.startsWith('delete_product_')) {
|
} else if (action.startsWith('delete_product_')) {
|
||||||
logDebug(action, 'handleViewProduct');
|
logDebug(action, 'handleViewProduct');
|
||||||
await adminProductHandler.handleProductDelete(callbackQuery);
|
await adminProductHandler.handleProductDelete(callbackQuery);
|
||||||
@ -322,6 +342,14 @@ bot.on('callback_query', async (callbackQuery) => {
|
|||||||
logDebug(action, 'handleEditUserDistrict');
|
logDebug(action, 'handleEditUserDistrict');
|
||||||
await adminUserLocationHandler.handleEditUserDistrict(callbackQuery)
|
await adminUserLocationHandler.handleEditUserDistrict(callbackQuery)
|
||||||
}
|
}
|
||||||
|
// Dump manage
|
||||||
|
else if (action === "export_database") {
|
||||||
|
await adminDumpHandler.handleExportDatabase(callbackQuery);
|
||||||
|
return;
|
||||||
|
} else if (action === "import_database") {
|
||||||
|
await adminDumpHandler.handleImportDatabase(callbackQuery);
|
||||||
|
}
|
||||||
|
|
||||||
await bot.answerCallbackQuery(callbackQuery.id);
|
await bot.answerCallbackQuery(callbackQuery.id);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await ErrorHandler.handleError(bot, msg.chat.id, error, 'callback query');
|
await ErrorHandler.handleError(bot, msg.chat.id, error, 'callback query');
|
||||||
|
Loading…
Reference in New Issue
Block a user