Files
popa_minecraft_launcher_api/app/services/dailyreward.py
2025-12-13 00:51:35 +05:00

94 lines
3.6 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 datetime import datetime, timedelta
from app.db.database import users_collection, db
coins_sessions_collection = db.coins_sessions
class DailyRewardService:
async def claim_daily(self, username: str) -> dict:
now = datetime.utcnow()
today = now.date()
user = await users_collection.find_one({"username": username})
if not user:
return {"claimed": False, "reason": "user_not_found"}
last_claim_at = user.get("daily_last_claim_at")
last_claim_day = last_claim_at.date() if last_claim_at else None
# уже получал сегодня
if last_claim_day == today:
return {"claimed": False, "reason": "already_claimed_today", "streak": user.get("daily_streak", 0)}
# вычисляем новый стрик
yesterday = today - timedelta(days=1)
prev_streak = int(user.get("daily_streak", 0) or 0)
if last_claim_day == yesterday:
new_streak = prev_streak + 1
else:
new_streak = 1
# формула награды (пример)
base = 10
bonus = min(new_streak, 7) * 2 # кап на 7 дней
reward = base + bonus
# КЛЮЧЕВО: атомарная защита от двойного клика/параллельных запросов
# обновляем только если last_claim_day != today
result = await users_collection.update_one(
{
"username": username,
"$or": [
{"daily_last_claim_at": {"$exists": False}},
{"daily_last_claim_at": {"$lt": datetime(today.year, today.month, today.day)}},
],
},
{
"$inc": {"coins": reward},
"$set": {"daily_last_claim_at": now, "daily_streak": new_streak},
},
)
if result.modified_count == 0:
# кто-то уже успел получить сегодня (гонка)
user2 = await users_collection.find_one({"username": username})
return {"claimed": False, "reason": "already_claimed_today", "streak": user2.get("daily_streak", 0)}
# лог в coins_sessions (у тебя уже так сделано для coins_update) :contentReference[oaicite:4]{index=4}
await coins_sessions_collection.insert_one({
"player_name": username,
"update_type": "daily_login",
"timestamp": now,
"coins_added": reward,
"streak": new_streak,
})
return {"claimed": True, "coins_added": reward, "streak": new_streak}
async def get_status(self, username: str) -> dict:
now = datetime.utcnow()
today = now.date()
user = await users_collection.find_one({"username": username})
if not user:
return {"ok": False, "reason": "user_not_found"}
last_claim_at = user.get("daily_last_claim_at")
last_claim_day = last_claim_at.date() if last_claim_at else None
start_of_today = datetime(today.year, today.month, today.day)
start_of_tomorrow = start_of_today + timedelta(days=1)
can_claim = (last_claim_day != today)
seconds_to_next = 0 if can_claim else int((start_of_tomorrow - now).total_seconds())
if seconds_to_next < 0:
seconds_to_next = 0
return {
"ok": True,
"can_claim": can_claim,
"seconds_to_next": seconds_to_next,
"next_claim_at": start_of_tomorrow.isoformat() + "Z",
"streak": int(user.get("daily_streak", 0) or 0),
}