Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -11,13 +11,13 @@ import threading
|
|
| 11 |
|
| 12 |
# Настройка логирования
|
| 13 |
logging.basicConfig(level=logging.INFO)
|
| 14 |
-
logger = logging.getLogger(__name__) #
|
| 15 |
|
| 16 |
# Инициализация бота и Flask
|
| 17 |
BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA'
|
| 18 |
bot = Bot(token=BOT_TOKEN)
|
| 19 |
dp = Dispatcher()
|
| 20 |
-
app = Flask(__name__)
|
| 21 |
|
| 22 |
# Путь для хранения данных (товары и заказы)
|
| 23 |
DATA_FILE = 'data.json'
|
|
@@ -67,8 +67,10 @@ async def show_products(message: types.Message):
|
|
| 67 |
await message.answer("Нет доступных товаров.")
|
| 68 |
return
|
| 69 |
for product in data['products']:
|
| 70 |
-
await message.answer(
|
| 71 |
-
|
|
|
|
|
|
|
| 72 |
|
| 73 |
@dp.message(F.text == "🛒 Корзина")
|
| 74 |
async def show_cart(message: types.Message):
|
|
@@ -98,7 +100,11 @@ async def add_to_cart(callback_query: types.CallbackQuery):
|
|
| 98 |
if not cart:
|
| 99 |
cart = {'user_id': user_id, 'items': [], 'completed': False, 'date': datetime.now().isoformat()}
|
| 100 |
data['orders'].append(cart)
|
| 101 |
-
cart['items']
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
save_data(data)
|
| 103 |
await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
|
| 104 |
else:
|
|
@@ -133,85 +139,59 @@ async def show_orders(message: types.Message):
|
|
| 133 |
response += f"\nИтого: {total} руб.\nДата: {order['date']}"
|
| 134 |
await message.answer(response)
|
| 135 |
|
| 136 |
-
# Админ-панель (Flask) с HTML
|
| 137 |
admin_html = """
|
| 138 |
<!DOCTYPE html>
|
| 139 |
<html>
|
| 140 |
<head>
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
input, textarea { width: 100%; margin: 5px 0; padding: 8px; }
|
| 148 |
-
button { background-color: #4CAF50; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; }
|
| 149 |
-
button:hover { background-color: #45a049; }
|
| 150 |
-
</style>
|
| 151 |
</head>
|
| 152 |
<body>
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
</div>
|
| 188 |
-
{% endfor %}
|
| 189 |
-
{% else %}
|
| 190 |
-
<p>Нет заказов.</p>
|
| 191 |
-
{% endif %}
|
| 192 |
-
</div>
|
| 193 |
-
<script>
|
| 194 |
-
document.getElementById('addProductForm').onsubmit = async (e) => {
|
| 195 |
-
e.preventDefault();
|
| 196 |
-
const formData = new FormData(e.target);
|
| 197 |
-
const response = await fetch('/add_product', { method: 'POST', body: formData });
|
| 198 |
-
if (response.ok) window.location.reload();
|
| 199 |
-
};
|
| 200 |
-
async function deleteProduct(productId) {
|
| 201 |
-
const response = await fetch(`/delete_product/${productId}`, { method: 'POST' });
|
| 202 |
-
if (response.ok) window.location.reload();
|
| 203 |
-
}
|
| 204 |
-
</script>
|
| 205 |
-
</body>
|
| 206 |
-
</html>
|
| 207 |
-
"""
|
| 208 |
|
| 209 |
@app.route('/')
|
| 210 |
def admin_panel():
|
| 211 |
try:
|
| 212 |
-
logger.info("
|
| 213 |
-
|
| 214 |
-
return render_template_string(admin_html, products=data['products'], orders=data['orders'])
|
| 215 |
except Exception as e:
|
| 216 |
logger.error(f"Ошибка в шаблоне: {e}")
|
| 217 |
return "Ошибка сервера. Проверьте логи.", 500
|
|
@@ -219,15 +199,21 @@ def admin_panel():
|
|
| 219 |
@app.route('/add_product', methods=['POST'])
|
| 220 |
def add_product():
|
| 221 |
try:
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
except Exception as e:
|
| 232 |
logger.error(f"Ошибка при добавлении товара: {e}")
|
| 233 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
@@ -236,9 +222,14 @@ def add_product():
|
|
| 236 |
def delete_product(product_id):
|
| 237 |
try:
|
| 238 |
logger.info(f"Deleting product with id={product_id}")
|
| 239 |
-
|
|
|
|
|
|
|
|
|
|
| 240 |
save_data(data)
|
|
|
|
| 241 |
return jsonify({'status': 'success'})
|
|
|
|
| 242 |
except Exception as e:
|
| 243 |
logger.error(f"Ошибка при удалении товара: {e}")
|
| 244 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
@@ -250,20 +241,23 @@ async def on_startup(_):
|
|
| 250 |
def run_flask():
|
| 251 |
try:
|
| 252 |
logger.info("Starting Flask server on port 7860")
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
|
|
|
|
|
|
|
|
|
| 256 |
|
| 257 |
if __name__ == '__main__':
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
|
|
|
| 11 |
|
| 12 |
# Настройка логирования
|
| 13 |
logging.basicConfig(level=logging.INFO)
|
| 14 |
+
logger = logging.getLogger(__name__) # Используем __name__ для логгера
|
| 15 |
|
| 16 |
# Инициализация бота и Flask
|
| 17 |
BOT_TOKEN = '7734802681:AAGKHGG8O9uNk64JWTHH5yqXzvSxCcoLUdA'
|
| 18 |
bot = Bot(token=BOT_TOKEN)
|
| 19 |
dp = Dispatcher()
|
| 20 |
+
app = Flask(__name__)
|
| 21 |
|
| 22 |
# Путь для хранения данных (товары и заказы)
|
| 23 |
DATA_FILE = 'data.json'
|
|
|
|
| 67 |
await message.answer("Нет доступных товаров.")
|
| 68 |
return
|
| 69 |
for product in data['products']:
|
| 70 |
+
await message.answer(
|
| 71 |
+
f"🏷 {product['name']} - {product['price']} руб.\nОписание: {product['description']}\n/id: {product['id']}",
|
| 72 |
+
reply_markup=get_product_keyboard(product['id'])
|
| 73 |
+
)
|
| 74 |
|
| 75 |
@dp.message(F.text == "🛒 Корзина")
|
| 76 |
async def show_cart(message: types.Message):
|
|
|
|
| 100 |
if not cart:
|
| 101 |
cart = {'user_id': user_id, 'items': [], 'completed': False, 'date': datetime.now().isoformat()}
|
| 102 |
data['orders'].append(cart)
|
| 103 |
+
cart_item = next((item for item in cart['items'] if item['product_id'] == product_id), None)
|
| 104 |
+
if cart_item:
|
| 105 |
+
cart_item['quantity'] += 1
|
| 106 |
+
else:
|
| 107 |
+
cart['items'].append({'product_id': product_id, 'quantity': 1})
|
| 108 |
save_data(data)
|
| 109 |
await bot.answer_callback_query(callback_query.id, "Товар добавлен в корзину!")
|
| 110 |
else:
|
|
|
|
| 139 |
response += f"\nИтого: {total} руб.\nДата: {order['date']}"
|
| 140 |
await message.answer(response)
|
| 141 |
|
| 142 |
+
# Админ-панель (Flask) с HTML-шаблоном
|
| 143 |
admin_html = """
|
| 144 |
<!DOCTYPE html>
|
| 145 |
<html>
|
| 146 |
<head>
|
| 147 |
+
<title>Админ-панель</title>
|
| 148 |
+
<style>
|
| 149 |
+
body { font-family: Arial; background-color: #f0f0f0; margin: 20px; }
|
| 150 |
+
.container { max-width: 800px; margin: auto; }
|
| 151 |
+
.product { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; background-color: #fff; }
|
| 152 |
+
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
</head>
|
| 154 |
<body>
|
| 155 |
+
<div class="container">
|
| 156 |
+
<h1>Управление товарами</h1>
|
| 157 |
+
<form id="addProductForm">
|
| 158 |
+
<input type="text" name="name" placeholder="Название" required><br>
|
| 159 |
+
<input type="number" name="price" placeholder="Цена" required><br>
|
| 160 |
+
<textarea name="description" placeholder="Описание"></textarea><br>
|
| 161 |
+
<button type="submit">Добавить товар</button>
|
| 162 |
+
</form>
|
| 163 |
+
<h2>Существующие товары</h2>
|
| 164 |
+
{% for product in products %}
|
| 165 |
+
<div class="product">
|
| 166 |
+
<b>{{ product.name }}</b> - {{ product.price }}<br>{{ product.description }}
|
| 167 |
+
<button onclick="deleteProduct({{ product.id }})">Удалить</button>
|
| 168 |
+
</div>
|
| 169 |
+
{% endfor %}
|
| 170 |
+
<h2>Заказы</h2>
|
| 171 |
+
{% for order in orders %}
|
| 172 |
+
<div class="product">
|
| 173 |
+
<b>Пользователь:</b> {{ order.user_id }}<br><b>Дата:</b> {{ order.date }}
|
| 174 |
+
<ul>{% for item in order.items %} <li>{{ item.quantity }}</li>{% endfor %}</ul></div>{% endfor %}
|
| 175 |
+
<script>
|
| 176 |
+
// JS для добавления/удаления товаров.
|
| 177 |
+
async function deleteProduct(productId) {
|
| 178 |
+
const response = await fetch(`/delete_product/${productId}`, { method: 'POST' });
|
| 179 |
+
if (response.ok) window.location.reload();
|
| 180 |
+
}
|
| 181 |
+
document.getElementById('addProductForm').onsubmit = async (e) => {
|
| 182 |
+
e.preventDefault();
|
| 183 |
+
const formData = new FormData(e.target);
|
| 184 |
+
const response = await fetch('/add_product', { method: 'POST', body: formData });
|
| 185 |
+
if (response.ok) window.location.reload();
|
| 186 |
+
};
|
| 187 |
+
</script>
|
| 188 |
+
</div></body></html>"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
@app.route('/')
|
| 191 |
def admin_panel():
|
| 192 |
try:
|
| 193 |
+
logger.info(f"Products: {data.get('products')}, Orders: {data.get('orders')}")
|
| 194 |
+
return render_template_string(admin_html, products=data.get('products', []), orders=data.get('orders', []))
|
|
|
|
| 195 |
except Exception as e:
|
| 196 |
logger.error(f"Ошибка в шаблоне: {e}")
|
| 197 |
return "Ошибка сервера. Проверьте логи.", 500
|
|
|
|
| 199 |
@app.route('/add_product', methods=['POST'])
|
| 200 |
def add_product():
|
| 201 |
try:
|
| 202 |
+
logger.info("Adding new product")
|
| 203 |
+
name = request.form.get('name')
|
| 204 |
+
price = float(request.form.get('price'))
|
| 205 |
+
description = request.form.get('description')
|
| 206 |
+
|
| 207 |
+
# Генерация нового ID для продукта
|
| 208 |
+
product_id = max((p['id'] for p in data.get('products', [])), default=0) + 1
|
| 209 |
+
|
| 210 |
+
# Добавление продукта в данные и сохранение
|
| 211 |
+
data.setdefault('products', []).append({'id': product_id, 'name': name, 'price': price, 'description': description})
|
| 212 |
+
|
| 213 |
+
save_data(data)
|
| 214 |
+
|
| 215 |
+
return jsonify({'status': 'success'})
|
| 216 |
+
|
| 217 |
except Exception as e:
|
| 218 |
logger.error(f"Ошибка при добавлении товара: {e}")
|
| 219 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
| 222 |
def delete_product(product_id):
|
| 223 |
try:
|
| 224 |
logger.info(f"Deleting product with id={product_id}")
|
| 225 |
+
|
| 226 |
+
# Удаление продукта из данных и сохранение
|
| 227 |
+
data['products'] = [p for p in data.get('products', []) if p['id'] != product_id]
|
| 228 |
+
|
| 229 |
save_data(data)
|
| 230 |
+
|
| 231 |
return jsonify({'status': 'success'})
|
| 232 |
+
|
| 233 |
except Exception as e:
|
| 234 |
logger.error(f"Ошибка при удалении товара: {e}")
|
| 235 |
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
| 241 |
def run_flask():
|
| 242 |
try:
|
| 243 |
logger.info("Starting Flask server on port 7860")
|
| 244 |
+
|
| 245 |
+
# Запуск Flask приложения
|
| 246 |
+
app.run(host='0.0.0.0', port=7860)
|
| 247 |
+
|
| 248 |
+
except Exception as e:
|
| 249 |
+
logger.error(f"Ошибка в Flask: {e}")
|
| 250 |
|
| 251 |
if __name__ == '__main__':
|
| 252 |
+
# Создаем и запускаем поток для Flask
|
| 253 |
+
flask_thread = threading.Thread(target=run_flask, daemon=True)
|
| 254 |
+
flask_thread.start()
|
| 255 |
+
logger.info("Flask thread started")
|
| 256 |
|
| 257 |
+
# Запускаем бота в главном потоке
|
| 258 |
+
try:
|
| 259 |
+
asyncio.run(dp.start_polling(bot, on_startup=on_startup))
|
| 260 |
+
except KeyboardInterrupt:
|
| 261 |
+
logger.info("Stopping bot and Flask")
|
| 262 |
+
finally:
|
| 263 |
+
flask_thread.join() # Ждем завершения потока Flask при завершении программы
|