diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -44,22 +44,40 @@ def load_data(): data['products'] = [] if 'categories' not in data: data['categories'] = [] + + # Ensure default values for new fields + for product in data['products']: + product.setdefault('is_top', False) + product.setdefault('in_stock', True) + return 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}") - return {'products': [], 'categories': []} - else: + + 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): 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 + 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): @@ -69,7 +87,7 @@ def load_data(): logging.error(f"Ошибка декодирования JSON в {DATA_FILE} после попытки скачивания.") return {'products': [], 'categories': []} except Exception as e: - logging.error(f"Неизвестная ошибка при загрузке данных после попытки скачивания: {e}") + logging.error(f"Неизвестная ошибка при загрузке данных после попытки скачивания: {e}", exc_info=True) return {'products': [], 'categories': []} except json.JSONDecodeError: logging.error(f"Ошибка декодирования JSON в локальном {DATA_FILE}. Файл может быть поврежден. Возврат пустой структуры.") @@ -78,9 +96,14 @@ def load_data(): logging.error(f"Неизвестная ошибка при загрузке данных ({DATA_FILE}): {e}", exc_info=True) return {'products': [], 'categories': []} - def save_data(data): try: + # Ensure defaults before saving + if 'products' in data: + for product in data['products']: + product.setdefault('is_top', False) + product.setdefault('in_stock', True) + with open(DATA_FILE, 'w', encoding='utf-8') as file: json.dump(data, file, ensure_ascii=False, indent=4) logging.info(f"Данные успешно сохранены в {DATA_FILE}") @@ -90,6 +113,7 @@ 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}") @@ -97,14 +121,22 @@ def load_users(): except FileNotFoundError: logging.warning(f"Локальный файл {USERS_FILE} не найден. Попытка скачать с HF.") 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} после скачивания.") - return users if isinstance(users, dict) else {} + 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 {} except (FileNotFoundError, RepositoryNotFoundError): logging.warning(f"Файл {USERS_FILE} не найден локально и в репозитории HF. Создание пустого файла.") - with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump({}, f) + if not os.path.exists(USERS_FILE): + with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump({}, f) return {} except json.JSONDecodeError: logging.error(f"Ошибка декодирования JSON в {USERS_FILE} после скачивания.") @@ -119,6 +151,7 @@ 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: @@ -128,7 +161,6 @@ 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 пропущена.") @@ -175,16 +207,19 @@ def download_db_from_hf(specific_file=None): token=HF_TOKEN_READ, local_dir=".", local_dir_use_symlinks=False, - force_download=True + force_download=True # Force download to overwrite local file ) logging.info(f"Файл {file_name} успешно скачан из Hugging Face в {local_path}.") downloaded_files_count += 1 except RepositoryNotFoundError: logging.error(f"Репозиторий {REPO_ID} не найден на Hugging Face. Скачивание прервано.") - break + break # Stop trying if repo not found except Exception as e: - if "404" in str(e) or isinstance(e, FileNotFoundError): - logging.warning(f"Файл {file_name} не найден в репозитории {REPO_ID} или ошибка доступа. Пропуск скачивания этого файла.") + # 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. else: logging.error(f"Ошибка при скачивании файла {file_name} с Hugging Face: {e}", exc_info=True) logging.info(f"Скачивание файлов с HF завершено. Скачано файлов: {downloaded_files_count}/{len(files_to_download)}.") @@ -195,7 +230,7 @@ def download_db_from_hf(specific_file=None): def periodic_backup(): - backup_interval = 1800 + backup_interval = 1800 # 30 minutes logging.info(f"Настройка периодического резервного копирования каждые {backup_interval} секунд.") while True: time.sleep(backup_interval) @@ -207,10 +242,20 @@ def periodic_backup(): @app.route('/') def catalog(): data = load_data() - products = data.get('products', []) + all_products = data.get('products', []) 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 "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())) + catalog_html = ''' @@ -221,225 +266,13 @@ def catalog(): - - -
-
- {% endif %}
- {{ product.get('description', '')[:50] }}{% if product.get('description', '')|length > 50 %}...{% endif %}
-
+ {% endif %}
+ {{ product.get('description', '') }}
+