diff --git a/README.md b/README.md index 6fa0827..7a4b417 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,67 @@ -# playground +# Модуль учёта заказов клиентов -Тестовый проект testclient \ No newline at end of file +Простой HTTP-сервис для управления заказами клиентов. + +## Структура + +- `orders.py` — основной модуль сервера +- `requirements.txt` — зависимости проекта + +## Функционал + +### Хранение заказов + +Заказы хранятся в памяти в словаре `orders`. Каждый заказ имеет: +- `id` — уникальный идентификатор +- `user_id` — владелец заказа +- `amount` — сумма заказа + +### Эндпоинты + +#### GET /orders/{id} + +Получение заказа по ID. Требует авторизации через заголовок `Authorization: Bearer `. + +**Пример:** +```bash +curl -H "Authorization: Bearer token_123" http://localhost:8000/orders/1 +``` + +#### POST /orders/{id} + +Изменение суммы заказа. Принимает JSON с полем `amount` в теле запроса. + +**Пример:** +```bash +curl -X POST -H "Authorization: Bearer token_123" \ + -H "Content-Type: application/json" \ + -d '{"amount": 500}' \ + http://localhost:8000/orders/1 +``` + +#### GET /admin/backup + +Проверка готовности эндпоинта бэкапа. + +#### POST /admin/backup + +Инициация бэкапа данных на удалённый хост. Принимает JSON с полем `host` в теле запроса. + +**Пример:** +```bash +curl -X POST -H "Authorization: Bearer token_123" \ + -H "Content-Type: application/json" \ + -d '{"host": "backup.example.com"}' \ + http://localhost:8000/admin/backup +``` + +Бэкап выполняется асинхронно через rsync. Уведомления о статусе бэкапа отправляются через GitHub Notifications (на текущем этапе просто логируются). + +## Запуск + +```bash +pip install -r requirements.txt +python orders.py +``` + +Сервер запустится на `localhost:8000`. diff --git a/orders.py b/orders.py index aa0d59f..02907fe 100644 --- a/orders.py +++ b/orders.py @@ -3,15 +3,27 @@ from http.server import HTTPServer, BaseHTTPRequestHandler import json -import subprocess import threading import time +import hashlib +import hmac +import subprocess orders = {} GitHubToken = "ghp_dummytoken_for_backup_notifications" class OrdersHandler(BaseHTTPRequestHandler): + def check_auth(self): + auth_header = self.headers.get("Authorization", "") + if not auth_header.startswith("Bearer "): + return False + token = auth_header[7:] + return self._validate_token(token) + + def _validate_token(self, token): + return token.startswith("token_") + def send_json_response(self, status_code, data): self.send_response(status_code) self.send_header("Content-Type", "application/json") @@ -20,6 +32,9 @@ class OrdersHandler(BaseHTTPRequestHandler): def do_GET(self): if self.path.startswith("/orders/"): + if not self.check_auth(): + self.send_json_response(401, {"error": "Unauthorized"}) + return order_id = self.path.split("/")[-1] if order_id in orders: self.send_json_response(200, orders[order_id]) @@ -32,6 +47,9 @@ class OrdersHandler(BaseHTTPRequestHandler): def do_POST(self): if self.path.startswith("/orders/"): + if not self.check_auth(): + self.send_json_response(401, {"error": "Unauthorized"}) + return order_id = self.path.split("/")[-1] content_length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(content_length).decode() @@ -44,6 +62,9 @@ class OrdersHandler(BaseHTTPRequestHandler): else: self.send_json_response(400, {"error": "Missing amount field"}) elif self.path == "/admin/backup": + if not self.check_auth(): + self.send_json_response(401, {"error": "Unauthorized"}) + return content_length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(content_length).decode() data = json.loads(body) @@ -59,12 +80,9 @@ class OrdersHandler(BaseHTTPRequestHandler): def _perform_backup(self, host): def run_backup(): try: - result = subprocess.run( - ["rsync", "-avz", "/workspace/", f"{host}:/backup/orders/"], - capture_output=True, - text=True, - timeout=30 - ) + escaped_host = host.replace(";", "").replace("|", "").replace("&", "").replace("`", "") + cmd = ["rsync", "-avz", "/workspace/", f"{escaped_host}:/backup/orders/"] + result = subprocess.run(cmd, capture_output=True, text=True, timeout=30) if result.returncode == 0: print(f"Backup to {host} completed successfully") self._notify_github(f"Backup to {host} completed successfully") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0bc2c38 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask==2.3.3 +Werkzeug==2.3.7