103 lines
4.4 KiB
Python
103 lines
4.4 KiB
Python
from datetime import datetime, timedelta, timezone
|
|
|
|
from flask import Blueprint, render_template, request
|
|
from sqlalchemy import desc, or_
|
|
|
|
from app.models.activity import Activity
|
|
from app.models.alarms import Alarm
|
|
from app.models.bridges import Bridge
|
|
from app.models.mirrors import Origin, Proxy
|
|
from app.models.base import Group
|
|
from app.portal.list import NewMirrorListForm
|
|
from app.portal.automation import bp as automation
|
|
from app.portal.bridgeconf import bp as bridgeconf
|
|
from app.portal.bridge import bp as bridge
|
|
from app.portal.eotk import bp as eotk
|
|
from app.portal.group import bp as group
|
|
from app.portal.list import bp as list_
|
|
from app.portal.origin import bp as origin
|
|
from app.portal.onion import bp as onion
|
|
from app.portal.proxy import bp as proxy
|
|
from app.portal.webhook import bp as webhook
|
|
|
|
portal = Blueprint("portal", __name__, template_folder="templates", static_folder="static")
|
|
portal.register_blueprint(automation, url_prefix="/automation")
|
|
portal.register_blueprint(bridgeconf, url_prefix="/bridgeconf")
|
|
portal.register_blueprint(bridge, url_prefix="/bridge")
|
|
portal.register_blueprint(eotk, url_prefix="/eotk")
|
|
portal.register_blueprint(group, url_prefix="/group")
|
|
portal.register_blueprint(list_, url_prefix="/list")
|
|
portal.register_blueprint(origin, url_prefix="/origin")
|
|
portal.register_blueprint(onion, url_prefix="/onion")
|
|
portal.register_blueprint(proxy, url_prefix="/proxy")
|
|
portal.register_blueprint(webhook, url_prefix="/webhook")
|
|
|
|
|
|
@portal.app_template_filter("mirror_expiry")
|
|
def calculate_mirror_expiry(s: datetime) -> str:
|
|
expiry = s + timedelta(days=3)
|
|
countdown = expiry - datetime.utcnow()
|
|
if countdown.days == 0:
|
|
return f"{countdown.seconds // 3600} hours"
|
|
return f"{countdown.days} days"
|
|
|
|
|
|
@portal.app_template_filter("format_datetime")
|
|
def format_datetime(s: datetime) -> str:
|
|
if s is None:
|
|
return "Unknown"
|
|
return s.strftime("%a, %d %b %Y %H:%M:%S")
|
|
|
|
|
|
def total_origins_blocked():
|
|
count = 0
|
|
for o in Origin.query.filter(Origin.destroyed == None).all():
|
|
for a in o.alarms:
|
|
if a.alarm_type.startswith("ooni"):
|
|
if a.alarm_state == AlarmState.WARNING:
|
|
count += 1
|
|
break
|
|
return count
|
|
|
|
@portal.route("/")
|
|
def portal_home():
|
|
groups = Group.query.order_by(Group.group_name).all()
|
|
now = datetime.now(timezone.utc)
|
|
proxies = Proxy.query.filter(Proxy.destroyed == None).all()
|
|
last24 = len(Proxy.query.filter(Proxy.deprecated > (now - timedelta(days=1))).all())
|
|
last72 = len(Proxy.query.filter(Proxy.deprecated > (now - timedelta(days=3))).all())
|
|
lastweek = len(Proxy.query.filter(Proxy.deprecated > (now - timedelta(days=7))).all())
|
|
alarms = {
|
|
s: len(Alarm.query.filter(Alarm.alarm_state == s.upper(), Alarm.last_updated > (now - timedelta(days=1))).all())
|
|
for s in ["critical", "warning", "ok", "unknown"]
|
|
}
|
|
br_last = {
|
|
d: len(Bridge.query.filter(Bridge.deprecated > (now - timedelta(days=d))).all())
|
|
for d in [1, 3, 7]
|
|
}
|
|
activity = Activity.query.filter(Activity.added > (now - timedelta(days=2))).order_by(desc(Activity.added)).all()
|
|
onionified = len([o for o in Origin.query.filter(Origin.destroyed == None).all() if o.onion() != None])
|
|
ooni_blocked = total_origins_blocked()
|
|
total_origins = len(Origin.query.filter(Origin.destroyed == None).all())
|
|
return render_template("home.html.j2", section="home", groups=groups, last24=last24, last72=last72,
|
|
lastweek=lastweek, proxies=proxies, **alarms, activity=activity, total_origins=total_origins,
|
|
onionified=onionified, br_last=br_last, ooni_blocked=ooni_blocked)
|
|
|
|
|
|
@portal.route("/search")
|
|
def search():
|
|
query = request.args.get("query")
|
|
proxies = Proxy.query.filter(or_(Proxy.url.contains(query)), Proxy.destroyed == None).all()
|
|
origins = Origin.query.filter(or_(Origin.description.contains(query), Origin.domain_name.contains(query))).all()
|
|
return render_template("search.html.j2", section="home", proxies=proxies, origins=origins)
|
|
|
|
|
|
@portal.route('/alarms')
|
|
def view_alarms():
|
|
one_day_ago = datetime.now(timezone.utc) - timedelta(days=1)
|
|
alarms = Alarm.query.filter(Alarm.last_updated >= one_day_ago).order_by(
|
|
desc(Alarm.alarm_state), desc(Alarm.state_changed)).all()
|
|
return render_template("list.html.j2",
|
|
section="alarm",
|
|
title="Alarms",
|
|
items=alarms)
|