diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -19,7 +19,6 @@ app = Flask(__name__) app.secret_key = 'manolisa_secret_key_no_login' DATA_FILE = 'data.json' - SYNC_FILES = [DATA_FILE] REPO_ID = "Kgshop/manolisa" @@ -50,7 +49,7 @@ translations = { 'details': "Подробнее", 'add_to_cart': "В корзину", 'loading': "Загрузка...", - 'specify_quantity_color': "Укажите количество", + 'specify_quantity_color': "Укажите количество и цвет", 'quantity': "Количество (линеек):", 'color_variant': "Цвет/Вариант:", 'confirm_add_to_cart': "Добавить в корзину", @@ -70,8 +69,8 @@ translations = { 'formulating_order': "Формируем заказ...", 'order_creation_error': "Ошибка при формировании заказа:", 'category': "Категория:", - 'no_category': "Без категории", 'season': "Сезон:", + 'no_category': "Без категории", 'no_season': "Без сезона", 'price': "Цена:", 'description': "Описание:", @@ -101,8 +100,6 @@ translations = { 'online_order': 'Онлайн', 'address_1_title': 'Адрес:', 'address_1_detail': 'Город Алматы, Рынок Олжа, ряд VIP, Бутик 7', - 'currency_usd': '$', - 'currency_kzt': '₸', }, 'kk': { 'site_title': "ManolisA - Каталог", @@ -120,7 +117,7 @@ translations = { 'details': "Толығырақ", 'add_to_cart': "Себетке қосу", 'loading': "Жүктелуде...", - 'specify_quantity_color': "Санын көрсетіңіз", + 'specify_quantity_color': "Саны мен түсін көрсетіңіз", 'quantity': "Саны (лента):", 'color_variant': "Түсі/нұсқасы:", 'confirm_add_to_cart': "Себетке қосу", @@ -140,8 +137,8 @@ translations = { 'formulating_order': "Тапсырысты рәсімдеудеміз...", 'order_creation_error': "Тапсырысты рәсімдеу кезінде қате:", 'category': "Санат:", - 'no_category': "Санатсыз", 'season': "Маусым:", + 'no_category': "Санатсыз", 'no_season': "Маусымсыз", 'price': "Бағасы:", 'description': "Сипаттамасы:", @@ -171,12 +168,9 @@ translations = { 'online_order': 'Онлайн', 'address_1_title': 'Мекенжай:', 'address_1_detail': 'Алматы қаласы, Олжа базары, VIP қатары, 7 бутик', - 'currency_usd': '$', - 'currency_kzt': '₸', } } - def get_locale(): return session.get('lang', 'ru') @@ -193,32 +187,19 @@ def set_language(language): session['lang'] = language if language in translations else 'ru' return redirect(request.referrer or url_for('catalog')) - def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWNLOAD_DELAY): if not HF_TOKEN_READ and not HF_TOKEN_WRITE: logging.warning("HF_TOKEN_READ/HF_TOKEN_WRITE not set. Download might fail for private repos.") - token_to_use = HF_TOKEN_READ if HF_TOKEN_READ else HF_TOKEN_WRITE - files_to_download = [specific_file] if specific_file else SYNC_FILES logging.info(f"Attempting download for {files_to_download} from {REPO_ID}...") all_successful = True - for file_name in files_to_download: success = False for attempt in range(retries + 1): try: logging.info(f"Downloading {file_name} (Attempt {attempt + 1}/{retries + 1})...") - local_path = hf_hub_download( - repo_id=REPO_ID, - filename=file_name, - repo_type="dataset", - token=token_to_use, - local_dir=".", - local_dir_use_symlinks=False, - force_download=True, - resume_download=False - ) + local_path = hf_hub_download(repo_id=REPO_ID, filename=file_name, repo_type="dataset", token=token_to_use, local_dir=".", local_dir_use_symlinks=False, force_download=True, resume_download=False) logging.info(f"Successfully downloaded {file_name} to {local_path}.") success = True break @@ -232,7 +213,7 @@ def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWN try: if file_name == DATA_FILE: with open(file_name, 'w', encoding='utf-8') as f: - json.dump({'products': [], 'categories': [], 'seasons': [], 'orders': {}, 'employees': [], 'settings': {'usd_kzt_rate': 450.0}}, f) + json.dump({'products': [], 'categories': [], 'seasons': [], 'orders': {}, 'employees': [], 'exchange_rate_kzt': 450.0}, f) logging.info(f"Created empty local file {file_name} because it was not found on HF.") except Exception as create_e: logging.error(f"Failed to create empty local file {file_name}: {create_e}") @@ -244,14 +225,11 @@ def download_db_from_hf(specific_file=None, retries=DOWNLOAD_RETRIES, delay=DOWN logging.error(f"Network error downloading {file_name} (Attempt {attempt + 1}): {e}. Retrying in {delay}s...") except Exception as e: logging.error(f"Unexpected error downloading {file_name} (Attempt {attempt + 1}): {e}. Retrying in {delay}s...", exc_info=True) - if attempt < retries: time.sleep(delay) - if not success: logging.error(f"Failed to download {file_name} after {retries + 1} attempts.") all_successful = False - logging.info(f"Download process finished. Overall success: {all_successful}") return all_successful @@ -263,18 +241,10 @@ def upload_db_to_hf(specific_file=None): api = HfApi() files_to_upload = [specific_file] if specific_file else SYNC_FILES logging.info(f"Starting upload of {files_to_upload} to HF repo {REPO_ID}...") - for file_name in files_to_upload: if os.path.exists(file_name): try: - api.upload_file( - path_or_fileobj=file_name, - path_in_repo=file_name, - repo_id=REPO_ID, - repo_type="dataset", - token=HF_TOKEN_WRITE, - commit_message=f"Sync {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" - ) + api.upload_file(path_or_fileobj=file_name, path_in_repo=file_name, repo_id=REPO_ID, repo_type="dataset", token=HF_TOKEN_WRITE, commit_message=f"Sync {file_name} {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") logging.info(f"File {file_name} successfully uploaded to Hugging Face.") except Exception as e: logging.error(f"Error uploading file {file_name} to Hugging Face: {e}") @@ -293,28 +263,8 @@ def periodic_backup(): upload_db_to_hf() logging.info("Periodic backup finished.") -def migrate_data_structure(data): - migrated = False - if 'products' in data and isinstance(data['products'], list): - for product in data['products']: - if 'photos' in product and 'variants' not in product: - migrated = True - colors = product.pop('colors', []) - photos = product.pop('photos', []) - product['variants'] = [] - - if colors and any(c.strip() for c in colors): - for color in colors: - if color.strip(): - product['variants'].append({"color": color.strip(), "photos": list(photos)}) - else: - product['variants'].append({"color": "Default", "photos": photos}) - if migrated: - logging.info("Migrated old product data structure to new variant-based structure.") - return data, migrated - def load_data(): - default_data = {'products': [], 'categories': [], 'seasons': [], 'orders': {}, 'employees': [], 'settings': {'usd_kzt_rate': 450.0}} + default_data = {'products': [], 'categories': [], 'seasons': [], 'orders': {}, 'employees': [], 'exchange_rate_kzt': 450.0} try: with open(DATA_FILE, 'r', encoding='utf-8') as file: data = json.load(file) @@ -322,21 +272,9 @@ def load_data(): if not isinstance(data, dict): logging.warning(f"Local {DATA_FILE} is not a dictionary. Attempting download.") raise FileNotFoundError - - # Check for all keys - if 'products' not in data: data['products'] = [] - if 'categories' not in data: data['categories'] = [] - if 'seasons' not in data: data['seasons'] = [] - if 'orders' not in data: data['orders'] = {} - if 'employees' not in data: data['employees'] = [] - if 'settings' not in data: data['settings'] = {'usd_kzt_rate': 450.0} - if 'usd_kzt_rate' not in data['settings']: data['settings']['usd_kzt_rate'] = 450.0 - - data, migrated = migrate_data_structure(data) - if migrated: - save_data(data) + for key, default_value in default_data.items(): + if key not in data: data[key] = default_value return data - except FileNotFoundError: logging.warning(f"Local file {DATA_FILE} not found. Attempting download from HF.") @@ -348,20 +286,9 @@ def load_data(): if not isinstance(data, dict): logging.error(f"Downloaded {DATA_FILE} is not a dictionary. Using default.") return default_data - - if 'products' not in data: data['products'] = [] - if 'categories' not in data: data['categories'] = [] - if 'seasons' not in data: data['seasons'] = [] - if 'orders' not in data: data['orders'] = {} - if 'employees' not in data: data['employees'] = [] - if 'settings' not in data: data['settings'] = {'usd_kzt_rate': 450.0} - if 'usd_kzt_rate' not in data['settings']: data['settings']['usd_kzt_rate'] = 450.0 - - data, migrated = migrate_data_structure(data) - if migrated: - save_data(data) + for key, default_value in default_data.items(): + if key not in data: data[key] = default_value return data - except FileNotFoundError: logging.error(f"File {DATA_FILE} still not found even after download reported success. Using default.") return default_data @@ -387,7 +314,9 @@ def save_data(data): if not isinstance(data, dict): logging.error("Attempted to save invalid data structure (not a dict). Aborting save.") return - + default_data_keys = {'products': [], 'categories': [], 'seasons': [], 'orders': {}, 'employees': [], 'exchange_rate_kzt': 450.0} + for key, default_value in default_data_keys.items(): + if key not in data: data[key] = default_value with open(DATA_FILE, 'w', encoding='utf-8') as file: json.dump(data, file, ensure_ascii=False, indent=4) logging.info(f"Data successfully saved to {DATA_FILE}") @@ -395,8 +324,6 @@ def save_data(data): except Exception as e: logging.error(f"Error saving data to {DATA_FILE}: {e}", exc_info=True) - - CATALOG_TEMPLATE = ''' @@ -405,13 +332,13 @@ CATALOG_TEMPLATE = '''
Категорий нет.
{% endfor %}Категорий нет.
{% endfor %} +Сезонов нет.
{% endfor %}Сезонов нет.
{% endfor %} +Сотрудников нет.
{% endfor %}Сотрудников нет.
{% endfor %} +