From ec96f67dfe75a558c5329cc1c4dae9728e73626e Mon Sep 17 00:00:00 2001 From: Artyom Ashirov <1323ED5@gmail.com> Date: Sat, 16 Nov 2024 17:53:43 +0300 Subject: [PATCH] Product edition --- src/handlers/adminProductHandler.js | 171 +++++++++++++++++++++++++++- src/index.js | 8 ++ 2 files changed, 176 insertions(+), 3 deletions(-) diff --git a/src/handlers/adminProductHandler.js b/src/handlers/adminProductHandler.js index 65587f1..1ee1574 100644 --- a/src/handlers/adminProductHandler.js +++ b/src/handlers/adminProductHandler.js @@ -398,7 +398,10 @@ export default class AdminProductHandler { }; 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}`}, ]); @@ -422,6 +425,8 @@ export default class AdminProductHandler { const messageId = callbackQuery.message.message_id; const [locationId, categoryId, subcategoryId] = callbackQuery.data.replace('prod_subcategory_', '').split('_'); + this.userStates.delete(chatId); + try { const {text, markup} = await this.viewProductsPage(locationId, categoryId, subcategoryId, 0); @@ -603,6 +608,97 @@ export default class AdminProductHandler { 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) { const chatId = callbackQuery.message.chat.id; const messageId = callbackQuery.message.message_id; @@ -678,6 +774,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
${jsonExample}\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) {
if (!this.isAdmin(callbackQuery.from.id)) return;
@@ -704,7 +867,10 @@ Coordinates: ${product.hidden_coordinates}
inline_keyboard: [
[
{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 +945,4 @@ Coordinates: ${product.hidden_coordinates}
await this.bot.sendMessage(chatId, 'Error deleting product. Please try again.');
}
}
-
}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 72c16ef..e58016c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -100,6 +100,11 @@ bot.on('message', async (msg) => {
return;
}
+ // Check for product edition
+ if (await adminProductHandler.handleProductEditImport(msg)) {
+ return;
+ }
+
logDebug(msg.text, 'handleMessage');
switch (msg.text) {
@@ -278,6 +283,9 @@ bot.on('callback_query', async (callbackQuery) => {
} else if (action.startsWith('view_product_')) {
logDebug(action, 'handleViewProduct');
await adminProductHandler.handleViewProduct(callbackQuery);
+ } else if (action.startsWith('edit_product_')) {
+ logDebug(action, 'handleProductEdit');
+ await adminProductHandler.handleProductEdit(callbackQuery)
} else if (action.startsWith('delete_product_')) {
logDebug(action, 'handleViewProduct');
await adminProductHandler.handleProductDelete(callbackQuery);