[docs]asyncdefget_or_create_user(telegram_id:int,username:Optional[str]=None,first_name:Optional[str]=None,last_name:Optional[str]=None,)->User:"""Get user by telegram_id or create new user with default free plan. :param telegram_id: Telegram user ID :param username: Telegram username (optional) :param first_name: User's first name (optional) :param last_name: User's last name (optional) :returns: User instance """asyncwithSessionLocal()assession:result=awaitsession.execute(select(User).where(User.telegram_id==telegram_id))user=result.scalar_one_or_none()ifuserisNone:# Set limits based on plan (FREE by default)daily_limit=5# Free plan defaultconcurrent_limit=1# Free plan defaultuser=User(telegram_id=telegram_id,username=username,first_name=first_name,last_name=last_name,plan=UserPlan.FREE,daily_task_limit=daily_limit,concurrent_task_limit=concurrent_limit,)session.add(user)awaitsession.commit()awaitsession.refresh(user)else:# Update user info if providedupdated=Falseifusernameanduser.username!=username:user.username=usernameupdated=Trueiffirst_nameanduser.first_name!=first_name:user.first_name=first_nameupdated=Trueiflast_nameanduser.last_name!=last_name:user.last_name=last_nameupdated=Trueifupdated:user.updated_at=datetime.now()awaitsession.commit()awaitsession.refresh(user)returnuser
[docs]asyncdefupgrade_user_plan(telegram_id:int,plan:UserPlan,expires_at:Optional[datetime]=None)->bool:"""Upgrade user plan and adjust limits. :param telegram_id: Telegram user ID :param plan: New plan type :param expires_at: Plan expiration date (for premium) :returns: True if upgraded successfully, False if user not found """asyncwithSessionLocal()assession:result=awaitsession.execute(select(User).where(User.telegram_id==telegram_id))user=result.scalar_one_or_none()ifuserisNone:returnFalseuser.plan=planuser.plan_expires_at=expires_at# Update limits based on planifplan==UserPlan.PREMIUM:user.daily_task_limit=100user.concurrent_task_limit=5else:user.daily_task_limit=5user.concurrent_task_limit=1user.updated_at=datetime.now()awaitsession.commit()returnTrue
[docs]asyncdefreset_daily_counters_if_needed(user:User)->User:"""Reset daily counters if a day has passed. :param user: User instance :returns: Updated user instance """now=datetime.now()if(now-user.last_daily_reset).days>=1:asyncwithSessionLocal()assession:# Re-fetch to avoid stale datafresh_user=awaitsession.get(User,user.id)iffresh_userand(now-fresh_user.last_daily_reset).days>=1:fresh_user.daily_tasks_created=0fresh_user.last_daily_reset=nowfresh_user.updated_at=nowawaitsession.commit()awaitsession.refresh(fresh_user)returnfresh_userreturnuser
[docs]asyncdefcheck_user_can_create_task(user:User)->Tuple[bool,str]:"""Check if user can create a new task based on limits. :param user: User instance :returns: Tuple of (can_create: bool, reason: str) """ifuser.is_banned:returnFalse,f"Account banned: {user.ban_reasonor'Violation of terms'}"ifnotuser.is_active:returnFalse,"Account deactivated"# Check plan expiration for premium usersifuser.plan==UserPlan.PREMIUManduser.plan_expires_at:ifdatetime.now()>user.plan_expires_at:returnFalse,"Premium plan expired"# Reset daily counters if neededuser=awaitreset_daily_counters_if_needed(user)# Check daily limitifuser.daily_tasks_created>=user.daily_task_limit:returnFalse,f"Daily task limit reached ({user.daily_task_limit})"# Check concurrent tasksasyncwithSessionLocal()assession:active_count=awaitsession.execute(select(func.count(UserTask.id)).where(and_(UserTask.user_id==user.id,UserTask.status.in_([TaskStatus.QUEUED,TaskStatus.PROCESSING]),)))active_tasks=active_count.scalar_one()or0ifactive_tasks>=user.concurrent_task_limit:return(False,f"Concurrent task limit reached ({user.concurrent_task_limit})",)returnTrue,"OK"