diff --git a/app/api/server.py b/app/api/server.py index b50229b..ac7dfc9 100644 --- a/app/api/server.py +++ b/app/api/server.py @@ -2,6 +2,8 @@ from fastapi import APIRouter from app.services.server.command import CommandService from app.services.server.event import EventService from app.models.server.command import ServerCommand +from datetime import datetime +import uuid router = APIRouter( prefix="/api/server", @@ -10,12 +12,29 @@ router = APIRouter( @router.post("/events") async def receive_server_event(event_data: dict): + # Обновляем активность сервера + server_ip = event_data.get("server_ip") + if server_ip: + await update_server_activity(server_ip) return await EventService().process_event(event_data) @router.post("/commands") async def add_server_command(command_data: ServerCommand): + # Обновляем last_activity для сервера + await CommandService()._update_server_activity(command_data.server_ip) return await CommandService().add_command(command_data) @router.get("/commands") async def get_server_commands(server_ip: str): return await CommandService().get_commands(server_ip) + +async def update_server_activity(server_ip): + """Обновляет время последней активности сервера""" + from app.db.database import db + game_servers_collection = db.game_servers + + await game_servers_collection.update_one( + {"ip": server_ip}, + {"$set": {"last_activity": datetime.utcnow()}}, + upsert=False + ) diff --git a/app/api/store.py b/app/api/store.py index b3b73d0..da7b094 100644 --- a/app/api/store.py +++ b/app/api/store.py @@ -54,3 +54,8 @@ async def get_user_purchased_capes(username: str): async def activate_purchased_cape(username: str, cape_id: str): """Активация приобретенного плаща""" return await store_cape_service.activate_purchased_cape(username, cape_id) + +@router.post("/user/{username}/capes/deactivate/{cape_id}") +async def deactivate_purchased_cape(username: str, cape_id: str): + """Деактивация приобретенного плаща""" + return await store_cape_service.deactivate_purchased_cape(username, cape_id) diff --git a/app/services/server/command.py b/app/services/server/command.py index 0692c9d..26b69b4 100644 --- a/app/services/server/command.py +++ b/app/services/server/command.py @@ -20,6 +20,10 @@ class CommandService: } print(f"[{datetime.now()}] Добавлена команда: {command_data.command} " f"для сервера {command_data.server_ip}") + + # Обновляем last_activity для сервера + await self._update_server_activity(command_data.server_ip) + return {"status": "success", "command_id": command_id} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @@ -47,3 +51,14 @@ class CommandService: return {"status": "success", "commands": commands} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) + + async def _update_server_activity(self, server_ip): + """Обновляет время последней активности для сервера""" + from app.db.database import db + game_servers_collection = db.game_servers + + await game_servers_collection.update_one( + {"ip": server_ip}, + {"$set": {"last_activity": datetime.utcnow()}}, + upsert=False # Не создаем новый сервер, только обновляем существующий + ) diff --git a/app/services/server/event.py b/app/services/server/event.py index 275c0fd..e326cae 100644 --- a/app/services/server/event.py +++ b/app/services/server/event.py @@ -101,11 +101,18 @@ class EventService: "port": 25565, # Стандартный порт Minecraft "description": f"Minecraft server {server_ip}", "max_players": 100, - "registered_at": datetime.utcnow() + "registered_at": datetime.utcnow(), + "last_activity": datetime.utcnow() # Добавляем поле last_activity } await game_servers_collection.insert_one(server_data) print(f"[{datetime.utcnow()}] Зарегистрирован новый сервер: {server_ip}") + else: + # Обновляем активность существующего сервера + await game_servers_collection.update_one( + {"ip": server_ip}, + {"$set": {"last_activity": datetime.utcnow()}} + ) return existing_server or await game_servers_collection.find_one({"ip": server_ip}) @@ -114,11 +121,18 @@ class EventService: from app.db.database import db online_players_collection = db.online_players + game_servers_collection = db.game_servers # Получаем ID сервера server = await self._register_server(server_ip, {}) server_id = server["id"] + # Обновляем время активности сервера + await game_servers_collection.update_one( + {"id": server_id}, + {"$set": {"last_activity": datetime.utcnow()}} + ) + # Помечаем всех игроков как оффлайн на этом сервере await online_players_collection.update_many( {"server_id": server_id}, diff --git a/app/services/server/prank.py b/app/services/server/prank.py index e5bccb3..b33a7ec 100644 --- a/app/services/server/prank.py +++ b/app/services/server/prank.py @@ -1,7 +1,7 @@ from fastapi import HTTPException from app.db.database import db, users_collection from app.models.server.prank import PrankCommand, PrankCommandUpdate -from datetime import datetime +from datetime import datetime, timedelta import uuid from app.services.server.command import CommandService @@ -124,6 +124,29 @@ class PrankService: async def get_all_servers(self): """Получение списка всех доступных серверов""" + # Проверяем и удаляем неактивные серверы (более 5 минут без данных) + current_time = datetime.utcnow() + inactive_threshold = 5 * 60 # 5 минут в секундах + + # Находим серверы, которые не отправляли данные больше 5 минут + # Учитываем, что у некоторых серверов может не быть поля last_activity + inactive_servers = await game_servers_collection.find({ + "last_activity": { + "$exists": True, + "$lt": current_time - timedelta(seconds=inactive_threshold) + } + }).to_list(100) + + # Удаляем неактивные серверы + if inactive_servers: + server_ids = [server["id"] for server in inactive_servers] + await game_servers_collection.delete_many({"id": {"$in": server_ids}}) + + # Опционально: логирование удаленных серверов + for server in inactive_servers: + print(f"Удален неактивный сервер: {server['name']} (ID: {server['id']})") + + # Получаем актуальный список серверов servers = await game_servers_collection.find().to_list(100) # Если нет зарегистрированных серверов, вернем пустой список @@ -144,7 +167,8 @@ class PrankService: "port": server.get("port"), "description": server.get("description", ""), "online_players": online_count, - "max_players": server.get("max_players", 0) + "max_players": server.get("max_players", 0), + "last_activity": server.get("last_activity") }) return result diff --git a/app/services/store_cape.py b/app/services/store_cape.py index e028503..b4e7b74 100644 --- a/app/services/store_cape.py +++ b/app/services/store_cape.py @@ -131,10 +131,23 @@ class StoreCapeService: except Exception as e: print(f"Ошибка при удалении файла: {e}") - # Удаляем из БД + # Удаляем из БД плащей магазина result = await store_capes_collection.delete_one({"id": cape_id}) if result.deleted_count == 0: raise HTTPException(status_code=500, detail="Ошибка при удалении из БД") + + # Удаляем из БД купленных плащей + purchases_collection = db.purchases + purchases = await purchases_collection.find_one({"cape_id": cape_id}) + if purchases: + await purchases_collection.delete_one({"cape_id": cape_id}) + + # Удаляем плащ из массива purchased_capes всех пользователей + users_collection = db.users + await users_collection.update_many( + {"purchased_capes.cape_id": cape_id}, + {"$pull": {"purchased_capes": {"cape_id": cape_id}}} + ) return {"status": "success"} @@ -189,6 +202,7 @@ class StoreCapeService: "purchased_capes": { "cape_id": cape_id, "cape_name": cape["name"], + "cape_description": cape["description"], "file_name": cape_filename, "purchased_at": datetime.utcnow() } @@ -233,6 +247,7 @@ class StoreCapeService: result.append({ "cape_id": cape.get("cape_id"), "cape_name": cape.get("cape_name"), + "cape_description": cape.get("cape_description"), "image_url": f"{FILES_URL}/capes/{cape.get('file_name')}", "purchased_at": cape.get("purchased_at"), "is_active": user.get("cloak_url") == f"{FILES_URL}/capes/{cape.get('file_name')}" @@ -267,4 +282,33 @@ class StoreCapeService: return { "status": "success", "message": f"Плащ '{selected_cape.get('cape_name')}' активирован" - } + } + + async def deactivate_purchased_cape(self, username: str, cape_id: str): + """Деактивация приобретенного плаща""" + user = await users_collection.find_one({"username": username}) + if not user: + raise HTTPException(status_code=404, detail="Пользователь не найден") + + # Проверяем, что плащ был приобретен + purchased_capes = user.get("purchased_capes", []) + selected_cape = None + + for cape in purchased_capes: + if cape.get("cape_id") == cape_id: + selected_cape = cape + break + + if not selected_cape: + raise HTTPException(status_code=404, detail="Плащ не найден среди приобретенных") + + # Устанавливаем выбранный плащ + await users_collection.update_one( + {"username": username}, + {"$set": {"cloak_url": None}} + ) + + return { + "status": "success", + "message": f"Плащ '{selected_cape.get('cape_name')}' деактивирован" + } diff --git a/app/static/capes_store/store_cape_d46bff22-fe66-4985-8fe9-9326be7573bd.png b/app/static/capes_store/store_cape_d46bff22-fe66-4985-8fe9-9326be7573bd.png new file mode 100644 index 0000000..83c97d5 Binary files /dev/null and b/app/static/capes_store/store_cape_d46bff22-fe66-4985-8fe9-9326be7573bd.png differ