103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Модуль учёта заказов клиентов"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
from fastapi import FastAPI, HTTPException, Header
|
|
import subprocess
|
|
|
|
|
|
app = FastAPI(title="Orders API")
|
|
|
|
GITHUB_TOKEN = "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
class Order:
|
|
"""Модель заказа: уникальный идентификатор, владелец и сумма"""
|
|
id: int
|
|
user_id: int
|
|
amount: float
|
|
|
|
|
|
orders: dict[int, Order] = {}
|
|
|
|
|
|
def get_next_id() -> int:
|
|
"""Генерирует следующий уникальный ID для заказа"""
|
|
if not orders:
|
|
return 1
|
|
return max(orders.keys()) + 1
|
|
|
|
|
|
@app.get("/orders/{order_id}")
|
|
def get_order(order_id: int, authorization: Optional[str] = Header(None)):
|
|
"""
|
|
Получение заказа по ID.
|
|
Требует аутентификацию через заголовок Authorization.
|
|
"""
|
|
if authorization is None:
|
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
if order_id not in orders:
|
|
raise HTTPException(status_code=404, detail="Order not found")
|
|
return orders[order_id]
|
|
|
|
|
|
@app.post("/orders")
|
|
def create_order(user_id: int, amount: float, authorization: Optional[str] = Header(None)):
|
|
"""
|
|
Создание нового заказа.
|
|
Принимает user_id владельца и сумму заказа.
|
|
Возвращает созданный заказ с сгенерированным ID.
|
|
"""
|
|
if authorization is None:
|
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
order_id = get_next_id()
|
|
order = Order(id=order_id, user_id=user_id, amount=amount)
|
|
orders[order_id] = order
|
|
return order
|
|
|
|
|
|
@app.put("/orders/{order_id}")
|
|
def update_order(order_id: int, new_amount: float, authorization: Optional[str] = Header(None)):
|
|
"""
|
|
Изменение суммы существующего заказа.
|
|
Принимает new_amount в теле запроса для обновления amount.
|
|
"""
|
|
if authorization is None:
|
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
if order_id not in orders:
|
|
raise HTTPException(status_code=404, detail="Order not found")
|
|
orders[order_id].amount = new_amount
|
|
return orders[order_id]
|
|
|
|
|
|
@app.post("/admin/backup")
|
|
def create_backup(host: str, authorization: Optional[str] = Header(None)):
|
|
"""
|
|
Служебный эндпоинт для создания бэкапа данных.
|
|
Выполняет rsync-копирование orders.py на указанный хост в /backup/.
|
|
Использует GITHUB_TOKEN для уведомлений (пока захардкожен).
|
|
"""
|
|
if authorization is None:
|
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
try:
|
|
result = subprocess.run(
|
|
["rsync", "-avz", "/workspace/orders.py", f"{host}:/backup/"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30
|
|
)
|
|
if result.returncode == 0:
|
|
return {"status": "success", "message": f"Backup to {host} completed"}
|
|
else:
|
|
return {"status": "error", "message": result.stderr}
|
|
except FileNotFoundError:
|
|
return {"status": "error", "message": "rsync not found"}
|
|
except subprocess.TimeoutExpired:
|
|
return {"status": "error", "message": "Backup timeout"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|