# mypy: ignore-errors from datetime import datetime, timedelta, timezone from flask import Blueprint, render_template from flask.typing import ResponseReturnValue from sqlalchemy import and_, desc, func from sqlalchemy.orm import aliased from app.extensions import db from app.models import Deprecation from app.models.mirrors import Country, Origin, Proxy report = Blueprint("report", __name__) def generate_subqueries(): DeprecationAlias = aliased(Deprecation) now = datetime.now(tz=timezone.utc) deprecations_24hr_subquery = ( db.session.query( DeprecationAlias.resource_id, func.count(DeprecationAlias.resource_id).label("deprecations_24hr"), ) .filter( DeprecationAlias.reason.like("block_%"), DeprecationAlias.deprecated_at >= now - timedelta(hours=24), DeprecationAlias.resource_type == "Proxy", ) .group_by(DeprecationAlias.resource_id) .subquery() ) deprecations_72hr_subquery = ( db.session.query( DeprecationAlias.resource_id, func.count(DeprecationAlias.resource_id).label("deprecations_72hr"), ) .filter( DeprecationAlias.reason.like("block_%"), DeprecationAlias.deprecated_at >= now - timedelta(hours=72), DeprecationAlias.resource_type == "Proxy", ) .group_by(DeprecationAlias.resource_id) .subquery() ) return deprecations_24hr_subquery, deprecations_72hr_subquery def countries_report(): deprecations_24hr_subquery, deprecations_72hr_subquery = generate_subqueries() return ( db.session.query( Country, func.coalesce( func.sum(deprecations_24hr_subquery.c.deprecations_24hr), 0 ).label("total_deprecations_24hr"), func.coalesce( func.sum(deprecations_72hr_subquery.c.deprecations_72hr), 0 ).label("total_deprecations_72hr"), ) .join(Origin, Country.origins) .join(Proxy, Origin.proxies) .outerjoin( deprecations_24hr_subquery, Proxy.id == deprecations_24hr_subquery.c.resource_id, ) .outerjoin( deprecations_72hr_subquery, Proxy.id == deprecations_72hr_subquery.c.resource_id, ) .group_by(Country.id) .all() ) def origins_report(): deprecations_24hr_subquery, deprecations_72hr_subquery = generate_subqueries() return ( db.session.query( Origin, func.coalesce( func.sum(deprecations_24hr_subquery.c.deprecations_24hr), 0 ).label("total_deprecations_24hr"), func.coalesce( func.sum(deprecations_72hr_subquery.c.deprecations_72hr), 0 ).label("total_deprecations_72hr"), ) .outerjoin(Proxy, Origin.proxies) .outerjoin( deprecations_24hr_subquery, Proxy.id == deprecations_24hr_subquery.c.resource_id, ) .outerjoin( deprecations_72hr_subquery, Proxy.id == deprecations_72hr_subquery.c.resource_id, ) .filter(Origin.destroyed.is_(None)) .group_by(Origin.id) .order_by(desc("total_deprecations_24hr")) .all() ) @report.app_template_filter("country_name") def country_description_filter(country_code): country = Country.query.filter_by(country_code=country_code).first() return country.description if country else None @report.route("/blocks", methods=["GET"]) def report_blocks() -> ResponseReturnValue: blocked_today = ( db.session.query( # type: ignore[no-untyped-call] Origin.domain_name, Origin.description, Proxy.added, Proxy.deprecated, Proxy.deprecation_reason, ) .join(Origin, Origin.id == Proxy.origin_id) .filter( and_( Proxy.deprecated > datetime.now(tz=timezone.utc) - timedelta(days=1), Proxy.deprecation_reason.like("block_%"), ) ) .all() ) return render_template( "report_blocks.html.j2", blocked_today=blocked_today, origins=sorted(origins_report(), key=lambda o: o[1], reverse=True), countries=sorted( countries_report(), key=lambda c: c[0].risk_level, reverse=True ), )