πŸ” Overview

generate_statistics_task generates a daily report for each user and sends it via Telegram.

The report includes separate categories:

  • blocked domains by Google Safe Browsing
  • blocked domains by DNS
  • replaced domains by rotation
  • unblocked domains
  • manually switched domains

⏱ Schedule (Celery Beat)

Configured in config/settings.py:

  • generate_statistics_task β€” daily at 08:30

πŸ“ Task Definition

@celery.task
def generate_statistics_task():
    yesterday = (timezone.now() - timezone.timedelta(days=1)).date()
 
    for user in UserModel.objects.all():
        TelegramSender.send_daily_statistics_message(
            report_date=yesterday.strftime("%Y-%m-%d"),
            domain_blocked_by_google=list(
                Link.objects.filter(
                    owner=user,
                    blocked_at__date=yesterday,
                    reason__in=BlockReasons.google_safe_browsing(),
                ).exclude(status=LinkStatuses.ACTIVE)
                 .values_list("domain", flat=True)
                 .distinct()
            ),
            domain_blocked_by_dns=list(
                Link.objects.filter(
                    owner=user,
                    blocked_at__date=yesterday,
                    reason=BlockReasons.DNS_NOT_RESOLVABLE,
                ).exclude(status=LinkStatuses.ACTIVE)
                 .values_list("domain", flat=True)
                 .distinct()
            ),
            domain_blocked_by_rotation=list(
                Link.objects.filter(
                    owner=user,
                    blocked_at__date=yesterday,
                    reason=BlockReasons.ROTATION,
                ).exclude(status=LinkStatuses.ACTIVE)
                 .values_list("domain", flat=True)
                 .distinct()
            ),
            unblocked_domains=list(
                Link.objects.filter(owner=user, unblocked_at__date=yesterday)
                .exclude(status=LinkStatuses.BLOCKED)
                .values_list("domain", flat=True)
                .distinct()
            ),
            manually_switched_domains=list(
                Link.objects.filter(
                    owner=user,
                    blocked_at__date=yesterday,
                    reason=BlockReasons.BLOCKED_BY_USER,
                ).exclude(status=LinkStatuses.ACTIVE)
                 .values_list("domain", flat=True)
                 .distinct()
            ),
            user=user,
        )

βš™οΈ Task Behavior & Flow

  1. Calculates the date for β€œyesterday”.
  2. For each user:
    • queries Link records by date + reason
    • extracts distinct domains
    • sends a single Telegram message (see Telegram Messages)