from flask import Flask, request, redirect, session, Response, jsonify
import json, os, random, time, uuid
from datetime import datetime
from functools import wraps
app = Flask(__name__)
app.secret_key = "bank_secret_key_2025"
app.config['SESSION_PERMANENT'] = True
app.config['PERMANENT_SESSION_LIFETIME'] = 3600
USERS_FILE = "users.json"
HISTORY_FILE = "history.json"
CARDS_FILE = "cards.json"
SHOP_FILE = "shop.json"
PAYMENTS_FILE = "payments.json" # Новый файл для платежей
# ---------- ИНИЦИАЛИЗАЦИЯ ФАЙЛОВ ----------
def init_files():
"""Инициализация файлов (без удаления существующих)"""
# Создаем файлы если они не существуют
files_to_init = [
(USERS_FILE, {
"admin": {
"password": "admin123",
"balance": 100000,
"deposit": 0,
"credit": 0,
"role": "admin",
"full_name": "Администратор Системы",
"email": "admin@bank.com",
"api_key": None
}
}),
(HISTORY_FILE, []),
(CARDS_FILE, {}),
(SHOP_FILE, {"items": [], "ads": []}),
(PAYMENTS_FILE, []) # Инициализация файла платежей
]
for filename, default_data in files_to_init:
if not os.path.exists(filename):
with open(filename, "w", encoding='utf-8') as f:
json.dump(default_data, f, indent=4, ensure_ascii=False)
# Инициализируем файлы при запуске
init_files()
# ---------- ФУНКЦИИ ДЛЯ РАБОТЫ С ДАННЫМИ ----------
def load_users():
try:
with open(USERS_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
# Убеждаемся, что данные в правильном формате
if not isinstance(data, dict):
print("Warning: users.json is not a dictionary, resetting to default")
data = {
"admin": {
"password": "admin123",
"balance": 100000,
"deposit": 0,
"credit": 0,
"role": "admin",
"full_name": "Администратор Системы",
"email": "admin@bank.com",
"api_key": None
}
}
save_users(data)
return data
# Проверяем, что все значения являются словарями
cleaned_data = {}
for username, user_data in data.items():
if isinstance(user_data, dict):
cleaned_data[username] = user_data
else:
print(f"Warning: User {username} data is not a dict, resetting")
cleaned_data[username] = {
"password": "reset123",
"balance": 1000,
"deposit": 0,
"credit": 0,
"role": "client",
"full_name": "Пользователь",
"email": "user@example.com",
"api_key": None
}
if cleaned_data != data:
save_users(cleaned_data)
return cleaned_data
except Exception as e:
print(f"Error loading users: {e}")
data = {
"admin": {
"password": "admin123",
"balance": 100000,
"deposit": 0,
"credit": 0,
"role": "admin",
"full_name": "Администратор Системы",
"email": "admin@bank.com",
"api_key": None
}
}
save_users(data)
return data
def save_users(data):
with open(USERS_FILE, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
def load_history():
try:
with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except:
return []
def save_history(data):
with open(HISTORY_FILE, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
def load_cards():
try:
with open(CARDS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except:
return {}
def save_cards(data):
with open(CARDS_FILE, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
# ---------- ФУНКЦИИ ДЛЯ ПЛАТЕЖЕЙ ----------
def load_payments():
"""Загрузка платежей"""
try:
with open(PAYMENTS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except:
return []
def save_payments(data):
"""Сохранение платежей"""
with open(PAYMENTS_FILE, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
def create_payment(payer, receiver, amount, description="", external_id=""):
"""Создание платежа"""
payments = load_payments()
payment_id = str(uuid.uuid4())[:12]
payment_data = {
"id": payment_id,
"payer": payer,
"receiver": receiver,
"amount": int(amount),
"description": description,
"external_id": external_id,
"created": int(time.time()),
"status": "pending", # pending, completed, failed, cancelled
"completed_at": None
}
payments.append(payment_data)
save_payments(payments)
return payment_id, payment_data
def process_payment(payment_id, payer_username=None):
"""Обработка платежа"""
payments = load_payments()
users = load_users()
payment = None
for p in payments:
if p["id"] == payment_id:
payment = p
break
if not payment:
return False, "Платеж не найден"
if payment["status"] != "pending":
return False, f"Платеж уже обработан (статус: {payment['status']})"
# Если передан payer_username, проверяем что это тот же плательщик
if payer_username and payment["payer"] != payer_username:
return False, "Неверный плательщик"
payer = payment["payer"]
receiver = payment["receiver"]
amount = payment["amount"]
# Проверяем существование пользователей
if payer not in users:
return False, "Плательщик не найден"
if receiver not in users:
return False, "Получатель не найден"
# Проверяем баланс плательщика
if users[payer]["balance"] < amount:
return False, "Недостаточно средств"
# Выполняем перевод
users[payer]["balance"] -= amount
users[receiver]["balance"] += amount
save_users(users)
# Обновляем статус платежа
for p in payments:
if p["id"] == payment_id:
p["status"] = "completed"
p["completed_at"] = int(time.time())
break
save_payments(payments)
# Добавляем в историю
add_history(payer, "payment_sent", amount, f"Платеж #{payment_id} для {receiver}")
add_history(receiver, "payment_received", amount, f"Платеж #{payment_id} от {payer}")
return True, "Платеж успешно выполнен"
def cancel_payment(payment_id):
"""Отмена платежа"""
payments = load_payments()
for payment in payments:
if payment["id"] == payment_id and payment["status"] == "pending":
payment["status"] = "cancelled"
save_payments(payments)
return True, "Платеж отменен"
return False, "Платеж не найден или уже обработан"
# ---------- ФУНКЦИИ ДЛЯ МАГАЗИНА ----------
def load_shop():
"""Загрузка данных магазина"""
try:
with open(SHOP_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
# Обеспечиваем наличие всех ключей
if "items" not in data:
data["items"] = []
if "ads" not in data:
data["ads"] = []
return data
except:
return {"items": [], "ads": []}
def save_shop(data):
"""Сохранение данных магазина"""
with open(SHOP_FILE, "w", encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
def create_shop_item(seller_username, title, description, price, category="other"):
"""Создание товара в магазине"""
shop_data = load_shop()
item_id = str(uuid.uuid4())[:8]
new_item = {
"id": item_id,
"seller": seller_username,
"title": title,
"description": description,
"price": int(price),
"category": category,
"created": int(time.time()),
"status": "available",
"buyer": None
}
shop_data["items"].append(new_item)
save_shop(shop_data)
# Добавляем в историю
add_history(seller_username, "create_shop_item", 0, f"Товар: {title}")
return item_id
def create_advertisement(author, title, content, contact_info):
"""Создание объявления"""
shop_data = load_shop()
ad_id = str(uuid.uuid4())[:8]
new_ad = {
"id": ad_id,
"author": author,
"title": title,
"content": content,
"contact_info": contact_info,
"created": int(time.time()),
"status": "active"
}
shop_data["ads"].append(new_ad)
save_shop(shop_data)
# Добавляем в историю
add_history(author, "create_advertisement", 0, f"Объявление: {title}")
return ad_id
def buy_item(item_id, buyer_username):
"""Покупка товара"""
shop_data = load_shop()
users = load_users()
# Находим товар
item_to_buy = None
for item in shop_data["items"]:
if item["id"] == item_id and item["status"] == "available":
item_to_buy = item
break
if not item_to_buy:
return False, "Товар не найден или уже продан"
seller = item_to_buy["seller"]
price = item_to_buy["price"]
# Проверяем, есть ли у покупателя достаточно средств
if buyer_username not in users:
return False, "Покупатель не найден"
if users[buyer_username]["balance"] < price:
return False, "Недостаточно средств"
# Проверяем, что покупатель не покупает у себя
if buyer_username == seller:
return False, "Нельзя купить собственный товар"
# Проверяем, существует ли продавец
if seller not in users:
return False, "Продавец не найден"
# Выполняем транзакцию
users[buyer_username]["balance"] -= price
users[seller]["balance"] += price
save_users(users)
# Обновляем статус товара
for item in shop_data["items"]:
if item["id"] == item_id:
item["status"] = "sold"
item["buyer"] = buyer_username
item["sold_date"] = int(time.time())
break
save_shop(shop_data)
# Добавляем в историю
add_history(buyer_username, "buy_item", price, f"Товар: {item_to_buy['title']} от {seller}")
add_history(seller, "sell_item", price, f"Товар: {item_to_buy['title']} покупателю {buyer_username}")
return True, "Покупка успешно завершена"
# ---------- API КЛЮЧИ ----------
def generate_api_key():
"""Генерация API ключа"""
return f"bank_api_{uuid.uuid4().hex[:16]}"
def get_user_by_api_key(api_key):
"""Получение пользователя по API ключу - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
if not api_key:
return None, None
users = load_users()
for username, user_data in users.items():
# Проверяем, что user_data является словарем
if isinstance(user_data, dict) and user_data.get('api_key') == api_key:
return username, user_data
return None, None
# ---------- БАНКОВСКИЕ КАРТЫ ----------
def generate_card_number(user_id, card_type="standard"):
"""Генерация номера банковской карты"""
prefixes = {
"standard": ["5469", "4276", "5375", "4856"],
"gold": ["5469", "5278", "5375"],
"platinum": ["4475", "4876", "4999"]
}
prefix = random.choice(prefixes.get(card_type, prefixes["standard"]))
middle = ''.join([str(random.randint(0, 9)) for _ in range(8)])
last_digits = ''.join([str(random.randint(0, 9)) for _ in range(4)])
card_number = f"{prefix}{middle}{last_digits}"
formatted = ' '.join([card_number[i:i+4] for i in range(0, len(card_number), 4)])
return formatted
def generate_cvv():
"""Генерация CVV кода"""
return str(random.randint(100, 999))
def generate_expiry_date():
"""Генерация срока действия карты"""
from datetime import datetime, timedelta
expiry = datetime.now() + timedelta(days=365*3)
return expiry.strftime("%m/%y")
def get_user_cards(user_id):
"""Получение всех карт пользователя"""
cards = load_cards()
return cards.get(user_id, [])
def create_user_card(user_id, user_data, card_type="standard"):
"""Создание новой карты для пользователя"""
cards = load_cards()
if user_id not in cards:
cards[user_id] = []
# Проверяем, не слишком ли много карт у пользователя
if len(cards[user_id]) >= 5:
return None
card_id = str(uuid.uuid4())[:8]
new_card = {
"id": card_id,
"number": generate_card_number(user_id, card_type),
"holder": user_data.get('full_name', user_id.upper()),
"type": card_type,
"cvv": generate_cvv(),
"expiry": generate_expiry_date(),
"balance": user_data.get('balance', 0),
"currency": "USD",
"created": int(time.time()),
"active": True,
"limit": 10000 if card_type == "standard" else 50000 if card_type == "gold" else 100000,
"color": {
"standard": "#4361ee",
"gold": "#ffd166",
"platinum": "#e5e5e5"
}.get(card_type, "#4361ee")
}
cards[user_id].append(new_card)
save_cards(cards)
# Добавляем в историю
add_history(user_id, f"create_{card_type}_card", 0, f"Card {new_card['number'][-4:]}")
return new_card
# ---------- БАНКОВСКИЕ ОПЕРАЦИИ ----------
def daily_update():
"""Ежедневное обновление депозитов и кредитов"""
users = load_users()
updated = False
for user_id, u in users.items():
if isinstance(u, dict): # Проверяем, что это словарь
if u.get('deposit', 0) > 0:
u['deposit'] = int(u['deposit'] * 1.01)
updated = True
if u.get('credit', 0) > 0:
u['credit'] = int(u['credit'] * 1.05)
updated = True
if updated:
save_users(users)
def add_history(user, action, amount, target=None):
"""Добавление записи в историю"""
hist = load_history()
hist.append({
"time": int(time.time()),
"user": user,
"action": action,
"amount": amount,
"target": target,
"id": str(uuid.uuid4())[:8]
})
save_history(hist)
# ---------- ДЕКОРАТОРЫ ----------
def login_required(f):
"""Декоратор для проверки авторизации"""
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user' not in session:
return redirect('/')
return f(*args, **kwargs)
return decorated_function
def admin_required(f):
"""Декоратор для проверки прав администратора"""
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user' not in session:
return redirect('/')
users = load_users()
user_data = users.get(session['user'])
if not user_data or not isinstance(user_data, dict) or user_data.get('role') != 'admin':
return redirect('/dashboard')
return f(*args, **kwargs)
return decorated_function
# ИСПРАВЛЕННЫЙ ДЕКОРАТОР API
def api_key_required(f):
"""Декоратор для проверки API ключа - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
@wraps(f)
def decorated_function(*args, **kwargs):
api_key = None
# 1. Проверяем заголовок X-API-Key
if 'X-API-Key' in request.headers:
api_key = request.headers.get('X-API-Key')
# 2. Проверяем параметр запроса api_key
if not api_key and request.args.get('api_key'):
api_key = request.args.get('api_key')
# 3. Проверяем JSON тело
if not api_key and request.is_json:
try:
data = request.get_json()
if data and 'api_key' in data:
api_key = data.get('api_key')
except:
pass
# 4. Проверяем форму
if not api_key and request.form.get('api_key'):
api_key = request.form.get('api_key')
if not api_key:
return jsonify({'success': False, 'error': 'API key required'}), 401
# Получаем пользователя по API ключу
username, user_data = get_user_by_api_key(api_key)
if not username:
return jsonify({'success': False, 'error': 'Invalid API key'}), 401
# Сохраняем данные пользователя в объекте request
request.username = username
request.user_data = user_data
return f(*args, **kwargs)
return decorated_function
# ---------- HTML ШАБЛОНЫ ----------
def render_login():
return '''
Банк | Вход в систему
'''
def render_register():
return '''
Банк | Регистрация
'''
def render_card_html(card, width="400px"):
"""Генерация HTML для банковской карты"""
colors = {
"standard": "#4361ee",
"gold": "#ffd166",
"platinum": "#e5e5e5"
}
bg_color = card.get('color', colors.get(card['type'], "#4361ee"))
text_color = "#ffffff" if card['type'] == 'standard' else "#000000"
return f'''
{card['number']}
{card['holder']}
'''
def render_dashboard(user_data, history_data, user_cards, shop_data=None):
"""Генерация HTML личного кабинета"""
# Форматирование времени истории
for h in history_data:
h['formatted_time'] = datetime.fromtimestamp(h['time']).strftime('%d.%m.%Y %H:%M')
# HTML для истории
history_html = ""
for h in history_data[-10:][::-1]:
icon = "fa-history"
color = "text-primary"
if "deposit" in h['action']:
icon = "fa-piggy-bank"
color = "text-info"
elif "credit" in h['action']:
icon = "fa-credit-card"
color = "text-warning"
elif "transfer" in h['action']:
icon = "fa-exchange-alt"
color = "text-primary"
elif "card" in h['action']:
icon = "fa-credit-card"
color = "text-success"
elif "api" in h['action']:
icon = "fa-key"
color = "text-secondary"
elif "shop" in h['action'] or "item" in h['action'] or "advertisement" in h['action']:
icon = "fa-shopping-cart"
color = "text-success"
elif "payment" in h['action']:
icon = "fa-credit-card"
color = "text-success"
history_html += f'''
{h['formatted_time']}
{h['user']}
{h['action']}
{h['amount']:,} $
{h.get('target', '-')}
'''
# HTML для банковских карт
cards_html = ""
if user_cards:
for card in user_cards:
width = "350px" if len(card['number']) < 24 else "400px" if len(card['number']) < 28 else "450px"
cards_html += f'''
Карта {card['type'].upper()}
{render_card_html(card, width)}
CVV: {card['cvv']}
Срок: {card['expiry']}
Баланс: ${card['balance']:,}
Лимит: ${card['limit']:,}
'''
else:
cards_html = '''
У вас еще нет банковских карт. Создайте свою первую карту!
'''
# HTML для API ключа
api_key_html = ""
if user_data.get('api_key'):
api_key_html = f'''
'''
else:
api_key_html = '''
API ключ не создан
'''
# HTML для магазина
shop_tab_content = ""
if shop_data:
# Товары
shop_items_html = ""
available_items = [item for item in shop_data["items"] if item["status"] == "available"]
if available_items:
for item in available_items[-10:][::-1]: # Последние 10 товаров
created_date = datetime.fromtimestamp(item["created"]).strftime('%d.%m.%Y')
shop_items_html += f'''
{item["title"]}
{item["description"]}
Продавец: {item["seller"]}
Категория: {item["category"]}
Дата: {created_date}
${item["price"]:,}
'''
else:
shop_items_html = '''
В магазине пока нет товаров. Будьте первым, кто добавит товар!
'''
# Объявления
ads_html = ""
active_ads = [ad for ad in shop_data["ads"] if ad["status"] == "active"]
if active_ads:
for ad in active_ads[-10:][::-1]: # Последние 10 объявлений
created_date = datetime.fromtimestamp(ad["created"]).strftime('%d.%m.%Y')
ads_html += f'''
{ad["title"]}
{ad["content"]}
Автор: {ad["author"]}
Контакты: {ad["contact_info"]}
Дата: {created_date}
'''
shop_tab_content = f'''
Магазин
Добавить товар
Добавить объявление
Товары в магазине
{shop_items_html}
Объявления
{ads_html}
'''
# HTML для админ-панели
admin_tab = ""
if user_data.get('role') == 'admin':
admin_tab = '''
Админ-панель
'''
return f'''
Банк | Личный кабинет
Вклады
Откройте вклад под 1% ежедневно и получайте пассивный доход.
Кредиты
Получите кредит на любые цели. Ставка 5% ежедневно.
Переводы
Быстрые переводы между клиентами банка без комиссий.
Банковские карты
Выпустите банковскую карту для удобных платежей.
Магазин
Покупайте и продавайте товары, размещайте объявления.
Платежи
Принимайте платежи от клиентов через API или ссылки.
API Доступ
Интегрируйте банковские услуги в ваши приложения через API.
{shop_tab_content}
Время
Пользователь
Операция
Сумма
Получатель
{history_html}
Документация API
Используйте ваш API ключ для доступа к банковским операциям через REST API.
Базовый URL
http://ваш-домен/api/v1/
Аутентификация
Добавьте заголовок с вашим API ключом:
X-API-Key: ваш_api_ключ
Или передайте как параметр:
?api_key=ваш_api_ключ
Доступные методы
Метод
Эндпоинт
Описание
Параметры
GET
/api/v1/balance
Получить информацию о балансе
-
GET
/api/v1/history
Получить историю операций
limit (опционально)
GET
/api/v1/cards
Получить список карт
-
POST
/api/v1/deposit
Открыть вклад
amount (int)
POST
/api/v1/credit
Взять кредит
amount (int)
POST
/api/v1/transfer
Сделать перевод
target (str), amount (int)
POST
/api/v1/cards/create
Создать карту
card_type (standard|gold|platinum)
POST
/api/v1/cards/delete
Удалить карту
card_id (str)
GET
/api/v1/shop/items
Получить список товаров
-
GET
/api/v1/shop/ads
Получить список объявлений
-
POST
/api/v1/payment/create
Создать платеж
receiver, amount, description
POST
/api/v1/payment/process
Выполнить платеж
payment_id
Примеры использования
Python с requests:
import requests
api_key = "ваш_api_ключ"
base_url = "http://ваш-домен/api/v1"
# Получить баланс
headers = {{"X-API-Key": api_key}}
response = requests.get(f"{{base_url}}/balance", headers=headers)
print(response.json())
# Сделать перевод
data = {{"target": "получатель", "amount": 100}}
response = requests.post(f"{{base_url}}/transfer", headers=headers, json=data)
print(response.json())
cURL:
# Получить баланс
curl -H "X-API-Key: ваш_api_ключ" http://ваш-домен/api/v1/balance
# Сделать перевод
curl -X POST -H "X-API-Key: ваш_api_ключ" \\
-H "Content-Type: application/json" \\
-d '{{"target": "получатель", "amount": 100}}' \\
http://ваш-домен/api/v1/transfer
'''
def render_admin_panel(users):
"""Генерация HTML админ-панели - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
users_html = ""
current_user = session.get('user')
valid_users_count = 0
total_balance = 0
total_deposit = 0
total_credit = 0
for username, user in users.items():
# Пропускаем текущего пользователя
if username == current_user:
continue
# Проверяем, что пользователь - словарь (корректные данные)
if not isinstance(user, dict):
continue
# Безопасно получаем данные пользователя
role = user.get('role', 'client')
balance = user.get('balance', 0)
deposit = user.get('deposit', 0)
credit = user.get('credit', 0)
email = user.get('email', 'нет')
# Обновляем статистику
valid_users_count += 1
total_balance += balance
total_deposit += deposit
total_credit += credit
# Определяем цвет бейджа роли
badge_color = "success" if role == 'admin' else "primary" if role == 'manager' else "secondary"
users_html += f'''
'''
return f'''
Админ-панель
{users_html if users_html else '''
Нет других пользователей для управления.
'''}
Статистика системы
Всего пользователей
{valid_users_count + 1}
Общий баланс
${total_balance:,}
Общие вклады
${total_deposit:,}
Общие кредиты
${total_credit:,}
'''
# ---------- СТРАНИЦА ОПЛАТЫ ----------
def render_payment_page():
"""Страница оплаты"""
return '''
Оплата | Банковская система
API для оплаты
Используйте API для интеграции платежей в ваши приложения:
1. Создать платеж:
POST /api/v1/payment/create
Headers: X-API-Key: ваш_ключ
Body: {
"receiver": "username",
"amount": 100,
"description": "Оплата за услугу"
}
2. Получить статус платежа:
GET /api/v1/payment/status/{payment_id}
Headers: X-API-Key: ваш_ключ
3. Пример ссылки для оплаты:
http://ваш-домен/pay/{payment_id}
Как это работает:
Создаете платеж через форму или API
Получаете уникальную ссылку или payment_id
Отправляете ссылку клиенту
Клиент переходит по ссылке и оплачивает
Вы получаете деньги на счет
Последние платежи
ID
Сумма
Получатель
Статус
Дата
'''
def render_pay_page(payment_id):
"""Страница оплаты для клиента"""
payments = load_payments()
payment = None
for p in payments:
if p["id"] == payment_id:
payment = p
break
if not payment:
return '''
Платеж не найден
Платеж не найден
Проверьте правильность ссылки или обратитесь к отправителю.
На главную
'''
if payment["status"] != "pending":
status_message = {
"completed": "Оплачен",
"failed": "Не удался",
"cancelled": "Отменен"
}.get(payment["status"], "Неизвестен")
return f'''
Статус платежа
Платеж {status_message}
ID платежа: {payment_id}
Сумма: ${payment['amount']}
Получатель: {payment['receiver']}
Описание: {payment['description']}
На главную
'''
return f'''
Оплата #{payment_id}
${payment['amount']}
Получатель:
{payment['receiver']}
Описание:
{payment['description'] or 'Нет описания'}
Статус:
Ожидает оплаты
Ваш логин
Пароль
Оплатить ${payment['amount']}
После оплаты средства будут переведены получателю
Безопасная оплата
Все платежи защищены банковской системой. Для оплаты требуется авторизация.
'''
# ---------- ИСПРАВЛЕННЫЕ API МАРШРУТЫ ----------
@app.route('/api/v1/balance', methods=['GET'])
@api_key_required
def api_balance():
"""API: Получить информацию о балансе - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
user_data = request.user_data
return jsonify({
'success': True,
'username': request.username,
'balance': user_data.get('balance', 0),
'deposit': user_data.get('deposit', 0),
'credit': user_data.get('credit', 0),
'total': user_data.get('balance', 0) + user_data.get('deposit', 0) - user_data.get('credit', 0)
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/history', methods=['GET'])
@api_key_required
def api_history():
"""API: Получить историю операций - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
history = load_history()
user_history = [h for h in history if h['user'] == request.username]
limit = request.args.get('limit', type=int, default=50)
if limit > 0 and limit < len(user_history):
user_history = user_history[-limit:]
for h in user_history:
h['time_formatted'] = datetime.fromtimestamp(h['time']).strftime('%Y-%m-%d %H:%M:%S')
return jsonify({
'success': True,
'count': len(user_history),
'history': user_history[::-1]
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/cards', methods=['GET'])
@api_key_required
def api_cards():
"""API: Получить список карт - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
cards = get_user_cards(request.username)
safe_cards = []
for card in cards:
safe_card = card.copy()
if 'number' in safe_card and len(safe_card['number']) > 4:
safe_card['number_masked'] = '**** **** **** ' + safe_card['number'][-4:]
safe_card['cvv'] = '***'
safe_cards.append(safe_card)
return jsonify({
'success': True,
'count': len(safe_cards),
'cards': safe_cards
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/deposit', methods=['POST'])
@api_key_required
def api_deposit():
"""API: Открыть вклад - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
amount = data.get('amount')
if not amount:
return jsonify({'success': False, 'error': 'Amount required'}), 400
amount = int(amount)
if amount <= 0:
return jsonify({'success': False, 'error': 'Amount must be positive'}), 400
users = load_users()
user = users.get(request.username)
if not user or user['balance'] < amount:
return jsonify({'success': False, 'error': 'Insufficient funds'}), 400
user['balance'] -= amount
user['deposit'] += amount
save_users(users)
add_history(request.username, 'api_deposit', amount)
return jsonify({
'success': True,
'message': f'Deposit of ${amount} created successfully',
'new_balance': user['balance'],
'new_deposit': user['deposit']
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/credit', methods=['POST'])
@api_key_required
def api_credit():
"""API: Взять кредит - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
amount = data.get('amount')
if not amount:
return jsonify({'success': False, 'error': 'Amount required'}), 400
amount = int(amount)
if amount <= 0:
return jsonify({'success': False, 'error': 'Amount must be positive'}), 400
users = load_users()
user = users.get(request.username)
if not user:
return jsonify({'success': False, 'error': 'User not found'}), 404
user['balance'] += amount
user['credit'] += amount
save_users(users)
add_history(request.username, 'api_credit', amount)
return jsonify({
'success': True,
'message': f'Credit of ${amount} taken successfully',
'new_balance': user['balance'],
'new_credit': user['credit']
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/transfer', methods=['POST'])
@api_key_required
def api_transfer():
"""API: Сделать перевод - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
target = data.get('target', '').strip()
amount = data.get('amount')
if not target:
return jsonify({'success': False, 'error': 'Target username required'}), 400
if not amount:
return jsonify({'success': False, 'error': 'Amount required'}), 400
amount = int(amount)
if amount <= 0:
return jsonify({'success': False, 'error': 'Amount must be positive'}), 400
users = load_users()
if target not in users:
return jsonify({'success': False, 'error': 'Target user not found'}), 404
if target == request.username:
return jsonify({'success': False, 'error': 'Cannot transfer to yourself'}), 400
sender = users.get(request.username)
if not sender:
return jsonify({'success': False, 'error': 'Sender not found'}), 404
if sender['balance'] < amount:
return jsonify({'success': False, 'error': 'Insufficient funds'}), 400
sender['balance'] -= amount
users[target]['balance'] += amount
save_users(users)
add_history(request.username, 'api_transfer', amount, target)
return jsonify({
'success': True,
'message': f'Transfer of ${amount} to {target} successful',
'new_balance': sender['balance']
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/cards/create', methods=['POST'])
@api_key_required
def api_create_card():
"""API: Создать карту - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
card_type = data.get('card_type', 'standard')
if card_type not in ['standard', 'gold', 'platinum']:
return jsonify({'success': False, 'error': 'Invalid card type'}), 400
users = load_users()
user = users.get(request.username)
if not user:
return jsonify({'success': False, 'error': 'User not found'}), 404
costs = {'standard': 0, 'gold': 50, 'platinum': 100}
cost = costs.get(card_type, 0)
if user['balance'] < cost:
return jsonify({'success': False, 'error': 'Insufficient funds'}), 400
if cost > 0:
user['balance'] -= cost
save_users(users)
card = create_user_card(request.username, user, card_type)
if not card:
if cost > 0:
user['balance'] += cost
save_users(users)
return jsonify({'success': False, 'error': 'Card creation failed. Maximum cards limit reached?'}), 400
safe_card = card.copy()
if 'number' in safe_card and len(safe_card['number']) > 4:
safe_card['number_masked'] = '**** **** **** ' + safe_card['number'][-4:]
safe_card['cvv'] = '***'
return jsonify({
'success': True,
'message': f'{card_type.capitalize()} card created successfully',
'card': safe_card,
'cost': cost,
'new_balance': user['balance']
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/cards/delete', methods=['POST'])
@api_key_required
def api_delete_card():
"""API: Удалить карту - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
card_id = data.get('card_id')
if not card_id:
return jsonify({'success': False, 'error': 'Card ID required'}), 400
cards = load_cards()
user_cards = cards.get(request.username, [])
card_to_delete = None
for card in user_cards:
if card['id'] == card_id:
card_to_delete = card
break
if not card_to_delete:
return jsonify({'success': False, 'error': 'Card not found'}), 404
cards[request.username] = [c for c in user_cards if c['id'] != card_id]
save_cards(cards)
add_history(request.username, 'api_delete_card', 0, f"Card {card_to_delete['number'][-4:]}")
return jsonify({
'success': True,
'message': f"Card ending with {card_to_delete['number'][-4:]} deleted successfully"
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
# ---------- API ДЛЯ ПЛАТЕЖЕЙ ----------
@app.route('/api/v1/payment/create', methods=['POST'])
@api_key_required
def api_payment_create():
"""API: Создать платеж"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
receiver = data.get('receiver')
amount = data.get('amount')
description = data.get('description', '')
external_id = data.get('external_id', '')
if not receiver:
return jsonify({'success': False, 'error': 'Receiver required'}), 400
if not amount:
return jsonify({'success': False, 'error': 'Amount required'}), 400
try:
amount_int = int(amount)
if amount_int <= 0:
return jsonify({'success': False, 'error': 'Amount must be positive'}), 400
except:
return jsonify({'success': False, 'error': 'Invalid amount'}), 400
# Проверяем существование получателя
users = load_users()
if receiver not in users:
return jsonify({'success': False, 'error': 'Receiver not found'}), 404
# Создаем платеж
payment_id, payment_data = create_payment(
payer=request.username,
receiver=receiver,
amount=amount_int,
description=description,
external_id=external_id
)
return jsonify({
'success': True,
'message': 'Payment created successfully',
'payment_id': payment_id,
'payment': payment_data,
'payment_url': f'/pay/{payment_id}'
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/payment/process', methods=['POST'])
@api_key_required
def api_payment_process():
"""API: Выполнить платеж"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
payment_id = data.get('payment_id')
if not payment_id:
return jsonify({'success': False, 'error': 'Payment ID required'}), 400
success, message = process_payment(payment_id, request.username)
return jsonify({
'success': success,
'message': message
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/payment/status/', methods=['GET'])
@api_key_required
def api_payment_status(payment_id):
"""API: Получить статус платежа"""
try:
payments = load_payments()
payment = None
for p in payments:
if p["id"] == payment_id:
payment = p
break
if not payment:
return jsonify({'success': False, 'error': 'Payment not found'}), 404
# Проверяем, имеет ли пользователь доступ к этому платежу
if payment["payer"] != request.username and payment["receiver"] != request.username:
users = load_users()
if users.get(request.username, {}).get('role') != 'admin':
return jsonify({'success': False, 'error': 'Access denied'}), 403
return jsonify({
'success': True,
'payment': payment
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/payment/list', methods=['GET'])
@api_key_required
def api_payment_list():
"""API: Получить список платежей пользователя"""
try:
payments = load_payments()
# Фильтруем платежи по пользователю
user_payments = []
for payment in payments:
if payment["payer"] == request.username or payment["receiver"] == request.username:
user_payments.append(payment)
# Сортируем по дате (новые сверху)
user_payments.sort(key=lambda x: x['created'], reverse=True)
# Ограничиваем количество
limit = min(20, len(user_payments))
user_payments = user_payments[:limit]
return jsonify({
'success': True,
'count': len(user_payments),
'payments': user_payments
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/shop/items', methods=['GET'])
@api_key_required
def api_shop_items():
"""API: Получить список товаров - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
shop_data = load_shop()
available_items = [item for item in shop_data["items"] if item["status"] == "available"]
for item in available_items:
item['created_formatted'] = datetime.fromtimestamp(item['created']).strftime('%Y-%m-%d %H:%M:%S')
return jsonify({
'success': True,
'count': len(available_items),
'items': available_items[::-1]
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/shop/ads', methods=['GET'])
@api_key_required
def api_shop_ads():
"""API: Получить список объявлений - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
shop_data = load_shop()
active_ads = [ad for ad in shop_data["ads"] if ad["status"] == "active"]
for ad in active_ads:
ad['created_formatted'] = datetime.fromtimestamp(ad['created']).strftime('%Y-%m-%d %H:%M:%S')
return jsonify({
'success': True,
'count': len(active_ads),
'ads': active_ads[::-1]
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/system/status', methods=['GET'])
@api_key_required
def api_system_status():
"""API: Получить статус системы - ИСПРАВЛЕННАЯ ВЕРСИЯ"""
try:
users = load_users()
valid_users = [u for u in users.values() if isinstance(u, dict)]
total_users = len(valid_users)
total_balance = sum(u.get('balance', 0) for u in valid_users)
total_deposit = sum(u.get('deposit', 0) for u in valid_users)
total_credit = sum(u.get('credit', 0) for u in valid_users)
return jsonify({
'success': True,
'system_status': 'operational',
'statistics': {
'total_users': total_users,
'total_balance': total_balance,
'total_deposit': total_deposit,
'total_credit': total_credit,
'net_worth': total_balance + total_deposit - total_credit
},
'timestamp': int(time.time())
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
# ДОБАВЛЕННЫЕ API ЭНДПОИНТЫ
@app.route('/api/v1/users', methods=['GET'])
@api_key_required
def api_users():
"""API: Получить список пользователей (только для админов)"""
try:
users = load_users()
if not isinstance(request.user_data, dict) or request.user_data.get('role') != 'admin':
return jsonify({'success': False, 'error': 'Admin access required'}), 403
safe_users = {}
for username, user in users.items():
if isinstance(user, dict):
safe_user = user.copy()
safe_user.pop('password', None)
safe_users[username] = safe_user
return jsonify({
'success': True,
'count': len(safe_users),
'users': safe_users
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/health', methods=['GET'])
def api_health():
"""API: Проверка здоровья системы (не требует API ключа)"""
try:
files = [USERS_FILE, HISTORY_FILE, CARDS_FILE, SHOP_FILE, PAYMENTS_FILE]
file_status = {}
for file in files:
file_status[file] = os.path.exists(file)
return jsonify({
'status': 'healthy',
'timestamp': int(time.time()),
'files': file_status,
'message': 'System is operational'
})
except Exception as e:
return jsonify({'status': 'unhealthy', 'error': str(e)}), 500
@app.route('/api/v1/shop/create_item', methods=['POST'])
@api_key_required
def api_create_shop_item():
"""API: Создать товар в магазине"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
title = data.get('title')
description = data.get('description')
price = data.get('price')
category = data.get('category', 'other')
if not title or not description or not price:
return jsonify({'success': False, 'error': 'Title, description and price required'}), 400
try:
price_int = int(price)
if price_int <= 0:
return jsonify({'success': False, 'error': 'Price must be positive'}), 400
except:
return jsonify({'success': False, 'error': 'Invalid price'}), 400
item_id = create_shop_item(request.username, title, description, price_int, category)
return jsonify({
'success': True,
'message': f'Item "{title}" created successfully',
'item_id': item_id
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/v1/shop/buy_item', methods=['POST'])
@api_key_required
def api_buy_item():
"""API: Купить товар"""
try:
if not request.is_json:
return jsonify({'success': False, 'error': 'JSON data required'}), 400
data = request.get_json()
item_id = data.get('item_id')
if not item_id:
return jsonify({'success': False, 'error': 'Item ID required'}), 400
success, message = buy_item(item_id, request.username)
return jsonify({
'success': success,
'message': message
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
# ---------- МАГАЗИН МАРШРУТЫ ----------
@app.route('/create_shop_item', methods=['POST'])
@login_required
def create_shop_item_route():
"""Создание товара в магазине"""
title = request.form.get('title')
description = request.form.get('description')
price = request.form.get('price')
category = request.form.get('category', 'other')
if not title or not description or not price:
return redirect('/dashboard')
try:
price_int = int(price)
if price_int <= 0:
return redirect('/dashboard')
except:
return redirect('/dashboard')
item_id = create_shop_item(session['user'], title, description, price_int, category)
return redirect('/dashboard')
@app.route('/create_advertisement', methods=['POST'])
@login_required
def create_advertisement_route():
"""Создание объявления"""
title = request.form.get('title')
content = request.form.get('content')
contact_info = request.form.get('contact_info')
if not title or not content or not contact_info:
return redirect('/dashboard')
ad_id = create_advertisement(session['user'], title, content, contact_info)
return redirect('/dashboard')
@app.route('/buy_item/', methods=['POST'])
@login_required
def buy_item_route(item_id):
"""Покупка товара"""
success, message = buy_item(item_id, session['user'])
return redirect('/dashboard')
# ---------- ПЛАТЕЖНЫЕ МАРШРУТЫ ----------
@app.route('/payment_page')
@login_required
def payment_page():
"""Страница управления платежами"""
return render_payment_page()
@app.route('/create_payment_link', methods=['POST'])
@login_required
def create_payment_link():
"""Создание ссылки для оплаты"""
receiver = request.form.get('receiver')
amount = request.form.get('amount')
description = request.form.get('description', '')
if not receiver or not amount:
return redirect('/payment_page')
try:
amount_int = int(amount)
if amount_int <= 0:
return redirect('/payment_page')
except:
return redirect('/payment_page')
payment_id, payment_data = create_payment(
payer=session['user'],
receiver=receiver,
amount=amount_int,
description=description
)
return redirect(f'/payment_page')
@app.route('/pay/', methods=['GET'])
def pay_page(payment_id):
"""Страница оплаты для клиента"""
return render_pay_page(payment_id)
@app.route('/process_payment/', methods=['POST'])
def process_payment_route(payment_id):
"""Обработка платежа (для неавторизованных пользователей)"""
username = request.form.get('username')
password = request.form.get('password')
if not username or not password:
return "Неверные данные", 400
# Проверяем логин и пароль
users = load_users()
user_data = users.get(username)
if not user_data or user_data['password'] != password:
return "Неверный логин или пароль", 401
# Проверяем, что пользователь является плательщиком
payments = load_payments()
payment = None
for p in payments:
if p["id"] == payment_id:
payment = p
break
if not payment:
return "Платеж не найден", 404
if payment["payer"] != username:
return "Вы не являетесь плательщиком по этому платежу", 403
# Выполняем платеж
success, message = process_payment(payment_id, username)
if success:
return redirect(f'/pay/{payment_id}')
else:
return f"Ошибка: {message}", 400
# ---------- ОСНОВНЫЕ МАРШРУТЫ ----------
@app.route('/', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
users = load_users()
username = request.form.get('username')
password = request.form.get('password')
user_data = users.get(username)
if user_data and isinstance(user_data, dict) and user_data['password'] == password:
session['user'] = username
return redirect('/dashboard')
else:
return render_login().replace('',
'Неверный логин или пароль
')
return render_login()
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
users = load_users()
username = request.form.get('username')
if username in users:
return render_register().replace('',
'Пользователь уже существует
')
user_data = {
'password': request.form.get('password'),
'balance': 1000,
'deposit': 0,
'credit': 0,
'role': 'client',
'full_name': f"{request.form.get('first_name')} {request.form.get('last_name')}",
'email': request.form.get('email'),
'api_key': None
}
users[username] = user_data
save_users(users)
session['user'] = username
return redirect('/dashboard')
return render_register()
@app.route('/dashboard')
@login_required
def dashboard():
users = load_users()
history = load_history()
if session['user'] not in users:
session.clear()
return redirect('/')
user_data = users[session['user']]
user_history = [h for h in history if h['user'] == session['user']]
user_cards = get_user_cards(session['user'])
shop_data = load_shop()
return render_dashboard(user_data, user_history[-20:], user_cards, shop_data)
@app.route('/generate_api_key', methods=['POST'])
@login_required
def generate_api_key_route():
users = load_users()
user = users.get(session['user'])
if user and isinstance(user, dict):
user['api_key'] = generate_api_key()
save_users(users)
add_history(session['user'], 'generate_api_key', 0)
return redirect('/dashboard')
@app.route('/deposit', methods=['POST'])
@login_required
def deposit():
users = load_users()
user = users.get(session['user'])
try:
amount = int(request.form.get('amount', 0))
if amount > 0 and user and user['balance'] >= amount:
user['balance'] -= amount
user['deposit'] += amount
save_users(users)
add_history(session['user'], 'deposit', amount)
except:
pass
return redirect('/dashboard')
@app.route('/credit', methods=['POST'])
@login_required
def credit():
users = load_users()
user = users.get(session['user'])
try:
amount = int(request.form.get('amount', 0))
if amount > 0 and user:
user['balance'] += amount
user['credit'] += amount
save_users(users)
add_history(session['user'], 'credit', amount)
except:
pass
return redirect('/dashboard')
@app.route('/transfer', methods=['POST'])
@login_required
def transfer():
users = load_users()
sender = session['user']
try:
target = request.form.get('target')
amount = int(request.form.get('amount', 0))
sender_data = users.get(sender)
target_data = users.get(target)
if (amount > 0 and target_data and target != sender and
sender_data and sender_data['balance'] >= amount):
sender_data['balance'] -= amount
target_data['balance'] += amount
save_users(users)
add_history(sender, 'transfer', amount, target)
except Exception as e:
print(f"Transfer error: {e}")
pass
return redirect('/dashboard')
@app.route('/create_card', methods=['POST'])
@login_required
def create_card():
users = load_users()
user = users.get(session['user'])
card_type = request.form.get('card_type', 'standard')
costs = {
'standard': 0,
'gold': 50,
'platinum': 100
}
cost = costs.get(card_type, 0)
if user and user['balance'] >= cost:
user['balance'] -= cost
save_users(users)
card = create_user_card(session['user'], user, card_type)
if card:
add_history(session['user'], 'create_card', cost, f"{card_type}_{card['number'][-4:]}")
return redirect('/dashboard')
@app.route('/delete_card/', methods=['POST'])
@login_required
def delete_card(card_id):
cards = load_cards()
user_cards = cards.get(session['user'], [])
cards[session['user']] = [c for c in user_cards if c['id'] != card_id]
save_cards(cards)
return redirect('/dashboard')
# ---------- АДМИН МАРШРУТЫ (ИСПРАВЛЕННЫЕ) ----------
@app.route('/admin')
@admin_required
def admin():
users = load_users()
return render_admin_panel(users)
@app.route('/admin/change_role', methods=['POST'])
@admin_required
def admin_change_role():
users = load_users()
username = request.form.get('username')
new_role = request.form.get('role')
if username in users and username != session['user'] and isinstance(users[username], dict):
users[username]['role'] = new_role
save_users(users)
add_history(session['user'], 'change_role', 0, f"{username}->{new_role}")
return redirect('/admin')
@app.route('/admin/add_money', methods=['POST'])
@admin_required
def admin_add_money():
users = load_users()
username = request.form.get('username')
amount = int(request.form.get('amount', 0))
if username in users and amount > 0 and isinstance(users[username], dict):
users[username]['balance'] += amount
save_users(users)
add_history('admin', 'add_money', amount, username)
return redirect('/admin')
@app.route('/logout')
def logout():
session.clear()
return redirect('/')
# ---------- API ДОКУМЕНТАЦИЯ ----------
@app.route('/api/docs')
def api_docs():
"""Страница с документацией API"""
return '''
API Документация
Документация API
Используйте API для интеграции банковских услуг в ваши приложения.
Базовый URL
http://localhost:5000/api/v1/
Аутентификация
Для использования API необходим API ключ. Получите его в личном кабинете.
Передавайте ключ одним из способов:
Заголовок HTTP:
X-API-Key: ваш_api_ключ
Параметр запроса:
?api_key=ваш_api_ключ
JSON тело запроса:
{
"api_key": "ваш_api_ключ",
...
}
Доступные эндпоинты
GET /api/v1/health
Проверка здоровья системы (не требует API ключа)
curl http://localhost:5000/api/v1/health
GET /api/v1/balance
Получить информацию о балансе пользователя
curl -H "X-API-Key: ваш_ключ" http://localhost:5000/api/v1/balance
GET /api/v1/history?limit=50
Получить историю операций (опциональный параметр limit)
POST /api/v1/deposit
Открыть вклад. Требуется JSON: {"amount": 100}
curl -X POST -H "X-API-Key: ваш_ключ" -H "Content-Type: application/json"
-d "{\\"amount\\": 100}" http://localhost:5000/api/v1/deposit
POST /api/v1/credit
Взять кредит. Требуется JSON: {"amount": 100}
POST /api/v1/transfer
Сделать перевод. Требуется JSON: {"target": "username", "amount": 100}
GET /api/v1/cards
Получить список карт пользователя
POST /api/v1/cards/create
Создать карту. Требуется JSON: {"card_type": "standard"}
GET /api/v1/shop/items
Получить список товаров в магазине
POST /api/v1/payment/create
Создать платеж. Требуется JSON: {"receiver": "...", "amount": 100, "description": "..."}
POST /api/v1/payment/process
Выполнить платеж. Требуется JSON: {"payment_id": "..."}
GET /api/v1/payment/status/{payment_id}
Получить статус платежа
GET /api/v1/system/status
Получить статус системы
'''
# ================= ДЕКОРАТОР УЧИТЕЛЯ =================
from functools import wraps
def teacher_required(f):
@wraps(f)
def decorated(*args, **kwargs):
if 'user' not in session:
return redirect("/")
users = load_users()
user = users.get(session['user'])
if not user:
return redirect("/")
if user.get("role") not in ["teacher", "admin"]:
return redirect("/dashboard")
return f(*args, **kwargs)
return decorated
# ============================================================
# ========= ГРАФИК ДИНАМИКИ СРЕДНЕГО БАЛЛА ==================
# ============================================================
@app.route("/student_avg_graph/")
@login_required
@teacher_required
def student_avg_graph(student):
journal = load_journal()
if student not in journal:
return "Нет данных"
subjects = journal[student]
# собираем оценки по порядку добавления
all_grades = []
for subject, grades in subjects.items():
all_grades += grades
averages = []
current = []
for g in all_grades:
current.append(g)
averages.append(sum(current) / len(current))
plt.figure()
plt.plot(range(1, len(averages)+1), averages)
plt.xlabel("Количество оценок")
plt.ylabel("Средний балл")
plt.title(f"Динамика среднего балла {student}")
img = BytesIO()
plt.savefig(img, format="png")
plt.close()
img.seek(0)
graph_url = base64.b64encode(img.getvalue()).decode()
return f"""
📈 Динамика среднего балла: {student}
Назад
"""
# ============================================================
# ========= ФИНАНСОВЫЙ ГРАФИК УЧЕНИКА ========================
# ============================================================
@app.route("/student_finance_graph/")
@login_required
@teacher_required
def student_finance_graph(student):
journal = load_journal()
users = load_users()
if student not in journal:
return "Нет данных"
subjects = journal[student]
# считаем баланс на основе оценок
balance_history = []
balance = 0
for subject, grades in subjects.items():
for g in grades:
balance += calculate_money_for_grade(g)
balance_history.append(balance)
if not balance_history:
return "Нет оценок"
plt.figure()
plt.plot(range(1, len(balance_history)+1), balance_history)
plt.xlabel("Количество оценок")
plt.ylabel("Баланс ($)")
plt.title(f"Финансовая динамика {student}")
img = BytesIO()
plt.savefig(img, format="png")
plt.close()
img.seek(0)
graph_url = base64.b64encode(img.getvalue()).decode()
return f"""
💰 Финансовый график: {student}
Назад
"""
# ============================================================
# ОБНОВЛЕНИЕ ТАБЛИЦЫ В ЖУРНАЛЕ (добавление ссылок)
# ============================================================
@app.route("/journal")
@login_required
@teacher_required
def journal_page():
journal = load_journal()
table = ""
for student, subjects in journal.items():
total = []
for grades in subjects.values():
total += grades
avg = round(sum(total)/len(total),2) if total else 0
table += f"""
{student}
{avg}
📊 Успеваемость
📈 Средний
💰 Финансы
"""
return f"""
Электронный журнал PRO MAX
Назад
Создать класс
Создать
Добавить ученика в класс
Добавить
Поставить оценку
Поставить
Ученики
Ученик
Средний балл
Графики
{table}
🏆 Смотреть рейтинг
"""
if __name__ == '__main__':
import threading
def daily_update_thread():
while True:
time.sleep(86400)
daily_update()
thread = threading.Thread(target=daily_update_thread, daemon=True)
thread.start()
app.run(host='0.0.0.0', port=5000, debug=True)