Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,48 +10,40 @@ from huggingface_hub.utils import RepositoryNotFoundError
|
|
| 10 |
from werkzeug.utils import secure_filename
|
| 11 |
|
| 12 |
app = Flask(__name__)
|
| 13 |
-
app.secret_key = 'your_unique_secret_key_12345'
|
| 14 |
DATA_FILE = 'data_detobuv.json'
|
| 15 |
USERS_FILE = 'users_detobuv.json'
|
| 16 |
-
CONFIG_FILE = 'config.json'
|
| 17 |
|
| 18 |
-
# Список файлов для синхронизации
|
| 19 |
SYNC_FILES = [DATA_FILE, USERS_FILE, CONFIG_FILE]
|
| 20 |
|
| 21 |
-
# Настройки Hugging Face
|
| 22 |
REPO_ID = "Kgshop/clients"
|
| 23 |
HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
|
| 24 |
HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
RETAIL_ADDRESS = "Дордой Мир Обуви, номер 150" # Розница
|
| 29 |
|
| 30 |
-
# Поддерживаемые валюты
|
| 31 |
CURRENCIES = {
|
| 32 |
'USD': 'Доллар США ($)',
|
| 33 |
'KGS': 'Кыргызский сом (с)'
|
| 34 |
}
|
| 35 |
|
| 36 |
-
# Настройка логирования
|
| 37 |
logging.basicConfig(level=logging.DEBUG)
|
| 38 |
|
| 39 |
def load_config():
|
| 40 |
-
"""Загрузка конфигурации (курс KGS к USD)."""
|
| 41 |
try:
|
| 42 |
with open(CONFIG_FILE, 'r', encoding='utf-8') as file:
|
| 43 |
config = json.load(file)
|
| 44 |
-
return config.get('kgs_to_usd', 89.0)
|
| 45 |
except (FileNotFoundError, json.JSONDecodeError):
|
| 46 |
-
return 89.0
|
| 47 |
|
| 48 |
def save_config(kgs_to_usd):
|
| 49 |
-
"""Сохранение конфигурации."""
|
| 50 |
with open(CONFIG_FILE, 'w', encoding='utf-8') as file:
|
| 51 |
json.dump({'kgs_to_usd': kgs_to_usd}, file, ensure_ascii=False, indent=4)
|
| 52 |
|
| 53 |
def convert_price(price_usd, currency):
|
| 54 |
-
"""Конвертация цены из USD в указанную валюту."""
|
| 55 |
kgs_to_usd = load_config()
|
| 56 |
if currency == 'KGS':
|
| 57 |
return round(price_usd * kgs_to_usd, 2)
|
|
@@ -101,7 +93,7 @@ def load_users():
|
|
| 101 |
def save_users(users):
|
| 102 |
with open(USERS_FILE, 'w', encoding='utf-8') as file:
|
| 103 |
json.dump(users, file, ensure_ascii=False, indent=4)
|
| 104 |
-
upload_db_to_hf()
|
| 105 |
|
| 106 |
def upload_db_to_hf():
|
| 107 |
try:
|
|
@@ -398,6 +390,8 @@ def catalog():
|
|
| 398 |
max-width: 700px;
|
| 399 |
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
| 400 |
animation: slideIn 0.3s ease-out;
|
|
|
|
|
|
|
| 401 |
}
|
| 402 |
body.dark-mode .modal-content {
|
| 403 |
background: #2d3748;
|
|
@@ -475,6 +469,17 @@ def catalog():
|
|
| 475 |
border: 1px solid #e2e8f0;
|
| 476 |
font-size: 1rem;
|
| 477 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 478 |
</style>
|
| 479 |
</head>
|
| 480 |
<body>
|
|
@@ -513,14 +518,14 @@ def catalog():
|
|
| 513 |
</div>
|
| 514 |
<div class="products-grid" id="products-grid">
|
| 515 |
{% for product in products %}
|
| 516 |
-
<div class="product"
|
| 517 |
-
data-name="{{ product['name']|lower }}"
|
| 518 |
data-description="{{ product['description']|lower }}"
|
| 519 |
data-category="{{ product.get('category', 'Без категории') }}">
|
| 520 |
{% if product.get('photos') and product['photos']|length > 0 %}
|
| 521 |
<div class="product-image">
|
| 522 |
-
<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photos'][0] }}"
|
| 523 |
-
alt="{{ product['name'] }}"
|
| 524 |
loading="lazy">
|
| 525 |
</div>
|
| 526 |
{% endif %}
|
|
@@ -708,7 +713,7 @@ def catalog():
|
|
| 708 |
const itemTotal = itemPrice * item.quantity;
|
| 709 |
total += itemTotal;
|
| 710 |
return `
|
| 711 |
-
<div class="cart-item">
|
| 712 |
<div style="display: flex; align-items: center;">
|
| 713 |
${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
|
| 714 |
<div>
|
|
@@ -717,6 +722,7 @@ def catalog():
|
|
| 717 |
</div>
|
| 718 |
</div>
|
| 719 |
<span>${itemTotal.toFixed(2)} ${selectedCurrency}</span>
|
|
|
|
| 720 |
</div>
|
| 721 |
`;
|
| 722 |
}).join('');
|
|
@@ -725,6 +731,14 @@ def catalog():
|
|
| 725 |
document.getElementById('cartModal').style.display = 'block';
|
| 726 |
}
|
| 727 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
function orderViaWhatsApp() {
|
| 729 |
const cart = JSON.parse(localStorage.getItem('cart') || '[]');
|
| 730 |
if (cart.length === 0) {
|
|
@@ -782,11 +796,11 @@ def catalog():
|
|
| 782 |
</body>
|
| 783 |
</html>
|
| 784 |
'''
|
| 785 |
-
return render_template_string(catalog_html, products=products, categories=categories,
|
| 786 |
-
repo_id=REPO_ID, is_authenticated=is_authenticated,
|
| 787 |
-
wholesale_address=WHOLESALE_ADDRESS, retail_address=RETAIL_ADDRESS,
|
| 788 |
-
session=session, convert_price=convert_price,
|
| 789 |
-
selected_currency=selected_currency, currencies=CURRENCIES,
|
| 790 |
kgs_to_usd=kgs_to_usd)
|
| 791 |
|
| 792 |
@app.route('/product/<int:index>')
|
|
@@ -808,8 +822,8 @@ def product_detail(index):
|
|
| 808 |
{% for photo in product['photos'] %}
|
| 809 |
<div class="swiper-slide" style="background-color: #fff; display: flex; justify-content: center; align-items: center;">
|
| 810 |
<div class="swiper-zoom-container">
|
| 811 |
-
<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ photo }}"
|
| 812 |
-
alt="{{ product['name'] }}"
|
| 813 |
style="max-width: 100%; max-height: 300px; object-fit: contain;">
|
| 814 |
</div>
|
| 815 |
</div>
|
|
@@ -834,8 +848,8 @@ def product_detail(index):
|
|
| 834 |
<p><strong>Доступные цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
|
| 835 |
</div>
|
| 836 |
'''
|
| 837 |
-
return render_template_string(detail_html, product=product, repo_id=REPO_ID,
|
| 838 |
-
is_authenticated=is_authenticated, convert_price=convert_price,
|
| 839 |
selected_currency=selected_currency)
|
| 840 |
|
| 841 |
@app.route('/set_currency', methods=['POST'])
|
|
@@ -856,17 +870,17 @@ def register():
|
|
| 856 |
country = request.form.get('country')
|
| 857 |
city = request.form.get('city')
|
| 858 |
purchase_type = request.form.get('purchase_type')
|
| 859 |
-
|
| 860 |
if purchase_type == 'retail':
|
| 861 |
return render_template_string('''
|
| 862 |
<h2>Мы продаем только оптом</h2>
|
| 863 |
<p><a href="{{ url_for('register') }}">Назад к регистрации</a></p>
|
| 864 |
''')
|
| 865 |
-
|
| 866 |
users = load_users()
|
| 867 |
if login in users:
|
| 868 |
return "Пользователь с таким логином уже существует", 400
|
| 869 |
-
|
| 870 |
users[login] = {
|
| 871 |
'password': password,
|
| 872 |
'first_name': first_name,
|
|
@@ -879,9 +893,9 @@ def register():
|
|
| 879 |
session['user'] = login
|
| 880 |
session['country'] = country
|
| 881 |
session['city'] = city
|
| 882 |
-
session['currency'] = 'USD'
|
| 883 |
return redirect(url_for('catalog'))
|
| 884 |
-
|
| 885 |
return render_template_string('''
|
| 886 |
<!DOCTYPE html>
|
| 887 |
<html lang="ru">
|
|
@@ -976,15 +990,15 @@ def login():
|
|
| 976 |
login = request.form.get('login')
|
| 977 |
password = request.form.get('password')
|
| 978 |
users = load_users()
|
| 979 |
-
|
| 980 |
if login in users and users[login]['password'] == password:
|
| 981 |
session['user'] = login
|
| 982 |
session['country'] = users[login]['country']
|
| 983 |
session['city'] = users[login]['city']
|
| 984 |
-
session['currency'] = 'USD'
|
| 985 |
return redirect(url_for('catalog'))
|
| 986 |
return "Неверный логин или пароль", 401
|
| 987 |
-
|
| 988 |
return render_template_string('''
|
| 989 |
<!DOCTYPE html>
|
| 990 |
<html lang="ru">
|
|
@@ -1069,7 +1083,7 @@ def auto_login():
|
|
| 1069 |
session['user'] = login
|
| 1070 |
session['country'] = users[login]['country']
|
| 1071 |
session['city'] = users[login]['city']
|
| 1072 |
-
session['currency'] = 'USD'
|
| 1073 |
return "OK", 200
|
| 1074 |
return "Ошибка авторизации", 401
|
| 1075 |
|
|
@@ -1091,10 +1105,10 @@ def admin():
|
|
| 1091 |
|
| 1092 |
if request.method == 'POST':
|
| 1093 |
action = request.form.get('action')
|
| 1094 |
-
|
| 1095 |
if action == 'add_category':
|
| 1096 |
category_name = request.form.get('category_name')
|
| 1097 |
-
if category_name and category_name not in categories:
|
| 1098 |
categories.append(category_name)
|
| 1099 |
save_data(data)
|
| 1100 |
return redirect(url_for('admin'))
|
|
@@ -1117,7 +1131,7 @@ def admin():
|
|
| 1117 |
photos_files = request.files.getlist('photos')
|
| 1118 |
colors = request.form.getlist('colors')
|
| 1119 |
photos_list = []
|
| 1120 |
-
|
| 1121 |
if photos_files:
|
| 1122 |
for photo in photos_files[:10]:
|
| 1123 |
if photo and photo.filename:
|
|
@@ -1138,14 +1152,14 @@ def admin():
|
|
| 1138 |
photos_list.append(photo_filename)
|
| 1139 |
if os.path.exists(temp_path):
|
| 1140 |
os.remove(temp_path)
|
| 1141 |
-
|
| 1142 |
if not name or not price or not description:
|
| 1143 |
return "Ошибка: Заполните все обязательные поля", 400
|
| 1144 |
-
|
| 1145 |
-
price = float(price.replace(',', '.'))
|
| 1146 |
new_product = {
|
| 1147 |
'name': name,
|
| 1148 |
-
'price': price,
|
| 1149 |
'description': description,
|
| 1150 |
'category': category if category in categories else 'Без категории',
|
| 1151 |
'photos': photos_list,
|
|
@@ -1154,7 +1168,7 @@ def admin():
|
|
| 1154 |
products.append(new_product)
|
| 1155 |
save_data(data)
|
| 1156 |
return redirect(url_for('admin'))
|
| 1157 |
-
|
| 1158 |
elif action == 'edit':
|
| 1159 |
index = int(request.form.get('index'))
|
| 1160 |
name = request.form.get('name')
|
|
@@ -1163,7 +1177,7 @@ def admin():
|
|
| 1163 |
category = request.form.get('category')
|
| 1164 |
photos_files = request.files.getlist('photos')
|
| 1165 |
colors = request.form.getlist('colors')
|
| 1166 |
-
|
| 1167 |
if photos_files and any(photo.filename for photo in photos_files):
|
| 1168 |
new_photos_list = []
|
| 1169 |
for photo in photos_files[:10]:
|
|
@@ -1186,15 +1200,15 @@ def admin():
|
|
| 1186 |
if os.path.exists(temp_path):
|
| 1187 |
os.remove(temp_path)
|
| 1188 |
products[index]['photos'] = new_photos_list
|
| 1189 |
-
|
| 1190 |
products[index]['name'] = name
|
| 1191 |
-
products[index]['price'] = float(price.replace(',', '.'))
|
| 1192 |
products[index]['description'] = description
|
| 1193 |
products[index]['category'] = category if category in categories else 'Без категории'
|
| 1194 |
products[index]['colors'] = colors if colors else []
|
| 1195 |
save_data(data)
|
| 1196 |
return redirect(url_for('admin'))
|
| 1197 |
-
|
| 1198 |
elif action == 'delete':
|
| 1199 |
index = int(request.form.get('index'))
|
| 1200 |
del products[index]
|
|
@@ -1204,7 +1218,7 @@ def admin():
|
|
| 1204 |
elif action == 'set_exchange_rate':
|
| 1205 |
kgs_to_usd = float(request.form.get('kgs_to_usd').replace(',', '.'))
|
| 1206 |
save_config(kgs_to_usd)
|
| 1207 |
-
upload_db_to_hf()
|
| 1208 |
return redirect(url_for('admin'))
|
| 1209 |
|
| 1210 |
elif action == 'delete_user':
|
|
@@ -1213,7 +1227,7 @@ def admin():
|
|
| 1213 |
del users[login]
|
| 1214 |
save_users(users)
|
| 1215 |
return redirect(url_for('admin'))
|
| 1216 |
-
|
| 1217 |
admin_html = '''
|
| 1218 |
<!DOCTYPE html>
|
| 1219 |
<html lang="ru">
|
|
@@ -1480,8 +1494,8 @@ def admin():
|
|
| 1480 |
</body>
|
| 1481 |
</html>
|
| 1482 |
'''
|
| 1483 |
-
return render_template_string(admin_html, products=products, categories=categories,
|
| 1484 |
-
repo_id=REPO_ID, users=users, kgs_to_usd=kgs_to_usd,
|
| 1485 |
convert_price=convert_price)
|
| 1486 |
|
| 1487 |
@app.route('/backup', methods=['POST'])
|
|
|
|
| 10 |
from werkzeug.utils import secure_filename
|
| 11 |
|
| 12 |
app = Flask(__name__)
|
| 13 |
+
app.secret_key = 'your_unique_secret_key_12345'
|
| 14 |
DATA_FILE = 'data_detobuv.json'
|
| 15 |
USERS_FILE = 'users_detobuv.json'
|
| 16 |
+
CONFIG_FILE = 'config.json'
|
| 17 |
|
|
|
|
| 18 |
SYNC_FILES = [DATA_FILE, USERS_FILE, CONFIG_FILE]
|
| 19 |
|
|
|
|
| 20 |
REPO_ID = "Kgshop/clients"
|
| 21 |
HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
|
| 22 |
HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
|
| 23 |
|
| 24 |
+
WHOLESALE_ADDRESS = "Дордой, рынок Кербен, 9 ряд, 06 бутик"
|
| 25 |
+
RETAIL_ADDRESS = "Дордой Мир Обуви, номер 150"
|
|
|
|
| 26 |
|
|
|
|
| 27 |
CURRENCIES = {
|
| 28 |
'USD': 'Доллар США ($)',
|
| 29 |
'KGS': 'Кыргызский сом (с)'
|
| 30 |
}
|
| 31 |
|
|
|
|
| 32 |
logging.basicConfig(level=logging.DEBUG)
|
| 33 |
|
| 34 |
def load_config():
|
|
|
|
| 35 |
try:
|
| 36 |
with open(CONFIG_FILE, 'r', encoding='utf-8') as file:
|
| 37 |
config = json.load(file)
|
| 38 |
+
return config.get('kgs_to_usd', 89.0)
|
| 39 |
except (FileNotFoundError, json.JSONDecodeError):
|
| 40 |
+
return 89.0
|
| 41 |
|
| 42 |
def save_config(kgs_to_usd):
|
|
|
|
| 43 |
with open(CONFIG_FILE, 'w', encoding='utf-8') as file:
|
| 44 |
json.dump({'kgs_to_usd': kgs_to_usd}, file, ensure_ascii=False, indent=4)
|
| 45 |
|
| 46 |
def convert_price(price_usd, currency):
|
|
|
|
| 47 |
kgs_to_usd = load_config()
|
| 48 |
if currency == 'KGS':
|
| 49 |
return round(price_usd * kgs_to_usd, 2)
|
|
|
|
| 93 |
def save_users(users):
|
| 94 |
with open(USERS_FILE, 'w', encoding='utf-8') as file:
|
| 95 |
json.dump(users, file, ensure_ascii=False, indent=4)
|
| 96 |
+
upload_db_to_hf()
|
| 97 |
|
| 98 |
def upload_db_to_hf():
|
| 99 |
try:
|
|
|
|
| 390 |
max-width: 700px;
|
| 391 |
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
| 392 |
animation: slideIn 0.3s ease-out;
|
| 393 |
+
overflow-y: auto;
|
| 394 |
+
max-height: 80vh;
|
| 395 |
}
|
| 396 |
body.dark-mode .modal-content {
|
| 397 |
background: #2d3748;
|
|
|
|
| 469 |
border: 1px solid #e2e8f0;
|
| 470 |
font-size: 1rem;
|
| 471 |
}
|
| 472 |
+
.remove-item-button {
|
| 473 |
+
background: none;
|
| 474 |
+
border: none;
|
| 475 |
+
color: #ef4444;
|
| 476 |
+
cursor: pointer;
|
| 477 |
+
font-size: 1rem;
|
| 478 |
+
margin-left: 10px;
|
| 479 |
+
}
|
| 480 |
+
.remove-item-button:hover {
|
| 481 |
+
color: #dc2626;
|
| 482 |
+
}
|
| 483 |
</style>
|
| 484 |
</head>
|
| 485 |
<body>
|
|
|
|
| 518 |
</div>
|
| 519 |
<div class="products-grid" id="products-grid">
|
| 520 |
{% for product in products %}
|
| 521 |
+
<div class="product"
|
| 522 |
+
data-name="{{ product['name']|lower }}"
|
| 523 |
data-description="{{ product['description']|lower }}"
|
| 524 |
data-category="{{ product.get('category', 'Без категории') }}">
|
| 525 |
{% if product.get('photos') and product['photos']|length > 0 %}
|
| 526 |
<div class="product-image">
|
| 527 |
+
<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ product['photos'][0] }}"
|
| 528 |
+
alt="{{ product['name'] }}"
|
| 529 |
loading="lazy">
|
| 530 |
</div>
|
| 531 |
{% endif %}
|
|
|
|
| 713 |
const itemTotal = itemPrice * item.quantity;
|
| 714 |
total += itemTotal;
|
| 715 |
return `
|
| 716 |
+
<div class="cart-item" data-item-id="${item.id}">
|
| 717 |
<div style="display: flex; align-items: center;">
|
| 718 |
${item.photo ? `<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/${item.photo}" alt="${item.name}">` : ''}
|
| 719 |
<div>
|
|
|
|
| 722 |
</div>
|
| 723 |
</div>
|
| 724 |
<span>${itemTotal.toFixed(2)} ${selectedCurrency}</span>
|
| 725 |
+
<button class="remove-item-button" onclick="removeItemFromCart('${item.id}')">×</button>
|
| 726 |
</div>
|
| 727 |
`;
|
| 728 |
}).join('');
|
|
|
|
| 731 |
document.getElementById('cartModal').style.display = 'block';
|
| 732 |
}
|
| 733 |
|
| 734 |
+
function removeItemFromCart(itemId) {
|
| 735 |
+
let cart = JSON.parse(localStorage.getItem('cart') || '[]');
|
| 736 |
+
cart = cart.filter(item => item.id !== itemId);
|
| 737 |
+
localStorage.setItem('cart', JSON.stringify(cart));
|
| 738 |
+
openCartModal();
|
| 739 |
+
updateCartButton();
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
function orderViaWhatsApp() {
|
| 743 |
const cart = JSON.parse(localStorage.getItem('cart') || '[]');
|
| 744 |
if (cart.length === 0) {
|
|
|
|
| 796 |
</body>
|
| 797 |
</html>
|
| 798 |
'''
|
| 799 |
+
return render_template_string(catalog_html, products=products, categories=categories,
|
| 800 |
+
repo_id=REPO_ID, is_authenticated=is_authenticated,
|
| 801 |
+
wholesale_address=WHOLESALE_ADDRESS, retail_address=RETAIL_ADDRESS,
|
| 802 |
+
session=session, convert_price=convert_price,
|
| 803 |
+
selected_currency=selected_currency, currencies=CURRENCIES,
|
| 804 |
kgs_to_usd=kgs_to_usd)
|
| 805 |
|
| 806 |
@app.route('/product/<int:index>')
|
|
|
|
| 822 |
{% for photo in product['photos'] %}
|
| 823 |
<div class="swiper-slide" style="background-color: #fff; display: flex; justify-content: center; align-items: center;">
|
| 824 |
<div class="swiper-zoom-container">
|
| 825 |
+
<img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ photo }}"
|
| 826 |
+
alt="{{ product['name'] }}"
|
| 827 |
style="max-width: 100%; max-height: 300px; object-fit: contain;">
|
| 828 |
</div>
|
| 829 |
</div>
|
|
|
|
| 848 |
<p><strong>Доступные цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
|
| 849 |
</div>
|
| 850 |
'''
|
| 851 |
+
return render_template_string(detail_html, product=product, repo_id=REPO_ID,
|
| 852 |
+
is_authenticated=is_authenticated, convert_price=convert_price,
|
| 853 |
selected_currency=selected_currency)
|
| 854 |
|
| 855 |
@app.route('/set_currency', methods=['POST'])
|
|
|
|
| 870 |
country = request.form.get('country')
|
| 871 |
city = request.form.get('city')
|
| 872 |
purchase_type = request.form.get('purchase_type')
|
| 873 |
+
|
| 874 |
if purchase_type == 'retail':
|
| 875 |
return render_template_string('''
|
| 876 |
<h2>Мы продаем только оптом</h2>
|
| 877 |
<p><a href="{{ url_for('register') }}">Назад к регистрации</a></p>
|
| 878 |
''')
|
| 879 |
+
|
| 880 |
users = load_users()
|
| 881 |
if login in users:
|
| 882 |
return "Пользователь с таким логином уже существует", 400
|
| 883 |
+
|
| 884 |
users[login] = {
|
| 885 |
'password': password,
|
| 886 |
'first_name': first_name,
|
|
|
|
| 893 |
session['user'] = login
|
| 894 |
session['country'] = country
|
| 895 |
session['city'] = city
|
| 896 |
+
session['currency'] = 'USD'
|
| 897 |
return redirect(url_for('catalog'))
|
| 898 |
+
|
| 899 |
return render_template_string('''
|
| 900 |
<!DOCTYPE html>
|
| 901 |
<html lang="ru">
|
|
|
|
| 990 |
login = request.form.get('login')
|
| 991 |
password = request.form.get('password')
|
| 992 |
users = load_users()
|
| 993 |
+
|
| 994 |
if login in users and users[login]['password'] == password:
|
| 995 |
session['user'] = login
|
| 996 |
session['country'] = users[login]['country']
|
| 997 |
session['city'] = users[login]['city']
|
| 998 |
+
session['currency'] = 'USD'
|
| 999 |
return redirect(url_for('catalog'))
|
| 1000 |
return "Неверный логин или пароль", 401
|
| 1001 |
+
|
| 1002 |
return render_template_string('''
|
| 1003 |
<!DOCTYPE html>
|
| 1004 |
<html lang="ru">
|
|
|
|
| 1083 |
session['user'] = login
|
| 1084 |
session['country'] = users[login]['country']
|
| 1085 |
session['city'] = users[login]['city']
|
| 1086 |
+
session['currency'] = 'USD'
|
| 1087 |
return "OK", 200
|
| 1088 |
return "Ошибка авторизации", 401
|
| 1089 |
|
|
|
|
| 1105 |
|
| 1106 |
if request.method == 'POST':
|
| 1107 |
action = request.form.get('action')
|
| 1108 |
+
|
| 1109 |
if action == 'add_category':
|
| 1110 |
category_name = request.form.get('category_name')
|
| 1111 |
+
if category_name and category_name not in categories:
|
| 1112 |
categories.append(category_name)
|
| 1113 |
save_data(data)
|
| 1114 |
return redirect(url_for('admin'))
|
|
|
|
| 1131 |
photos_files = request.files.getlist('photos')
|
| 1132 |
colors = request.form.getlist('colors')
|
| 1133 |
photos_list = []
|
| 1134 |
+
|
| 1135 |
if photos_files:
|
| 1136 |
for photo in photos_files[:10]:
|
| 1137 |
if photo and photo.filename:
|
|
|
|
| 1152 |
photos_list.append(photo_filename)
|
| 1153 |
if os.path.exists(temp_path):
|
| 1154 |
os.remove(temp_path)
|
| 1155 |
+
|
| 1156 |
if not name or not price or not description:
|
| 1157 |
return "Ошибка: Заполните все обязательные поля", 400
|
| 1158 |
+
|
| 1159 |
+
price = float(price.replace(',', '.'))
|
| 1160 |
new_product = {
|
| 1161 |
'name': name,
|
| 1162 |
+
'price': price,
|
| 1163 |
'description': description,
|
| 1164 |
'category': category if category in categories else 'Без категории',
|
| 1165 |
'photos': photos_list,
|
|
|
|
| 1168 |
products.append(new_product)
|
| 1169 |
save_data(data)
|
| 1170 |
return redirect(url_for('admin'))
|
| 1171 |
+
|
| 1172 |
elif action == 'edit':
|
| 1173 |
index = int(request.form.get('index'))
|
| 1174 |
name = request.form.get('name')
|
|
|
|
| 1177 |
category = request.form.get('category')
|
| 1178 |
photos_files = request.files.getlist('photos')
|
| 1179 |
colors = request.form.getlist('colors')
|
| 1180 |
+
|
| 1181 |
if photos_files and any(photo.filename for photo in photos_files):
|
| 1182 |
new_photos_list = []
|
| 1183 |
for photo in photos_files[:10]:
|
|
|
|
| 1200 |
if os.path.exists(temp_path):
|
| 1201 |
os.remove(temp_path)
|
| 1202 |
products[index]['photos'] = new_photos_list
|
| 1203 |
+
|
| 1204 |
products[index]['name'] = name
|
| 1205 |
+
products[index]['price'] = float(price.replace(',', '.'))
|
| 1206 |
products[index]['description'] = description
|
| 1207 |
products[index]['category'] = category if category in categories else 'Без категории'
|
| 1208 |
products[index]['colors'] = colors if colors else []
|
| 1209 |
save_data(data)
|
| 1210 |
return redirect(url_for('admin'))
|
| 1211 |
+
|
| 1212 |
elif action == 'delete':
|
| 1213 |
index = int(request.form.get('index'))
|
| 1214 |
del products[index]
|
|
|
|
| 1218 |
elif action == 'set_exchange_rate':
|
| 1219 |
kgs_to_usd = float(request.form.get('kgs_to_usd').replace(',', '.'))
|
| 1220 |
save_config(kgs_to_usd)
|
| 1221 |
+
upload_db_to_hf()
|
| 1222 |
return redirect(url_for('admin'))
|
| 1223 |
|
| 1224 |
elif action == 'delete_user':
|
|
|
|
| 1227 |
del users[login]
|
| 1228 |
save_users(users)
|
| 1229 |
return redirect(url_for('admin'))
|
| 1230 |
+
|
| 1231 |
admin_html = '''
|
| 1232 |
<!DOCTYPE html>
|
| 1233 |
<html lang="ru">
|
|
|
|
| 1494 |
</body>
|
| 1495 |
</html>
|
| 1496 |
'''
|
| 1497 |
+
return render_template_string(admin_html, products=products, categories=categories,
|
| 1498 |
+
repo_id=REPO_ID, users=users, kgs_to_usd=kgs_to_usd,
|
| 1499 |
convert_price=convert_price)
|
| 1500 |
|
| 1501 |
@app.route('/backup', methods=['POST'])
|