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);