# mypy: ignore-errors from datetime import datetime, timedelta from flask import Blueprint, render_template from flask.typing import ResponseReturnValue from sqlalchemy import func, and_, desc from sqlalchemy.orm import aliased from app.extensions import db from app.models import Deprecation from app.models.mirrors import Proxy, Origin, Country report = Blueprint("report", __name__) def generate_subqueries(): DeprecationAlias = aliased(Deprecation) now = datetime.utcnow() 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.utcnow() - 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), )