Files
popa_minecraft_launcher_api/app/services/store_cape.py

315 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import HTTPException, UploadFile
from app.db.database import users_collection
from app.core.config import FILES_URL
from datetime import datetime
import uuid
from pathlib import Path
import os
import shutil
from app.models.cape import CapeStore, CapeStoreUpdate
# Создаем коллекцию для плащей в БД
from app.db.database import db
store_capes_collection = db.store_capes
class StoreCapeService:
async def add_cape(self, name: str, description: str, price: int, cape_file: UploadFile):
"""Добавление нового плаща в магазин"""
# Проверка типа файла
if not cape_file.content_type.startswith('image/'):
raise HTTPException(status_code=400, detail="Файл должен быть изображением")
# Определяем расширение
ext = None
if cape_file.content_type == "image/png":
ext = "png"
elif cape_file.content_type == "image/gif":
ext = "gif"
else:
raise HTTPException(status_code=400, detail="Поддерживаются только PNG и GIF плащи")
# Проверка размера файла (максимум 2MB)
max_size = 2 * 1024 * 1024 # 2MB
contents = await cape_file.read()
if len(contents) > max_size:
raise HTTPException(status_code=400, detail="Файл слишком большой (максимум 2MB)")
# Создаем папку для плащей магазина, если ее нет
cape_dir = Path("app/static/capes_store")
cape_dir.mkdir(parents=True, exist_ok=True)
# Генерируем ID и имя файла
cape_id = str(uuid.uuid4())
cape_filename = f"store_cape_{cape_id}.{ext}"
cape_path = cape_dir / cape_filename
# Сохраняем файл
with open(cape_path, "wb") as f:
f.write(contents)
# Создаем запись в БД
cape_data = {
"id": cape_id,
"name": name,
"description": description,
"price": price,
"file_name": cape_filename,
"created_at": datetime.utcnow()
}
await store_capes_collection.insert_one(cape_data)
return {"id": cape_id, "status": "success"}
async def get_all_capes(self):
"""Получение всех плащей из магазина"""
capes = await store_capes_collection.find().to_list(1000)
result = []
for cape in capes:
result.append({
"id": cape["id"],
"name": cape["name"],
"description": cape["description"],
"price": cape["price"],
"image_url": f"{FILES_URL}/capes_store/{cape['file_name']}"
})
return result
async def get_cape_by_id(self, cape_id: str):
"""Получение плаща по ID"""
cape = await store_capes_collection.find_one({"id": cape_id})
if not cape:
raise HTTPException(status_code=404, detail="Плащ не найден")
return {
"id": cape["id"],
"name": cape["name"],
"description": cape["description"],
"price": cape["price"],
"image_url": f"{FILES_URL}/capes_store/{cape['file_name']}"
}
async def update_cape(self, cape_id: str, update_data: CapeStoreUpdate):
"""Обновление информации о плаще"""
cape = await store_capes_collection.find_one({"id": cape_id})
if not cape:
raise HTTPException(status_code=404, detail="Плащ не найден")
# Готовим данные для обновления
update = {}
if update_data.name:
update["name"] = update_data.name
if update_data.description:
update["description"] = update_data.description
if update_data.price is not None:
update["price"] = update_data.price
if update:
result = await store_capes_collection.update_one(
{"id": cape_id},
{"$set": update}
)
if result.modified_count == 0:
raise HTTPException(status_code=500, detail="Ошибка при обновлении")
return {"status": "success"}
async def delete_cape(self, cape_id: str):
"""Удаление плаща из магазина"""
cape = await store_capes_collection.find_one({"id": cape_id})
if not cape:
raise HTTPException(status_code=404, detail="Плащ не найден")
# Удаляем файл
cape_path = Path(f"app/static/capes_store/{cape['file_name']}")
if cape_path.exists():
try:
cape_path.unlink()
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"}
async def purchase_cape(self, username: str, cape_id: str):
"""Покупка плаща пользователем"""
# Находим пользователя
user = await users_collection.find_one({"username": username})
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Находим плащ
cape = await store_capes_collection.find_one({"id": cape_id})
if not cape:
raise HTTPException(status_code=404, detail="Плащ не найден")
# Проверяем достаточно ли монет
user_coins = user.get("coins", 0)
if user_coins < cape["price"]:
raise HTTPException(status_code=400,
detail=f"Недостаточно монет. Требуется: {cape['price']}, имеется: {user_coins}")
# Копируем плащ из хранилища магазина в персональную папку пользователя
cape_store_path = Path(f"app/static/capes_store/{cape['file_name']}")
# Создаем папку для плащей пользователя
cape_dir = Path("app/static/capes")
cape_dir.mkdir(parents=True, exist_ok=True)
# Генерируем имя файла для персонального плаща
filename_parts = cape['file_name'].split('.')
ext = filename_parts[-1]
cape_filename = f"{username}_{int(datetime.now().timestamp())}.{ext}"
cape_path = cape_dir / cape_filename
# Копируем файл
try:
shutil.copy(cape_store_path, cape_path)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Ошибка при копировании файла: {e}")
# Обновляем данные пользователя
# 1. Списываем монеты
# 2. Устанавливаем новый плащ
# 3. Добавляем плащ в список приобретенных
result = await users_collection.update_one(
{"username": username},
{"$set": {
"coins": user_coins - cape["price"],
"cloak_url": f"{FILES_URL}/capes/{cape_filename}"
},
"$push": {
"purchased_capes": {
"cape_id": cape_id,
"cape_name": cape["name"],
"cape_description": cape["description"],
"file_name": cape_filename,
"purchased_at": datetime.utcnow()
}
}}
)
if result.modified_count == 0:
# Если обновление не удалось, удаляем файл плаща
if os.path.exists(cape_path):
os.remove(cape_path)
raise HTTPException(status_code=500, detail="Ошибка при обновлении данных пользователя")
# Логируем покупку в БД
purchase_data = {
"username": username,
"user_id": user["_id"],
"cape_id": cape_id,
"cape_name": cape["name"],
"price": cape["price"],
"purchase_date": datetime.utcnow()
}
from app.db.database import db
await db.purchases.insert_one(purchase_data)
return {
"status": "success",
"message": f"Плащ '{cape['name']}' успешно приобретен",
"remaining_coins": user_coins - cape["price"]
}
async def get_user_purchased_capes(self, username: str):
"""Получение всех плащей, приобретенных пользователем"""
user = await users_collection.find_one({"username": username})
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
purchased_capes = user.get("purchased_capes", [])
result = []
for cape in purchased_capes:
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')}"
})
return result
async def activate_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": f"{FILES_URL}/capes/{selected_cape.get('file_name')}"}}
)
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')}' деактивирован"
}