diff --git "a/Optomshoptxt.txt" "b/Optomshoptxt.txt"
new file mode 100644--- /dev/null
+++ "b/Optomshoptxt.txt"
@@ -0,0 +1,3681 @@
+
+
+from flask import Flask, render_template_string, request, redirect, url_for
+import json
+import os
+import logging
+import threading
+import time
+from datetime import datetime
+from huggingface_hub import HfApi, hf_hub_download
+from huggingface_hub.utils import RepositoryNotFoundError
+from werkzeug.utils import secure_filename
+
+app = Flask(__name__)
+DATA_FILE = 'data_firecollection.json'
+
+# Настройки Hugging Face
+REPO_ID = "Kgshop/Clients2" # Замените, если нужно
+HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
+HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
+
+# Настройка логирования
+logging.basicConfig(level=logging.DEBUG)
+
+def load_data():
+ try:
+ download_db_from_hf()
+ with open(DATA_FILE, 'r', encoding='utf-8') as file:
+ data = json.load(file)
+ logging.info("Данные успешно загружены из JSON")
+ if not isinstance(data, dict) or 'products' not in data or 'categories' not in data:
+ return {'products': [], 'categories': []} # Corrected: return empty dict with lists
+ return data
+ except FileNotFoundError:
+ logging.warning("Локальный файл базы данных не найден после скачивания.")
+ return {'products': [], 'categories': []}
+ except json.JSONDecodeError:
+ logging.error("Ошибка: Невозможно декодировать JSON файл.")
+ return {'products': [], 'categories': []}
+ except RepositoryNotFoundError:
+ logging.error("Репозиторий не найден. Создание локальной базы данных.")
+ return {'products': [], 'categories': []}
+ except Exception as e:
+ logging.error(f"Произошла ошибка при загрузке данных: {e}")
+ return {'products': [], 'categories': []}
+
+def save_data(data):
+ try:
+ with open(DATA_FILE, 'w', encoding='utf-8') as file:
+ json.dump(data, file, ensure_ascii=False, indent=4)
+ logging.info("Данные успешно сохранены в JSON")
+ upload_db_to_hf()
+ except Exception as e:
+ logging.error(f"Ошибка при сохранении данных: {e}")
+ raise
+
+def upload_db_to_hf():
+ try:
+ api = HfApi()
+ api.upload_file(
+ path_or_fileobj=DATA_FILE,
+ path_in_repo=DATA_FILE,
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE,
+ commit_message=f"Автоматическое резервное копирование базы данных {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
+ )
+ logging.info("Резервная копия JSON базы успешно загружена на Hugging Face.")
+ except Exception as e:
+ logging.error(f"Ошибка при загрузке резервной копии: {e}")
+
+def download_db_from_hf():
+ try:
+ hf_hub_download(
+ repo_id=REPO_ID,
+ filename=DATA_FILE,
+ repo_type="dataset",
+ token=HF_TOKEN_READ,
+ local_dir=".",
+ local_dir_use_symlinks=False
+ )
+ logging.info("JSON база успешно скачана из Hugging Face.")
+ except RepositoryNotFoundError as e:
+ logging.error(f"Репозиторий не найден: {e}")
+ raise
+ except Exception as e:
+ logging.error(f"Ошибка при скачивании JSON базы: {e}")
+ raise
+
+def periodic_backup():
+ while True:
+ upload_db_to_hf()
+ time.sleep(800)
+
+@app.route('/')
+def catalog():
+ data = load_data()
+ products = data['products']
+ # categories = data['categories'] Removed categories from main page
+
+ catalog_html = '''
+
+
+
+
+
+ Fire collection
+
+
+
+
+
+
+
+
+
+
+
+
Наш адрес
+
Рынок Дордой, 0 проход , 2034 контейнер
+
График работы
+
По адресу: без выходных с 8:00 до 16:00, онлайн: круглосуточно
+
+
+
+
+
+
+ {% for product in products %}
+
+
+
+
+ {% if product.get('photos') and product['photos']|length > 0 %}
+
+
+
+ {% endif %}
+ {% if product.get('wholesale_price') and product.get('min_wholesale') %}
+
Опт от {{ product['min_wholesale'] }}
+ {% endif %}
+ {% if product.get('discount') %}
+
Скидка {{ product['discount'] }}%
+ {% endif %}
+
{{ product['name'] }}
+
+ {% if product.get('discount') %}
+ {{ product['price'] }} с
+ {{ (product['price'] * (1 - product['discount'] / 100))|round(2) }} с
+ Скидка: {{ product['discount'] }}%
+ {% else %}
+ {{ product['price'] }} с
+ {% endif %}
+
+
{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}
+
В корзину
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+ ×
+
Укажите количество и цвет
+
+
+ Добавить
+
+
+
+
+
+
+
×
+
Корзина
+
+
+ Итого: 0 с
+ Очистить
+ Заказать
+
+
+
+
+ 🛒
+
+
+
+
+
+
+
+
+
+
+ '''
+ return render_template_string(catalog_html, products=products, repo_id=REPO_ID)
+
+@app.route('/categories')
+def categories_page():
+ data = load_data()
+ categories = data['categories']
+
+ categories_html = '''
+
+
+
+
+
+ Fire collection
+
+
+
+
+
+
+
+
+
+
+
+
+ '''
+ return render_template_string(categories_html, categories=categories)
+
+@app.route('/category/')
+def category_products(category):
+ data = load_data()
+ products = [p for p in data['products'] if p.get('category') == category]
+ # categories = data['categories'] # No longer needed here
+
+ category_html = '''
+
+
+
+
+
+ Fire collection
+
+
+
+
+
+
+
+
+
+ {% for product in products %}
+
+
+
+
+ {% if product.get('photos') and product['photos']|length > 0 %}
+
+
+
+ {% endif %}
+ {% if product.get('wholesale_price') and product.get('min_wholesale') %}
+
Опт от {{ product['min_wholesale'] }}
+ {% endif %}
+ {% if product.get('discount') %}
+
Скидка {{ product['discount'] }}%
+ {% endif %}
+
{{ product['name'] }}
+
+ {% if product.get('discount') %}
+ {{ product['price'] }} с
+ {{ (product['price'] * (1 - product['discount'] / 100))|round(2) }} с
+ Скидка: {{ product['discount'] }}%
+ {% else %}
+ {{ product['price'] }} с
+ {% endif %}
+
+
{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}
+
В корзину
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+ ×
+
Укажите количество и цвет
+
+
+ Добавить
+
+
+
+
+
+
+
×
+
Корзина
+
+
+ Итого: 0 с
+ Очистить
+ Заказать
+
+
+
+
+ 🛒
+
+
+
+
+
+
+
+
+
+ '''
+ return render_template_string(category_html, products=products, category=category, repo_id=REPO_ID)
+
+
+@app.route('/favorites')
+def favorites_page():
+ data = load_data()
+ products = data['products']
+ favorites = request.args.get('favorites', '[]') # Not really used directly, but kept for consistency
+
+ favorites_html = '''
+
+
+
+
+
+ Fire collection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
Укажите количество и цвет
+
+
+ Добавить
+
+
+
+
+
+
+
×
+
Корзина
+
+
+ Итого: 0 с
+ Очистить
+ Заказать
+
+
+
+
+
+ 🛒
+
+
+
+
+
+
+
+
+
+ '''
+ return render_template_string(favorites_html, products=products, repo_id=REPO_ID)
+
+
+
+@app.route('/discounts')
+def discounts_page():
+ data = load_data()
+ products = [p for p in data['products'] if p.get('discount')]
+ # categories = data['categories'] # No longer used in this view
+
+ discounts_html = '''
+
+
+
+
+
+ Fire collection
+
+
+
+
+
+
+
+
+
+ {% for product in products %}
+
+
+
+
+ {% if product.get('photos') and product['photos']|length > 0 %}
+
+
+
+ {% endif %}
+ {% if product.get('wholesale_price') and product.get('min_wholesale') %}
+
Опт от {{ product['min_wholesale'] }}
+ {% endif %}
+ {% if product.get('discount') %}
+
Скидка {{ product['discount'] }}%
+ {% endif %}
+
{{ product['name'] }}
+
+ {% if product.get('discount') %}
+ {{ product['price'] }} с
+ {{ (product['price'] * (1 - product['discount'] / 100))|round(2) }} с
+ Скидка: {{ product['discount'] }}%
+ {% else %}
+ {{ product['price'] }} с
+ {% endif %}
+
+
{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}
+
В корзину
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+ ×
+
Укажите количество и цвет
+
+
+ Добавить
+
+
+
+
+
+
+
×
+
Корзина
+
+
+ Итого: 0 с
+ Очистить
+ Заказать
+
+
+
+
+ 🛒
+
+
+
+
+
+
+
+
+
+ '''
+ return render_template_string(discounts_html, products=products, repo_id=REPO_ID)
+
+
+@app.route('/product/')
+def product_details(index):
+ data = load_data()
+ if index < 0 or index >= len(data['products']):
+ return "Product not found", 404 # Return a 404 error if index is out of bounds
+ product = data['products'][index]
+
+ product_html = '''
+
+
+
{{ product['name'] }}
+
+
+ {% for photo in product.get('photos', []) %}
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+ {% if product.get('discount') %}
+ {{ product['price'] }} с
+ {{ (product['price'] * (1 - product['discount'] / 100))|round(2) }} с
+ Скидка: {{ product['discount'] }}%
+ {% else %}
+ {{ product['price'] }} с
+ {% endif %}
+
+
Описание: {{ product['description'] }}
+
Категория: {{ product.get('category', 'Без категории') }}
+ {% if product.get('colors') %}
+
+ Цвета:
+ {% for color in product['colors'] %}
+ {{ color }}
+ {% endfor %}
+
+ {% endif %}
+
+ '''
+ return render_template_string(product_html, product=product, repo_id=REPO_ID)
+
+@app.route('/admin', methods=['GET', 'POST'])
+def admin():
+ data = load_data()
+ products = data['products']
+ categories = data['categories']
+
+ if request.method == 'POST':
+ action = request.form.get('action')
+
+ if action == 'add':
+ photos = request.files.getlist('photos')
+ photo_filenames = []
+ for photo in photos:
+ if photo and photo.filename:
+ filename = secure_filename(photo.filename)
+ api = HfApi()
+ api.upload_file(
+ path_or_fileobj=photo,
+ path_in_repo=f"photos/{filename}",
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE
+ )
+ photo_filenames.append(filename)
+
+ colors = request.form.getlist('colors')
+ colors = [color.strip() for color in colors if color.strip()]
+
+ new_product = {
+ 'name': request.form['name'],
+ 'price': float(request.form['price']),
+ 'description': request.form['description'],
+ 'category': request.form['category'],
+ 'colors': colors,
+ 'photos': photo_filenames,
+ 'discount': float(request.form['discount']) if request.form['discount'] else None
+ }
+ products.append(new_product)
+
+ elif action == 'edit':
+ index = int(request.form['index'])
+ photos = request.files.getlist('photos')
+ photo_filenames = products[index].get('photos', []) # Keep existing photos
+ for photo in photos:
+ if photo and photo.filename:
+ filename = secure_filename(photo.filename)
+ api = HfApi()
+ api.upload_file(
+ path_or_fileobj=photo,
+ path_in_repo=f"photos/{filename}",
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE
+ )
+ photo_filenames.append(filename) # Add new photos
+
+ colors = request.form.getlist('colors')
+ colors = [color.strip() for color in colors if color.strip()]
+
+ products[index] = {
+ 'name': request.form['name'],
+ 'price': float(request.form['price']),
+ 'description': request.form['description'],
+ 'category': request.form['category'],
+ 'colors': colors,
+ 'photos': photo_filenames, # Updated photo list
+ 'discount': float(request.form['discount']) if request.form['discount'] else None
+ }
+
+ elif action == 'delete':
+ index = int(request.form['index'])
+ # Delete photos from Hugging Face Hub before deleting the product
+ product_to_delete = products[index]
+ if 'photos' in product_to_delete:
+ api = HfApi()
+ for photo in product_to_delete['photos']:
+ try:
+ api.delete_file(
+ path_in_repo=f"photos/{photo}",
+ repo_id=REPO_ID,
+ repo_type="dataset",
+ token=HF_TOKEN_WRITE
+ )
+ except Exception as e:
+ logging.error(f"Error deleting photo {photo}: {e}")
+ products.pop(index)
+
+
+ elif action == 'add_category':
+ category = request.form['category_name'].strip()
+ if category and category not in categories:
+ categories.append(category)
+
+ elif action == 'delete_category':
+ index = int(request.form['category_index'])
+ category_to_delete = categories[index]
+ categories.pop(index)
+ #Set category to "Без категории" for products in the deleted category
+ for product in products:
+ if product.get('category') == category_to_delete:
+ product['category'] = 'Без категории'
+
+ save_data({'products': products, 'categories': categories})
+ return redirect(url_for('admin'))
+
+ admin_html = '''
+
+
+
+
+
+ Fire collection - Админ-панель
+
+
+
+
+
+
Fire collection - Админ-панель
+
+
+
+
+
Добавить категорию
+
+
+ Название категории:
+
+ Добавить категорию
+
+
+
+
+ {% for category in categories %}
+
+
{{ category }}
+
+
+
+ Удалить категорию
+
+
+ {% endfor %}
+
+
+
Список товаров
+
+
+
+
+ {% for product in products %}
+
+
{{ product['name'] }}
+
Цена: {{ product['price'] }} с
+ {% if product.get('discount') %}
+
Скидка: {{ product['discount'] }}%
+ {% endif %}
+
Описание: {{ product['description'] }}
+
Категория: {{ product.get('category', 'Без категории') }}
+
Цвета: {{ product.get('colors', ['Нет цветов'])|join(', ') }}
+ {% if product.get('photos') %}
+
Фотографии:
+ {% for photo in product['photos'] %}
+
+ {% endfor %}
+ {% endif %}
+
+ Редактировать
+
+
+
+ Название:
+
+ Цена:
+
+ Скидка (%):
+
+ Описание:
+ {{ product['description'] }}
+ Категория:
+
+ Без категории
+ {% for category in categories %}
+ {{ category }}
+ {% endfor %}
+
+ Фотографии (до 10):
+
+ Цвета:
+
+ Добавить цвет
+ Сохранить
+
+
+
+
+
+ Удалить
+
+
+ {% endfor %}
+
+
+
+
+
+ '''
+ return render_template_string(admin_html, products=products, categories=categories, repo_id=REPO_ID)
+
+@app.route('/backup', methods=['POST'])
+def backup():
+ upload_db_to_hf()
+ return "Резервная копия создана.", 200
+
+@app.route('/download', methods=['GET'])
+def download():
+ download_db_from_hf()
+ return "База данных скачана.", 200
+
+if __name__ == '__main__':
+ backup_thread = threading.Thread(target=periodic_backup, daemon=True)
+ backup_thread.start()
+ try:
+ load_data()
+ except Exception as e:
+ logging.error(f"Не удалось загрузить базу данных: {e}")
+ app.run(debug=True, host='0.0.0.0', port=7860)