lots of typing fixes

This commit is contained in:
Iain Learmonth 2022-05-16 11:44:03 +01:00
parent 51f580a304
commit 3665c34961
43 changed files with 260 additions and 178 deletions

View file

@ -1,6 +1,8 @@
from datetime import datetime, timedelta, timezone
from typing import Optional
from flask import Blueprint, render_template, request
from flask.typing import ResponseReturnValue
from sqlalchemy import desc, or_
from app.models.activity import Activity
@ -43,13 +45,13 @@ def calculate_mirror_expiry(s: datetime) -> str:
@portal.app_template_filter("format_datetime")
def format_datetime(s: datetime) -> str:
def format_datetime(s: Optional[datetime]) -> str:
if s is None:
return "Unknown"
return s.strftime("%a, %d %b %Y %H:%M:%S")
def total_origins_blocked():
def total_origins_blocked() -> int:
count = 0
for o in Origin.query.filter(Origin.destroyed == None).all():
for a in o.alarms:
@ -59,8 +61,9 @@ def total_origins_blocked():
break
return count
@portal.route("/")
def portal_home():
def portal_home() -> ResponseReturnValue:
groups = Group.query.order_by(Group.group_name).all()
now = datetime.now(timezone.utc)
proxies = Proxy.query.filter(Proxy.destroyed == None).all()
@ -86,7 +89,7 @@ def portal_home():
@portal.route("/search")
def search():
def search() -> ResponseReturnValue:
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()
@ -94,7 +97,7 @@ def search():
@portal.route('/alarms')
def view_alarms():
def view_alarms() -> ResponseReturnValue:
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()

View file

@ -1,6 +1,8 @@
from datetime import datetime
from typing import Optional
from flask import render_template, flash, Response, Blueprint
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import SubmitField, BooleanField
@ -12,13 +14,13 @@ from app.portal.util import view_lifecycle, response_404
bp = Blueprint("automation", __name__)
class EditAutomationForm(FlaskForm):
class EditAutomationForm(FlaskForm): # type: ignore
enabled = BooleanField('Enabled')
submit = SubmitField('Save Changes')
@bp.route("/list")
def automation_list():
def automation_list() -> ResponseReturnValue:
automations = Automation.query.filter(
Automation.destroyed == None).order_by(Automation.description).all()
return render_template("list.html.j2",
@ -29,8 +31,8 @@ def automation_list():
@bp.route('/edit/<automation_id>', methods=['GET', 'POST'])
def automation_edit(automation_id):
automation = Automation.query.filter(Automation.id == automation_id).first()
def automation_edit(automation_id: int) -> ResponseReturnValue:
automation: Optional[Automation] = Automation.query.filter(Automation.id == automation_id).first()
if automation is None:
return Response(render_template("error.html.j2",
section="automation",
@ -52,7 +54,7 @@ def automation_edit(automation_id):
@bp.route("/kick/<automation_id>", methods=['GET', 'POST'])
def automation_kick(automation_id: int):
def automation_kick(automation_id: int) -> ResponseReturnValue:
automation = Automation.query.filter(
Automation.id == automation_id,
Automation.destroyed == None).first()

View file

@ -1,4 +1,7 @@
from typing import Optional
from flask import render_template, Response, flash, redirect, url_for, Blueprint
from flask.typing import ResponseReturnValue
from app.extensions import db
from app.models.bridges import Bridge
@ -8,7 +11,7 @@ bp = Blueprint("bridge", __name__)
@bp.route("/list")
def bridge_list():
def bridge_list() -> ResponseReturnValue:
bridges = Bridge.query.filter(Bridge.destroyed == None).all()
return render_template("list.html.j2",
section="bridge",
@ -18,8 +21,8 @@ def bridge_list():
@bp.route("/block/<bridge_id>", methods=['GET', 'POST'])
def bridge_blocked(bridge_id):
bridge: Bridge = Bridge.query.filter(Bridge.id == bridge_id, Bridge.destroyed == None).first()
def bridge_blocked(bridge_id: int) -> ResponseReturnValue:
bridge: Optional[Bridge] = Bridge.query.filter(Bridge.id == bridge_id, Bridge.destroyed == None).first()
if bridge is None:
return Response(render_template("error.html.j2",
header="404 Proxy Not Found",

View file

@ -1,6 +1,8 @@
from datetime import datetime
from typing import Optional, List
from flask import render_template, url_for, flash, redirect, Response, Blueprint
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import SelectField, StringField, IntegerField, SubmitField
@ -14,7 +16,7 @@ from app.portal.util import response_404, view_lifecycle
bp = Blueprint("bridgeconf", __name__)
class NewBridgeConfForm(FlaskForm):
class NewBridgeConfForm(FlaskForm): # type: ignore
provider = SelectField('Provider', validators=[DataRequired()])
method = SelectField('Distribution Method', validators=[DataRequired()])
description = StringField('Description')
@ -23,15 +25,15 @@ class NewBridgeConfForm(FlaskForm):
submit = SubmitField('Save Changes')
class EditBridgeConfForm(FlaskForm):
class EditBridgeConfForm(FlaskForm): # type: ignore
description = StringField('Description')
number = IntegerField('Number', validators=[NumberRange(1, message="One or more bridges must be created")])
submit = SubmitField('Save Changes')
@bp.route("/list")
def bridgeconf_list():
bridgeconfs = BridgeConf.query.filter(BridgeConf.destroyed == None).all()
def bridgeconf_list() -> ResponseReturnValue:
bridgeconfs: List[BridgeConf] = BridgeConf.query.filter(BridgeConf.destroyed == None).all()
return render_template("list.html.j2",
section="bridgeconf",
title="Tor Bridge Configurations",
@ -42,7 +44,7 @@ def bridgeconf_list():
@bp.route("/new", methods=['GET', 'POST'])
@bp.route("/new/<group_id>", methods=['GET', 'POST'])
def bridgeconf_new(group_id=None):
def bridgeconf_new(group_id: Optional[int] = None) -> ResponseReturnValue:
form = NewBridgeConfForm()
form.group.choices = [(x.id, x.group_name) for x in Group.query.all()]
form.provider.choices = [
@ -82,7 +84,7 @@ def bridgeconf_new(group_id=None):
@bp.route('/edit/<bridgeconf_id>', methods=['GET', 'POST'])
def bridgeconf_edit(bridgeconf_id):
def bridgeconf_edit(bridgeconf_id: int) -> ResponseReturnValue:
bridgeconf = BridgeConf.query.filter(BridgeConf.id == bridgeconf_id).first()
if bridgeconf is None:
return Response(render_template("error.html.j2",
@ -107,7 +109,7 @@ def bridgeconf_edit(bridgeconf_id):
@bp.route("/destroy/<bridgeconf_id>", methods=['GET', 'POST'])
def bridgeconf_destroy(bridgeconf_id: int):
def bridgeconf_destroy(bridgeconf_id: int) -> ResponseReturnValue:
bridgeconf = BridgeConf.query.filter(BridgeConf.id == bridgeconf_id, BridgeConf.destroyed == None).first()
if bridgeconf is None:
return response_404("The requested bridge configuration could not be found.")

View file

@ -1,4 +1,5 @@
from flask import render_template, Blueprint, Response
from flask.typing import ResponseReturnValue
from sqlalchemy import desc
from app.models.base import Group
@ -8,7 +9,7 @@ bp = Blueprint("eotk", __name__)
@bp.route("/list")
def eotk_list():
def eotk_list() -> ResponseReturnValue:
instances = Eotk.query.filter(Eotk.destroyed == None).order_by(desc(Eotk.added)).all()
return render_template("list.html.j2",
section="eotk",
@ -18,7 +19,7 @@ def eotk_list():
@bp.route("/conf/<group_id>")
def eotk_conf(group_id: int):
def eotk_conf(group_id: int) -> ResponseReturnValue:
from app import app
group = Group.query.filter(Group.id == group_id).first()
return Response(render_template("sites.conf.j2",

View file

@ -2,12 +2,12 @@ from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField
class EditMirrorForm(FlaskForm):
class EditMirrorForm(FlaskForm): # type: ignore
origin = SelectField('Origin')
url = StringField('URL')
submit = SubmitField('Save Changes')
class EditProxyForm(FlaskForm):
class EditProxyForm(FlaskForm): # type: ignore
origin = SelectField('Origin')
submit = SubmitField('Save Changes')

View file

@ -1,6 +1,7 @@
from datetime import datetime
from flask import render_template, url_for, flash, redirect, Response, Blueprint
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import StringField, BooleanField, SubmitField
@ -12,21 +13,21 @@ from app.models.base import Group
bp = Blueprint("group", __name__)
class NewGroupForm(FlaskForm):
class NewGroupForm(FlaskForm): # type: ignore
group_name = StringField("Short Name", validators=[DataRequired()])
description = StringField("Description", validators=[DataRequired()])
eotk = BooleanField("Deploy EOTK instances?")
submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"})
class EditGroupForm(FlaskForm):
class EditGroupForm(FlaskForm): # type: ignore
description = StringField('Description', validators=[DataRequired()])
eotk = BooleanField("Deploy EOTK instances?")
submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"})
@bp.route("/list")
def group_list():
def group_list() -> ResponseReturnValue:
groups = Group.query.order_by(Group.group_name).all()
return render_template("list.html.j2",
section="group",
@ -37,7 +38,7 @@ def group_list():
@bp.route("/new", methods=['GET', 'POST'])
def group_new():
def group_new() -> ResponseReturnValue:
form = NewGroupForm()
if form.validate_on_submit():
group = Group()
@ -59,7 +60,7 @@ def group_new():
@bp.route('/edit/<group_id>', methods=['GET', 'POST'])
def group_edit(group_id):
def group_edit(group_id: int) -> ResponseReturnValue:
group = Group.query.filter(Group.id == group_id).first()
if group is None:
return Response(render_template("error.html.j2",

View file

@ -1,7 +1,9 @@
import json
from datetime import datetime
from typing import Optional
from flask import render_template, url_for, flash, redirect, Blueprint, Response
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import SelectField, StringField, SubmitField
@ -28,7 +30,7 @@ def list_format_name(s: str) -> str:
@bp.route('/list')
def list_list():
def list_list() -> ResponseReturnValue:
lists = MirrorList.query.filter(MirrorList.destroyed == None).all()
return render_template("list.html.j2",
section="list",
@ -48,7 +50,7 @@ def list_list():
@bp.route('/preview/<format_>')
def list_preview(format_: str):
def list_preview(format_: str) -> ResponseReturnValue:
if format_ == "bca":
return Response(json.dumps(mirror_mapping()), content_type="application/json")
if format_ == "bc2":
@ -59,7 +61,7 @@ def list_preview(format_: str):
@bp.route("/destroy/<list_id>", methods=['GET', 'POST'])
def list_destroy(list_id: int):
def list_destroy(list_id: int) -> ResponseReturnValue:
list_ = MirrorList.query.filter(MirrorList.id == list_id, MirrorList.destroyed == None).first()
if list_ is None:
return response_404("The requested bridge configuration could not be found.")
@ -76,10 +78,10 @@ def list_destroy(list_id: int):
@bp.route("/new", methods=['GET', 'POST'])
@bp.route("/new/<group_id>", methods=['GET', 'POST'])
def list_new(group_id=None):
def list_new(group_id: Optional[int] = None) -> ResponseReturnValue:
form = NewMirrorListForm()
form.provider.choices = [(k, v) for k, v in MirrorList.providers_supported]
form.format.choices = [(k, v) for k, v in MirrorList.formats_supported]
form.provider.choices = [(k, v) for k, v in MirrorList.providers_supported] # type: ignore
form.format.choices = [(k, v) for k, v in MirrorList.formats_supported] # type: ignore
if form.validate_on_submit():
list_ = MirrorList()
list_.provider = form.provider.data
@ -105,7 +107,7 @@ def list_new(group_id=None):
return render_template("new.html.j2", section="list", form=form)
class NewMirrorListForm(FlaskForm):
class NewMirrorListForm(FlaskForm): # type: ignore
provider = SelectField('Provider', validators=[DataRequired()])
format = SelectField('Distribution Method', validators=[DataRequired()])
description = StringField('Description', validators=[DataRequired()])

View file

@ -1,6 +1,8 @@
from datetime import datetime
from typing import Optional
from flask import flash, redirect, url_for, render_template, Response, Blueprint
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import StringField, SelectField, SubmitField
@ -14,7 +16,7 @@ from app.portal.util import response_404, view_lifecycle
bp = Blueprint("onion", __name__)
class NewOnionForm(FlaskForm):
class NewOnionForm(FlaskForm): # type: ignore
domain_name = StringField('Domain Name', validators=[DataRequired()])
onion_name = StringField('Onion Name', validators=[DataRequired(), Length(min=56, max=56)],
description="Onion service hostname, excluding the .onion suffix")
@ -23,7 +25,7 @@ class NewOnionForm(FlaskForm):
submit = SubmitField('Save Changes')
class EditOnionForm(FlaskForm):
class EditOnionForm(FlaskForm): # type: ignore
description = StringField('Description', validators=[DataRequired()])
group = SelectField('Group', validators=[DataRequired()])
submit = SubmitField('Save Changes')
@ -31,7 +33,7 @@ class EditOnionForm(FlaskForm):
@bp.route("/new", methods=['GET', 'POST'])
@bp.route("/new/<group_id>", methods=['GET', 'POST'])
def onion_new(group_id=None):
def onion_new(group_id: Optional[int] = None) -> ResponseReturnValue:
form = NewOnionForm()
form.group.choices = [(x.id, x.group_name) for x in Group.query.all()]
if form.validate_on_submit():
@ -57,8 +59,8 @@ def onion_new(group_id=None):
@bp.route('/edit/<onion_id>', methods=['GET', 'POST'])
def onion_edit(onion_id):
onion = Onion.query.filter(Onion.id == onion_id).first()
def onion_edit(onion_id: int) -> ResponseReturnValue:
onion: Optional[Onion] = Onion.query.filter(Onion.id == onion_id).first()
if onion is None:
return Response(render_template("error.html.j2",
section="onion",
@ -83,7 +85,7 @@ def onion_edit(onion_id):
@bp.route("/list")
def onion_list():
def onion_list() -> ResponseReturnValue:
onions = Onion.query.order_by(Onion.domain_name).all()
return render_template("list.html.j2",
section="onion",
@ -94,7 +96,7 @@ def onion_list():
@bp.route("/destroy/<onion_id>", methods=['GET', 'POST'])
def onion_destroy(onion_id: int):
def onion_destroy(onion_id: int) -> ResponseReturnValue:
onion = Onion.query.filter(Onion.id == onion_id, Onion.destroyed == None).first()
if onion is None:
return response_404("The requested onion service could not be found.")

View file

@ -1,6 +1,8 @@
from datetime import datetime
from typing import Optional, List
from flask import flash, redirect, url_for, render_template, Response, Blueprint
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import StringField, SelectField, SubmitField, BooleanField
@ -14,7 +16,7 @@ from app.portal.util import response_404, view_lifecycle
bp = Blueprint("origin", __name__)
class NewOriginForm(FlaskForm):
class NewOriginForm(FlaskForm): # type: ignore
domain_name = StringField('Domain Name', validators=[DataRequired()])
description = StringField('Description', validators=[DataRequired()])
group = SelectField('Group', validators=[DataRequired()])
@ -22,7 +24,7 @@ class NewOriginForm(FlaskForm):
submit = SubmitField('Save Changes')
class EditOriginForm(FlaskForm):
class EditOriginForm(FlaskForm): # type: ignore
description = StringField('Description', validators=[DataRequired()])
group = SelectField('Group', validators=[DataRequired()])
auto_rotate = BooleanField("Enable auto-rotation?")
@ -31,7 +33,7 @@ class EditOriginForm(FlaskForm):
@bp.route("/new", methods=['GET', 'POST'])
@bp.route("/new/<group_id>", methods=['GET', 'POST'])
def origin_new(group_id=None):
def origin_new(group_id: Optional[int] = None) -> ResponseReturnValue:
form = NewOriginForm()
form.group.choices = [(x.id, x.group_name) for x in Group.query.all()]
if form.validate_on_submit():
@ -57,8 +59,8 @@ def origin_new(group_id=None):
@bp.route('/edit/<origin_id>', methods=['GET', 'POST'])
def origin_edit(origin_id):
origin = Origin.query.filter(Origin.id == origin_id).first()
def origin_edit(origin_id: int) -> ResponseReturnValue:
origin: Optional[Origin] = Origin.query.filter(Origin.id == origin_id).first()
if origin is None:
return Response(render_template("error.html.j2",
section="origin",
@ -85,8 +87,8 @@ def origin_edit(origin_id):
@bp.route("/list")
def origin_list():
origins = Origin.query.order_by(Origin.domain_name).all()
def origin_list() -> ResponseReturnValue:
origins: List[Origin] = Origin.query.order_by(Origin.domain_name).all()
return render_template("list.html.j2",
section="origin",
title="Web Origins",
@ -101,7 +103,7 @@ def origin_list():
@bp.route("/onion")
def origin_onion():
def origin_onion() -> ResponseReturnValue:
origins = Origin.query.order_by(Origin.domain_name).all()
return render_template("list.html.j2",
section="origin",
@ -112,7 +114,7 @@ def origin_onion():
@bp.route("/destroy/<origin_id>", methods=['GET', 'POST'])
def origin_destroy(origin_id: int):
def origin_destroy(origin_id: int) -> ResponseReturnValue:
origin = Origin.query.filter(Origin.id == origin_id, Origin.destroyed == None).first()
if origin is None:
return response_404("The requested origin could not be found.")

View file

@ -1,4 +1,5 @@
from flask import render_template, Response, flash, redirect, url_for, Blueprint
from flask.typing import ResponseReturnValue
from sqlalchemy import desc
from app.extensions import db
@ -9,7 +10,7 @@ bp = Blueprint("proxy", __name__)
@bp.route("/list")
def proxy_list():
def proxy_list() -> ResponseReturnValue:
proxies = Proxy.query.filter(Proxy.destroyed == None).order_by(desc(Proxy.added)).all()
return render_template("list.html.j2",
section="proxy",
@ -19,7 +20,7 @@ def proxy_list():
@bp.route("/block/<proxy_id>", methods=['GET', 'POST'])
def proxy_block(proxy_id):
def proxy_block(proxy_id: int) -> ResponseReturnValue:
proxy = Proxy.query.filter(Proxy.id == proxy_id, Proxy.destroyed == None).first()
if proxy is None:
return Response(render_template("error.html.j2",

View file

@ -1,4 +1,5 @@
from flask import Response, render_template, flash, redirect, url_for
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from wtforms import SubmitField
@ -7,7 +8,7 @@ from app.models import AbstractResource
from app.models.activity import Activity
def response_404(message: str):
def response_404(message: str) -> ResponseReturnValue:
return Response(render_template("error.html.j2",
header="404 Not Found",
message=message))
@ -20,7 +21,7 @@ def view_lifecycle(*,
success_view: str,
section: str,
resource: AbstractResource,
action: str):
action: str) -> ResponseReturnValue:
form = LifecycleForm()
if action == "destroy":
form.submit.render_kw = {"class": "btn btn-danger"}
@ -54,5 +55,5 @@ def view_lifecycle(*,
form=form)
class LifecycleForm(FlaskForm):
class LifecycleForm(FlaskForm): # type: ignore
submit = SubmitField('Confirm')

View file

@ -1,6 +1,8 @@
from datetime import datetime
from typing import Optional
from flask import Blueprint, flash, Response, render_template, redirect, url_for
from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import StringField, SelectField, SubmitField
@ -22,7 +24,7 @@ def webhook_format_name(s: str) -> str:
return "Unknown"
class NewWebhookForm(FlaskForm):
class NewWebhookForm(FlaskForm): # type: ignore
description = StringField('Description', validators=[DataRequired()])
format = SelectField('Format', choices=[
("telegram", "Telegram"),
@ -33,7 +35,7 @@ class NewWebhookForm(FlaskForm):
@bp.route("/new", methods=['GET', 'POST'])
def webhook_new():
def webhook_new() -> ResponseReturnValue:
form = NewWebhookForm()
if form.validate_on_submit():
webhook = Webhook(
@ -53,7 +55,7 @@ def webhook_new():
@bp.route('/edit/<webhook_id>', methods=['GET', 'POST'])
def webhook_edit(webhook_id):
def webhook_edit(webhook_id: int) -> ResponseReturnValue:
webhook = Webhook.query.filter(Webhook.id == webhook_id).first()
if webhook is None:
return Response(render_template("error.html.j2",
@ -81,7 +83,7 @@ def webhook_edit(webhook_id):
@bp.route("/list")
def webhook_list():
def webhook_list() -> ResponseReturnValue:
webhooks = Webhook.query.all()
return render_template("list.html.j2",
section="webhook",
@ -92,8 +94,8 @@ def webhook_list():
@bp.route("/destroy/<webhook_id>", methods=['GET', 'POST'])
def webhook_destroy(webhook_id: int):
webhook = Webhook.query.filter(Webhook.id == webhook_id, Webhook.destroyed == None).first()
def webhook_destroy(webhook_id: int) -> ResponseReturnValue:
webhook: Optional[Webhook] = Webhook.query.filter(Webhook.id == webhook_id, Webhook.destroyed == None).first()
if webhook is None:
return response_404("The requested webhook could not be found.")
return view_lifecycle(