diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,4 +1,5 @@ + from flask import Flask, render_template_string, request, redirect, url_for, session, send_file, flash import json import os @@ -39,13 +40,14 @@ def load_data(): logging.info(f"Данные успешно загружены из {DATA_FILE}") if not isinstance(data, dict): logging.warning(f"{DATA_FILE} не является словарем. Инициализация пустой структурой.") - return {'products': [], 'categories': []} + data = {'products': [], 'categories': []} + if 'products' not in data: data['products'] = [] if 'categories' not in data: data['categories'] = [] - # Ensure default values for new fields + # Ensure new fields exist with defaults for product in data['products']: product.setdefault('is_top', False) product.setdefault('in_stock', True) @@ -54,30 +56,22 @@ def load_data(): except FileNotFoundError: logging.warning(f"Локальный файл {DATA_FILE} не найден. Попытка скачать с HF.") try: - # Create empty file before downloading if it doesn't exist at all if not os.path.exists(DATA_FILE): with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump({'products': [], 'categories': []}, f) logging.info(f"Создан пустой файл {DATA_FILE}") - - download_db_from_hf(specific_file=DATA_FILE) # Try downloading again - - # Check if download created the file or if it existed - if os.path.exists(DATA_FILE): + return {'products': [], 'categories': []} + else: with open(DATA_FILE, 'r', encoding='utf-8') as file: data = json.load(file) logging.info(f"Данные успешно загружены из {DATA_FILE} после попытки скачивания.") if not isinstance(data, dict): return {'products': [], 'categories': []} if 'products' not in data: data['products'] = [] if 'categories' not in data: data['categories'] = [] - # Ensure default values for new fields after download + # Ensure new fields exist with defaults after download for product in data['products']: product.setdefault('is_top', False) product.setdefault('in_stock', True) return data - else: - logging.warning(f"Файл {DATA_FILE} не найден и не скачан. Создание пустой структуры.") - return {'products': [], 'categories': []} # Return empty if download failed and file still missing - except (FileNotFoundError, RepositoryNotFoundError) as e: logging.warning(f"Файл {DATA_FILE} не найден локально и ошибка при доступе к репозиторию HF ({e}). Создание пустой структуры.") if not os.path.exists(DATA_FILE): @@ -87,7 +81,7 @@ def load_data(): logging.error(f"Ошибка декодирования JSON в {DATA_FILE} после попытки скачивания.") return {'products': [], 'categories': []} except Exception as e: - logging.error(f"Неизвестная ошибка при загрузке данных после попытки скачивания: {e}", exc_info=True) + logging.error(f"Неизвестная ошибка при загрузке данных после попытки скачивания: {e}") return {'products': [], 'categories': []} except json.JSONDecodeError: logging.error(f"Ошибка декодирования JSON в локальном {DATA_FILE}. Файл может быть поврежден. Возврат пустой структуры.") @@ -96,11 +90,12 @@ def load_data(): logging.error(f"Неизвестная ошибка при загрузке данных ({DATA_FILE}): {e}", exc_info=True) return {'products': [], 'categories': []} + def save_data(data): try: - # Ensure defaults before saving + # Ensure new fields exist before saving if 'products' in data: - for product in data['products']: + for product in data['products']: product.setdefault('is_top', False) product.setdefault('in_stock', True) @@ -113,7 +108,6 @@ def save_data(data): def load_users(): try: - download_db_from_hf(specific_file=USERS_FILE) with open(USERS_FILE, 'r', encoding='utf-8') as file: users = json.load(file) logging.info(f"Данные пользователей успешно загружены из {USERS_FILE}") @@ -121,22 +115,14 @@ def load_users(): except FileNotFoundError: logging.warning(f"Локальный файл {USERS_FILE} не найден. Попытка скачать с HF.") try: - if not os.path.exists(USERS_FILE): - with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump({}, f) - logging.info(f"Создан пустой файл {USERS_FILE}") - download_db_from_hf(specific_file=USERS_FILE) # Attempt download again - if os.path.exists(USERS_FILE): - with open(USERS_FILE, 'r', encoding='utf-8') as file: - users = json.load(file) - logging.info(f"Данные пользователей загружены из {USERS_FILE} после скачивания.") - return users if isinstance(users, dict) else {} - else: - logging.warning(f"Файл {USERS_FILE} не найден и не скачан. Возврат пустого словаря.") - return {} + download_db_from_hf(specific_file=USERS_FILE) + with open(USERS_FILE, 'r', encoding='utf-8') as file: + users = json.load(file) + logging.info(f"Данные пользователей загружены из {USERS_FILE} после скачивания.") + return users if isinstance(users, dict) else {} except (FileNotFoundError, RepositoryNotFoundError): logging.warning(f"Файл {USERS_FILE} не найден локально и в репозитории HF. Создание пустого файла.") - if not os.path.exists(USERS_FILE): - with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump({}, f) + with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump({}, f) return {} except json.JSONDecodeError: logging.error(f"Ошибка декодирования JSON в {USERS_FILE} после скачивания.") @@ -151,7 +137,6 @@ def load_users(): logging.error(f"Неизвестная ошибка при загрузке пользователей ({USERS_FILE}): {e}", exc_info=True) return {} - def save_users(users): try: with open(USERS_FILE, 'w', encoding='utf-8') as file: @@ -161,6 +146,7 @@ def save_users(users): except Exception as e: logging.error(f"Ошибка при сохранении данных пользователей в {USERS_FILE}: {e}", exc_info=True) + def upload_db_to_hf(specific_file=None): if not HF_TOKEN_WRITE: logging.warning("Переменная окружения HF_TOKEN (для записи) не установлена. Загрузка на Hugging Face пропущена.") @@ -207,19 +193,16 @@ def download_db_from_hf(specific_file=None): token=HF_TOKEN_READ, local_dir=".", local_dir_use_symlinks=False, - force_download=True # Force download to overwrite local file + force_download=True ) logging.info(f"Файл {file_name} успешно скачан из Hugging Face в {local_path}.") downloaded_files_count += 1 except RepositoryNotFoundError: logging.error(f"Репозиторий {REPO_ID} не найден на Hugging Face. Скачивание прервано.") - break # Stop trying if repo not found + break except Exception as e: - # Check specifically for file not found (different from repo not found) - if "404" in str(e) or "does not exist" in str(e).lower(): - logging.warning(f"Файл {file_name} не найден в репозитории {REPO_ID}. Пропуск скачивания этого файла.") - # If the file doesn't exist remotely, should we delete locally? - # For now, just skip download. Local file remains as is or empty if created earlier. + if "404" in str(e) or isinstance(e, FileNotFoundError) or "EntryNotFound" in str(e): + logging.warning(f"Файл {file_name} не найден в репозитории {REPO_ID} или ошибка доступа. Пропуск скачивания этого файла.") else: logging.error(f"Ошибка при скачивании файла {file_name} с Hugging Face: {e}", exc_info=True) logging.info(f"Скачивание файлов с HF завершено. Скачано файлов: {downloaded_files_count}/{len(files_to_download)}.") @@ -230,7 +213,7 @@ def download_db_from_hf(specific_file=None): def periodic_backup(): - backup_interval = 1800 # 30 minutes + backup_interval = 1800 logging.info(f"Настройка периодического резервного копирования каждые {backup_interval} секунд.") while True: time.sleep(backup_interval) @@ -246,15 +229,14 @@ def catalog(): categories = data.get('categories', []) is_authenticated = 'user' in session - # Add original index before filtering/sorting - for i, p in enumerate(all_products): - p['_original_index'] = i + # Filter out products that are not in stock + available_products = [p for p in all_products if p.get('in_stock', True)] - # Filter out "out of stock" products for display - display_products = [p for p in all_products if p.get('in_stock', True)] - - # Sort: Top products first, then by name - display_products.sort(key=lambda p: (not p.get('is_top', False), p.get('name', '').lower())) + # Sort products: top products first, then alphabetically + sorted_products = sorted( + available_products, + key=lambda p: (not p.get('is_top', False), p.get('name', '').lower()) + ) catalog_html = ''' @@ -266,13 +248,229 @@ def catalog(): - - + - - -
-
- {% endif %}
- {{ product.get('description', '') }}
-