gemification_admin bekötve
This commit is contained in:
@@ -5,6 +5,7 @@ from decimal import Decimal
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, desc
|
||||
from app.models import UserStats, PointsLedger, UserBadge, Badge
|
||||
from app.models.gamification.gamification import PointRule
|
||||
from app.models.identity import User, Wallet
|
||||
from app.models import FinancialLedger
|
||||
from app.services.config_service import config # 2.0 Központi konfigurátor
|
||||
@@ -15,6 +16,9 @@ class GamificationService:
|
||||
"""
|
||||
Gamification Service 2.0 - A 'Jövevény' lelke.
|
||||
Felelős a pontozásért, szintekért, büntetésekért és a jutalom-kreditekért.
|
||||
|
||||
Refaktor: A process_activity() most már a point_rules táblából is olvas,
|
||||
így az admin által definiált pontszabályok elsőbbséget élveznek a master configgal szemben.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
@@ -29,6 +33,22 @@ class GamificationService:
|
||||
service = GamificationService()
|
||||
return await service.process_activity(db, user_id, xp_amount=amount, social_amount=social_points, reason=reason, commit=commit)
|
||||
|
||||
async def _get_point_rule(self, db: AsyncSession, action_key: str) -> dict | None:
|
||||
"""Lekér egy pontszabályt a point_rules táblából action_key alapján.
|
||||
|
||||
Returns:
|
||||
dict with 'points' and 'description' or None if not found/inactive.
|
||||
"""
|
||||
stmt = select(PointRule).where(
|
||||
PointRule.action_key == action_key,
|
||||
PointRule.is_active == True
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
rule = result.scalar_one_or_none()
|
||||
if rule:
|
||||
return {"points": rule.points, "description": rule.description}
|
||||
return None
|
||||
|
||||
async def process_activity(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
@@ -37,13 +57,25 @@ class GamificationService:
|
||||
social_amount: int,
|
||||
reason: str,
|
||||
is_penalty: bool = False,
|
||||
commit: bool = True
|
||||
commit: bool = True,
|
||||
action_key: str | None = None,
|
||||
source_type: str | None = None,
|
||||
source_id: int | None = None,
|
||||
):
|
||||
""" A fő folyamat: Pontozás -> Büntetés szűrés -> Szintszámítás -> Kifizetés.
|
||||
|
||||
Refaktor 2.0:
|
||||
- Ha action_key meg van adva, a point_rules táblából olvassa a pontértékeket.
|
||||
- A master config csak fallback, ha nincs a point_rules-ben.
|
||||
- Támogatja a source_type és source_id mezőket a PointsLedger naplózáshoz.
|
||||
|
||||
Args:
|
||||
commit: If True (default), commits the transaction internally.
|
||||
Set to False when called from within a larger transaction.
|
||||
action_key: Opcionális. Ha meg van adva, a point_rules táblából
|
||||
olvassa a pontértékeket a master config helyett.
|
||||
source_type: Opcionális. A pontok forrásának típusa (pl. 'service_submission').
|
||||
source_id: Opcionális. A pontok forrásának ID-ja.
|
||||
"""
|
||||
try:
|
||||
# 1. ADMIN KONFIGURÁCIÓ BETÖLTÉSE
|
||||
@@ -59,6 +91,19 @@ class GamificationService:
|
||||
"level_rewards": {"credits_per_10_levels": 50}
|
||||
})
|
||||
|
||||
# 1/b. POINT RULES TÁBLA LEKÉRÉSE (ha action_key meg van adva)
|
||||
# A point_rules tábla elsőbbséget élvez a master config-gal szemben!
|
||||
if action_key:
|
||||
rule = await self._get_point_rule(db, action_key)
|
||||
if rule:
|
||||
# A point_rules-ból jövő pontok felülírják a paraméterként kapott értékeket
|
||||
xp_amount = rule["points"]
|
||||
if rule.get("description"):
|
||||
reason = f"{action_key}: {rule['description']}"
|
||||
logger.debug(f"Point rule applied: {action_key} -> {xp_amount} XP")
|
||||
else:
|
||||
logger.debug(f"No active point rule found for action_key='{action_key}', using fallback values.")
|
||||
|
||||
# 2. FELHASZNÁLÓ ÉS STATISZTIKA ELLENŐRZÉSE
|
||||
stats_stmt = select(UserStats).where(UserStats.user_id == user_id)
|
||||
stats = (await db.execute(stats_stmt)).scalar_one_or_none()
|
||||
@@ -70,7 +115,7 @@ class GamificationService:
|
||||
|
||||
# 3. BÜNTETŐ LOGIKA (Ha negatív esemény történik)
|
||||
if is_penalty:
|
||||
return await self._apply_penalty(db, stats, xp_amount, reason, cfg)
|
||||
return await self._apply_penalty(db, stats, xp_amount, reason, cfg, source_type=source_type, source_id=source_id)
|
||||
|
||||
# 4. SZORZÓK ALKALMAZÁSA (Büntetés alatt állók 'bírsága')
|
||||
multiplier = await self._calculate_multiplier(stats, cfg)
|
||||
@@ -107,8 +152,15 @@ class GamificationService:
|
||||
stats.social_points %= rate # A maradék pont megmarad
|
||||
await self._add_earned_credits(db, user_id, credits_to_add, "SOCIAL_ACTIVITY_CONVERSION")
|
||||
|
||||
# 7. NAPLÓZÁS
|
||||
db.add(PointsLedger(user_id=user_id, points=final_xp, reason=reason))
|
||||
# 7. NAPLÓZÁS (kibővítve xp, source_type, source_id mezőkkel)
|
||||
db.add(PointsLedger(
|
||||
user_id=user_id,
|
||||
points=final_xp,
|
||||
xp=final_xp,
|
||||
reason=reason,
|
||||
source_type=source_type,
|
||||
source_id=source_id,
|
||||
))
|
||||
|
||||
# Only commit if caller wants us to manage the transaction
|
||||
if commit:
|
||||
@@ -124,8 +176,12 @@ class GamificationService:
|
||||
|
||||
# --- PRIVÁT SEGÉDFÜGGVÉNYEK ---
|
||||
|
||||
async def _apply_penalty(self, db: AsyncSession, stats: UserStats, amount: int, reason: str, cfg: dict):
|
||||
"""Büntetőpontok hozzáadása és korlátozási szintek emelése."""
|
||||
async def _apply_penalty(self, db: AsyncSession, stats: UserStats, amount: int, reason: str, cfg: dict,
|
||||
source_type: str | None = None, source_id: int | None = None):
|
||||
"""Büntetőpontok hozzáadása és korlátozási szintek emelése.
|
||||
|
||||
Refaktor: Most már támogatja a source_type és source_id mezőket a naplózáshoz.
|
||||
"""
|
||||
stats.penalty_points += amount
|
||||
th = cfg["penalty_logic"]["thresholds"]
|
||||
|
||||
@@ -133,7 +189,14 @@ class GamificationService:
|
||||
elif stats.penalty_points >= th["level_2"]: stats.restriction_level = 2
|
||||
elif stats.penalty_points >= th["level_1"]: stats.restriction_level = 1
|
||||
|
||||
db.add(PointsLedger(user_id=stats.user_id, points=0, penalty_change=amount, reason=f"🔴 PENALTY: {reason}"))
|
||||
db.add(PointsLedger(
|
||||
user_id=stats.user_id,
|
||||
points=0,
|
||||
penalty_change=amount,
|
||||
reason=f"🔴 PENALTY: {reason}",
|
||||
source_type=source_type,
|
||||
source_id=source_id,
|
||||
))
|
||||
await db.commit()
|
||||
return stats
|
||||
|
||||
@@ -165,4 +228,4 @@ class GamificationService:
|
||||
details={"reason": reason}
|
||||
))
|
||||
|
||||
gamification_service = GamificationService()
|
||||
gamification_service = GamificationService()
|
||||
|
||||
Reference in New Issue
Block a user