gitscope
← marzneshin / v0.3.0-alpha / app/tasks/review_users.py
https://dev.kronoz.win/r/marzneshin.git
app/tasks/review_users.py · Python
Blame Raw
  1import asyncio
  2import logging
  3from datetime import datetime
  4from typing import TYPE_CHECKING
  5
  6from sqlalchemy.orm import Session
  7
  8from app import marznode
  9from app.db import (
 10    GetDB,
 11    get_notification_reminder,
 12    get_users,
 13    start_user_expire,
 14    update_user_status,
 15)
 16from app.models.user import ReminderType, UserResponse, UserStatus
 17from app.utils import report
 18from app.utils.helpers import calculate_expiration_days, calculate_usage_percent
 19from config import NOTIFY_DAYS_LEFT, NOTIFY_REACHED_USAGE_PERCENT, WEBHOOK_ADDRESS
 20
 21if TYPE_CHECKING:
 22    from app.db.models import User
 23
 24
 25logger = logging.getLogger(__name__)
 26
 27
 28def add_notification_reminders(
 29    db: Session, user: "User", now: datetime = datetime.utcnow()
 30) -> None:
 31    if user.data_limit:
 32        usage_percent = calculate_usage_percent(user.used_traffic, user.data_limit)
 33        if (usage_percent >= NOTIFY_REACHED_USAGE_PERCENT) and (
 34            not get_notification_reminder(db, user.id, ReminderType.data_usage)
 35        ):
 36            report.data_usage_percent_reached(
 37                db,
 38                usage_percent,
 39                UserResponse.model_validate(user),
 40                user.id,
 41                user.expire,
 42            )
 43
 44    if user.expire and ((now - user.created_at).days >= NOTIFY_DAYS_LEFT):
 45        expire_days = calculate_expiration_days(user.expire)
 46        if (expire_days <= NOTIFY_DAYS_LEFT) and (
 47            not get_notification_reminder(db, user.id, ReminderType.expiration_date)
 48        ):
 49            report.expire_days_reached(
 50                db, expire_days, UserResponse.model_validate(user), user.id, user.expire
 51            )
 52
 53
 54async def review_users():
 55    now = datetime.utcnow()
 56    with GetDB() as db:
 57        for user in get_users(db, status=UserStatus.active):
 58
 59            limited = user.data_limit and user.used_traffic >= user.data_limit
 60            expired = user.expire and user.expire <= now
 61            if limited:
 62                status = UserStatus.limited
 63            elif expired:
 64                status = UserStatus.expired
 65            else:
 66                if WEBHOOK_ADDRESS:
 67                    add_notification_reminders(db, user, now)
 68                continue
 69
 70            await marznode.operations.remove_user(user)
 71            update_user_status(db, user, status)
 72
 73            asyncio.create_task(
 74                report.status_change(
 75                    user.username, user.status, UserResponse.model_validate(user)
 76                )
 77            )
 78
 79            logger.info(f'User "{user.username}" status changed to {status}')
 80
 81        for user in get_users(db, status=UserStatus.on_hold):
 82
 83            if user.edit_at:
 84                base_time = user.edit_at
 85            else:
 86                base_time = user.created_at
 87
 88            # Check if the user is online After or at 'base_time'
 89            if user.online_at and base_time <= user.online_at:
 90                status = UserStatus.active
 91
 92            elif user.on_hold_timeout and (user.on_hold_timeout <= now):
 93                # If the user didn't connect within the timeout period, change status to "Active"
 94                status = UserStatus.active
 95
 96            else:
 97                continue
 98
 99            update_user_status(db, user, status)
100            start_user_expire(db, user)
101            asyncio.create_task(
102                report.status_change(
103                    user.username, user.status, UserResponse.model_validate(user)
104                )
105            )
106            logger.info(f"on hold user `{user.username}` has been activated")