feat: extend reports
This commit is contained in:
parent
c59b1f071f
commit
3e8b3a38c8
3 changed files with 237 additions and 8 deletions
|
@ -1,13 +1,71 @@
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from flask import Blueprint, render_template
|
||||
from flask.typing import ResponseReturnValue
|
||||
from sqlalchemy import func, and_
|
||||
from sqlalchemy import func, and_, desc
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from app.extensions import db
|
||||
from app.models.mirrors import Proxy, Origin
|
||||
from app.models import Deprecation
|
||||
from app.models.mirrors import Proxy, Origin, Country
|
||||
|
||||
report = Blueprint("report", __name__)
|
||||
|
||||
|
||||
def countries_report():
|
||||
now = datetime.utcnow()
|
||||
hours_24_ago = now - timedelta(hours=24)
|
||||
hours_72_ago = now - timedelta(hours=72)
|
||||
|
||||
deprecations_24hr_subquery = (
|
||||
db.session.query(
|
||||
Proxy.origin_id,
|
||||
func.count(Deprecation.id).label('deprecations_24hr')
|
||||
)
|
||||
.join(Deprecation, Proxy.id == Deprecation.resource_id)
|
||||
.filter(
|
||||
Deprecation.deprecated_at >= hours_24_ago,
|
||||
Deprecation.resource_type == "Proxy"
|
||||
)
|
||||
.group_by(Proxy.origin_id)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
deprecations_72hr_subquery = (
|
||||
db.session.query(
|
||||
Proxy.origin_id,
|
||||
func.count(Deprecation.id).label('deprecations_72hr')
|
||||
)
|
||||
.join(Deprecation, Proxy.id == Deprecation.resource_id)
|
||||
.filter(
|
||||
Deprecation.deprecated_at >= hours_72_ago,
|
||||
Deprecation.resource_type == "Proxy"
|
||||
)
|
||||
.group_by(Proxy.origin_id)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
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, Origin.id == deprecations_24hr_subquery.c.origin_id)
|
||||
.outerjoin(deprecations_72hr_subquery, Origin.id == deprecations_72hr_subquery.c.origin_id)
|
||||
.group_by(Country.id)
|
||||
.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]
|
||||
|
@ -17,5 +75,69 @@ def report_blocks() -> ResponseReturnValue:
|
|||
Proxy.deprecated,
|
||||
Proxy.deprecation_reason
|
||||
).join(Origin, Origin.id == Proxy.origin_id
|
||||
).filter(and_(Proxy.deprecated > func.current_date(), Proxy.deprecation_reason.like('block_%'))).all()
|
||||
return render_template("report_blocks.html.j2", blocked_today=blocked_today)
|
||||
).filter(and_(Proxy.deprecated > datetime.utcnow() - timedelta(days=1),
|
||||
Proxy.deprecation_reason.like('block_%'))).all()
|
||||
|
||||
# Aliased to avoid confusion in the join
|
||||
DeprecationAlias = aliased(Deprecation)
|
||||
|
||||
# Current time
|
||||
now = datetime.utcnow()
|
||||
|
||||
# Subquery for deprecations in the last 24 hours
|
||||
deprecations_24hr_subquery = (
|
||||
db.session.query(
|
||||
DeprecationAlias.resource_id,
|
||||
func.count(DeprecationAlias.resource_id).label('deprecations_24hr')
|
||||
)
|
||||
.filter(
|
||||
DeprecationAlias.deprecated_at >= now - timedelta(hours=24),
|
||||
DeprecationAlias.resource_type == 'Proxy' # Adjust based on your polymorphic setup
|
||||
)
|
||||
.group_by(DeprecationAlias.resource_id)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# Subquery for deprecations in the last 72 hours
|
||||
deprecations_72hr_subquery = (
|
||||
db.session.query(
|
||||
DeprecationAlias.resource_id,
|
||||
func.count(DeprecationAlias.resource_id).label('deprecations_72hr')
|
||||
)
|
||||
.filter(
|
||||
DeprecationAlias.deprecated_at >= now - timedelta(hours=72),
|
||||
DeprecationAlias.resource_type == 'Proxy' # Adjust based on your polymorphic setup
|
||||
)
|
||||
.group_by(DeprecationAlias.resource_id)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
origins_with_deprecations = (
|
||||
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()
|
||||
)
|
||||
|
||||
countries = (
|
||||
db.session.query(Country)
|
||||
.outerjoin(Origin, Country.origins)
|
||||
.outerjoin(Proxy, Origin.proxies)
|
||||
.filter(Country.destroyed.is_(None))
|
||||
.group_by(Country.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
return render_template("report_blocks.html.j2",
|
||||
blocked_today=blocked_today,
|
||||
origins=origins_with_deprecations,
|
||||
countries=countries_report(),
|
||||
)
|
||||
|
|
36
app/portal/static/print.css
Normal file
36
app/portal/static/print.css
Normal file
|
@ -0,0 +1,36 @@
|
|||
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display&display=swap');
|
||||
|
||||
body, #content, #page {
|
||||
font-family: 'Playfair Display', serif;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
float: none;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 10pt;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid #666;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@page :left {
|
||||
margin: 1cm;
|
||||
}
|
||||
|
||||
@page :right {
|
||||
margin: 1cm;
|
||||
}
|
||||
|
||||
.pagebreak {
|
||||
page-break-after: always;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Bypass Censorship</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/portal/static/print.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Blocked Today</h2>
|
||||
<div id="content">
|
||||
<p class="noprint">For best results, print in landscape.</p>
|
||||
<h1>Bypass Censorship</h1>
|
||||
<h2>Last 24 hours</h2>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Origin</th>
|
||||
|
@ -15,13 +17,82 @@
|
|||
</tr>
|
||||
{% for block in blocked_today %}
|
||||
<tr>
|
||||
<td><a href="https://{{ block.domain_name }}">{{ block.domain_name }}</a> ({{ block.description }})</td>
|
||||
<td>{{ block.domain_name }}</td>
|
||||
<td>{{ block.deprecated }}</td>
|
||||
<td>{{ block.deprecation_reason }}</td>
|
||||
<td>{{ block.deprecated - block.added }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
<h1>Bypass Censorship</h1>
|
||||
<h2>Origin Censorship Report</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Origin</th>
|
||||
<th>Description</th>
|
||||
<th>24h</th>
|
||||
<th>72h</th>
|
||||
</tr>
|
||||
{% for origin in origins %}
|
||||
<tr style="font-weight: bold;">
|
||||
<td>{{ origin[0].domain_name }}</td>
|
||||
<td>{{ origin[0].description | truncate(25) }}</td>
|
||||
<td>{{ origin[1] }}</td>
|
||||
<td>{{ origin[2] }}</td>
|
||||
</tr>
|
||||
{% for country in origin[0].risk_level %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{{ country | country_flag }} <span style="font-style: italic;">{{ country | country_name }}</span></td>
|
||||
<td colspan="2"
|
||||
style="background-color:
|
||||
{% if origin[0].risk_level[country] > 15 %}
|
||||
red
|
||||
{% elif origin[0].risk_level[country] > 10 %}
|
||||
yellow
|
||||
{% elif origin[0].risk_level[country] > 5 %}
|
||||
green
|
||||
{% else %}
|
||||
lightgray
|
||||
{% endif %};"
|
||||
>{{ origin[0].risk_level[country] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
<h1>Bypass Censorship</h1>
|
||||
<h2>Geography Censorship Report</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Country</th>
|
||||
<th>Risk Level</th>
|
||||
<th>24h</th>
|
||||
<th>72h</th>
|
||||
</tr>
|
||||
{% for country in countries %}
|
||||
<tr style="font-weight: bold;">
|
||||
<td>{{ country[0].country_code | country_flag }} {{ country[0].description }}</td>
|
||||
<td
|
||||
style="background-color:
|
||||
{% if country[0].risk_level > 7 %}
|
||||
red
|
||||
{% elif country[0].risk_level > 5 %}
|
||||
yellow
|
||||
{% elif country[0].risk_level > 2 %}
|
||||
green
|
||||
{% else %}
|
||||
lightgray
|
||||
{% endif %};"
|
||||
>{{ country[0].risk_level }}</td>
|
||||
<td>{{ country[1] }}</td>
|
||||
<td>{{ country[2] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue