add img to bonus and endpoint toogle activation bonus

This commit is contained in:
2025-12-07 17:26:43 +05:00
parent d4b1c1f5ee
commit a0808d29fa
4 changed files with 79 additions and 2 deletions

View File

@ -45,3 +45,12 @@ async def upgrade_user_bonus(username: str = Body(...), bonus_id: str = Body(...
from app.services.bonus import BonusService from app.services.bonus import BonusService
return await BonusService().upgrade_bonus(username, bonus_id) return await BonusService().upgrade_bonus(username, bonus_id)
@router.post("/toggle-activation")
async def toggle_bonus_activation(username: str = Body(...), bonus_id: str = Body(...)):
"""
Переключить активность бонуса пользователя.
Передаём username и bonus_id, is_active переключается на противоположное значение.
"""
from app.services.bonus import BonusService
return await BonusService().toggle_bonus_activation(username, bonus_id)

View File

@ -12,6 +12,7 @@ class CreateBonusType(BaseModel):
upgrade_price: int upgrade_price: int
duration: int # в секундах duration: int # в секундах
max_level: int = 0 max_level: int = 0
image_url: Optional[str] = None
class PurchaseBonus(BaseModel): class PurchaseBonus(BaseModel):
username: str username: str
@ -33,6 +34,7 @@ class BonusType(BaseModel):
upgrade_price: int # Цена улучшения за уровень upgrade_price: int # Цена улучшения за уровень
duration: int # Длительность в секундах (0 для бесконечных) duration: int # Длительность в секундах (0 для бесконечных)
max_level: int = 0 # 0 = без ограничения уровней max_level: int = 0 # 0 = без ограничения уровней
image_url: Optional[str] = None
class UserTypeBonus(BaseModel): class UserTypeBonus(BaseModel):
id: str id: str
@ -47,6 +49,7 @@ class UserTypeBonus(BaseModel):
expires_at: Optional[datetime] = None expires_at: Optional[datetime] = None
is_active: bool = True is_active: bool = True
is_permanent: bool is_permanent: bool
image_url: Optional[str] = None
class UserBonus(BaseModel): class UserBonus(BaseModel):
id: str id: str

View File

@ -25,7 +25,8 @@ class BonusService:
"price": bonus_data.price, "price": bonus_data.price,
"upgrade_price": bonus_data.upgrade_price, "upgrade_price": bonus_data.upgrade_price,
"duration": bonus_data.duration, "duration": bonus_data.duration,
"max_level": bonus_data.max_level "max_level": bonus_data.max_level,
"image_url": bonus_data.image_url,
} }
# Проверка на дубликат имени # Проверка на дубликат имени
@ -112,7 +113,8 @@ class BonusService:
"level": level, "level": level,
"purchased_at": bonus["purchased_at"].isoformat(), "purchased_at": bonus["purchased_at"].isoformat(),
"can_upgrade": bonus_type["max_level"] == 0 or level < bonus_type["max_level"], "can_upgrade": bonus_type["max_level"] == 0 or level < bonus_type["max_level"],
"upgrade_price": bonus_type["upgrade_price"] "upgrade_price": bonus_type["upgrade_price"],
"image_url": bonus_type.get("image_url"),
} }
# Для временных бонусов добавляем срок # Для временных бонусов добавляем срок
@ -125,6 +127,47 @@ class BonusService:
result.append(bonus_data) result.append(bonus_data)
return {"bonuses": result} return {"bonuses": result}
async def toggle_bonus_activation(self, username: str, bonus_id: str):
"""Переключить активность бонуса у пользователя"""
from app.db.database import users_collection
# Находим пользователя
user = await users_collection.find_one({"username": username})
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Находим бонус пользователя
user_bonus = await user_bonuses_collection.find_one({
"id": bonus_id,
"user_id": str(user["_id"]),
})
if not user_bonus:
raise HTTPException(status_code=404, detail="Бонус не найден или не принадлежит вам")
# Проверяем, не истек ли бонус при попытке включить
if user_bonus.get("expires_at") and user_bonus["expires_at"] < datetime.utcnow():
# На всякий случай зафиксируем в БД, что он не активен
await user_bonuses_collection.update_one(
{"id": bonus_id},
{"$set": {"is_active": False}}
)
raise HTTPException(status_code=400, detail="Срок действия бонуса истёк и он не может быть активирован")
new_status = not user_bonus.get("is_active", False)
await user_bonuses_collection.update_one(
{"id": bonus_id},
{"$set": {"is_active": new_status}}
)
return {
"status": "success",
"message": "Активность бонуса переключена",
"bonus_id": bonus_id,
"is_active": new_status,
}
async def purchase_bonus(self, username: str, bonus_type_id: str): async def purchase_bonus(self, username: str, bonus_type_id: str):
"""Покупка базового бонуса пользователем""" """Покупка базового бонуса пользователем"""

View File

@ -46,6 +46,28 @@ class CoinsService:
# Первое обновление (ограничиваем для безопасности) # Первое обновление (ограничиваем для безопасности)
minutes_to_reward = min(online_time // 60, 5) minutes_to_reward = min(online_time // 60, 5)
# НА ВСЯКИЙ ЕСЛИ ПОПЫ ВСЕ-РАВНО НЕПРАВИЛЬНО НАЧИСЛЯЮТСЯ
# if last_update:
# last_timestamp = last_update["timestamp"]
# seconds_since_update = int((now - last_timestamp).total_seconds())
# # Берём минимум: сколько прошло по часам и сколько игрок реально онлайн
# seconds_for_reward = min(seconds_since_update, online_time)
# # Начисляем только за полные минуты
# minutes_to_reward = seconds_for_reward // 60
# if minutes_to_reward < 1:
# return
# minutes_to_reward = min(minutes_to_reward, MAX_MINUTES_PER_UPDATE)
# else:
# # Первое обновление — считаем только от online_time, с лимитом для безопасности
# minutes_to_reward = min(online_time // 60, 5)
# if minutes_to_reward < 1:
# return
if minutes_to_reward > 0: if minutes_to_reward > 0:
# Обновляем монеты и время # Обновляем монеты и время
new_coins = current_coins + minutes_to_reward new_coins = current_coins + minutes_to_reward