diff --git a/app/portal/__init__.py b/app/portal/__init__.py index 2a801b8..4026d90 100644 --- a/app/portal/__init__.py +++ b/app/portal/__init__.py @@ -4,19 +4,20 @@ from flask import Blueprint, render_template, Response, flash, redirect, url_for from sqlalchemy import exc, desc, or_ from app.extensions import db -from app.models import AbstractResource from app.models.bridges import BridgeConf, Bridge from app.models.alarms import Alarm from app import Origin, Proxy from app.models.base import Group, MirrorList -from app.portal.forms import NewOriginForm, EditOriginForm, LifecycleForm, \ - NewBridgeConfForm, EditBridgeConfForm, NewMirrorListForm +from app.portal.forms import LifecycleForm, NewBridgeConfForm, EditBridgeConfForm, NewMirrorListForm from app.portal.group import bp as group +from app.portal.origin import bp as origin from app.portal.proxy import bp as proxy +from app.portal.util import response_404, view_lifecycle portal = Blueprint("portal", __name__, template_folder="templates", static_folder="static") portal.register_blueprint(group, url_prefix="/group") +portal.register_blueprint(origin, url_prefix="/origin") portal.register_blueprint(proxy, url_prefix="/proxy") @@ -48,72 +49,6 @@ def portal_home(): lastweek=lastweek, proxies=proxies) -@portal.route("/origin/new", methods=['GET', 'POST']) -@portal.route("/origin/new/", methods=['GET', 'POST']) -def new_origin(group_id=None): - form = NewOriginForm() - form.group.choices = [(x.id, x.group_name) for x in Group.query.all()] - if form.validate_on_submit(): - origin = Origin() - origin.group_id = form.group.data - origin.domain_name = form.domain_name.data - origin.description = form.description.data - origin.auto_rotation = form.auto_rotate.data - origin.created = datetime.utcnow() - origin.updated = datetime.utcnow() - try: - db.session.add(origin) - db.session.commit() - flash(f"Created new origin {origin.domain_name}.", "success") - return redirect(url_for("portal.edit_origin", origin_id=origin.id)) - except exc.SQLAlchemyError as e: - print(e) - flash("Failed to create new origin.", "danger") - return redirect(url_for("portal.view_origins")) - if group_id: - form.group.data = group_id - return render_template("new.html.j2", section="origin", form=form) - - -@portal.route('/origin/edit/', methods=['GET', 'POST']) -def edit_origin(origin_id): - origin = Origin.query.filter(Origin.id == origin_id).first() - if origin is None: - return Response(render_template("error.html.j2", - section="origin", - header="404 Origin Not Found", - message="The requested origin could not be found."), - status=404) - form = EditOriginForm(group=origin.group_id, - description=origin.description, - auto_rotate=origin.auto_rotation) - form.group.choices = [(x.id, x.group_name) for x in Group.query.all()] - if form.validate_on_submit(): - origin.group_id = form.group.data - origin.description = form.description.data - origin.auto_rotation = form.auto_rotate.data - origin.updated = datetime.utcnow() - try: - db.session.commit() - flash("Saved changes to group.", "success") - except exc.SQLAlchemyError: - flash("An error occurred saving the changes to the group.", "danger") - return render_template("origin.html.j2", - section="origin", - origin=origin, form=form) - - -@portal.route("/origins") -def view_origins(): - origins = Origin.query.order_by(Origin.domain_name).all() - return render_template("list.html.j2", - section="origin", - title="Origins", - item="origin", - new_link=url_for("portal.new_origin"), - items=origins) - - @portal.route("/search") def search(): query = request.args.get("query") @@ -294,39 +229,6 @@ def blocked_bridge(bridge_id): form=form) -def response_404(message: str): - return Response(render_template("error.html.j2", - header="404 Not Found", - message=message)) - - -def view_lifecycle(*, - header: str, - message: str, - success_message: str, - success_view: str, - section: str, - resource: AbstractResource, - action: str): - form = LifecycleForm() - if form.validate_on_submit(): - if action == "destroy": - resource.destroy() - elif action == "deprecate": - resource.deprecate(reason="manual") - else: - flash("Unknown action") - return redirect(url_for("portal.portal_home")) - db.session.commit() - flash(success_message, "success") - return redirect(url_for(success_view)) - return render_template("lifecycle.html.j2", - header=header, - message=message, - section=section, - form=form) - - @portal.route("/bridgeconf/destroy/", methods=['GET', 'POST']) def destroy_bridgeconf(bridgeconf_id: int): bridgeconf = BridgeConf.query.filter(BridgeConf.id == bridgeconf_id, BridgeConf.destroyed == None).first() @@ -343,17 +245,3 @@ def destroy_bridgeconf(bridgeconf_id: int): ) -@portal.route("/origin/destroy/", methods=['GET', 'POST']) -def destroy_origin(origin_id: int): - 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.") - return view_lifecycle( - header=f"Destroy origin {origin.domain_name}", - message=origin.description, - success_message="All proxies from the destroyed origin will shortly be destroyed at their providers.", - success_view="portal.view_origins", - section="origin", - resource=origin, - action="destroy" - ) diff --git a/app/portal/forms.py b/app/portal/forms.py index 1c2177a..b3396a2 100644 --- a/app/portal/forms.py +++ b/app/portal/forms.py @@ -3,19 +3,6 @@ from wtforms import StringField, SubmitField, SelectField, BooleanField, Integer from wtforms.validators import DataRequired, NumberRange -class NewOriginForm(FlaskForm): - domain_name = StringField('Domain Name', validators=[DataRequired()]) - description = StringField('Description', validators=[DataRequired()]) - group = SelectField('Group', validators=[DataRequired()]) - auto_rotate = BooleanField("Enable auto-rotation?", default=True) - submit = SubmitField('Save Changes') - - -class EditOriginForm(FlaskForm): - description = StringField('Description', validators=[DataRequired()]) - group = SelectField('Group', validators=[DataRequired()]) - auto_rotate = BooleanField("Enable auto-rotation?") - submit = SubmitField('Save Changes') class EditMirrorForm(FlaskForm): diff --git a/app/portal/origin.py b/app/portal/origin.py new file mode 100644 index 0000000..5c7d7d1 --- /dev/null +++ b/app/portal/origin.py @@ -0,0 +1,111 @@ +from datetime import datetime + +from flask import flash, redirect, url_for, render_template, Response, Blueprint +from flask_wtf import FlaskForm +from sqlalchemy import exc +from wtforms import StringField, SelectField, SubmitField, BooleanField +from wtforms.validators import DataRequired + +from app.extensions import db +from app.models.base import Group +from app.models.mirrors import Origin +from app.portal.util import response_404, view_lifecycle + +bp = Blueprint("origin", __name__) + + +class NewOriginForm(FlaskForm): + domain_name = StringField('Domain Name', validators=[DataRequired()]) + description = StringField('Description', validators=[DataRequired()]) + group = SelectField('Group', validators=[DataRequired()]) + auto_rotate = BooleanField("Enable auto-rotation?", default=True) + submit = SubmitField('Save Changes') + + +class EditOriginForm(FlaskForm): + description = StringField('Description', validators=[DataRequired()]) + group = SelectField('Group', validators=[DataRequired()]) + auto_rotate = BooleanField("Enable auto-rotation?") + submit = SubmitField('Save Changes') + + +@bp.route("/new", methods=['GET', 'POST']) +@bp.route("/new/", methods=['GET', 'POST']) +def origin_new(group_id=None): + form = NewOriginForm() + form.group.choices = [(x.id, x.group_name) for x in Group.query.all()] + if form.validate_on_submit(): + origin = Origin() + origin.group_id = form.group.data + origin.domain_name = form.domain_name.data + origin.description = form.description.data + origin.auto_rotation = form.auto_rotate.data + origin.created = datetime.utcnow() + origin.updated = datetime.utcnow() + try: + db.session.add(origin) + db.session.commit() + flash(f"Created new origin {origin.domain_name}.", "success") + return redirect(url_for("portal.origin.origin_edit", origin_id=origin.id)) + except exc.SQLAlchemyError as e: + print(e) + flash("Failed to create new origin.", "danger") + return redirect(url_for("portal.origin.origin_list")) + if group_id: + form.group.data = group_id + return render_template("new.html.j2", section="origin", form=form) + + +@bp.route('/edit/', methods=['GET', 'POST']) +def origin_edit(origin_id): + origin = Origin.query.filter(Origin.id == origin_id).first() + if origin is None: + return Response(render_template("error.html.j2", + section="origin", + header="404 Origin Not Found", + message="The requested origin could not be found."), + status=404) + form = EditOriginForm(group=origin.group_id, + description=origin.description, + auto_rotate=origin.auto_rotation) + form.group.choices = [(x.id, x.group_name) for x in Group.query.all()] + if form.validate_on_submit(): + origin.group_id = form.group.data + origin.description = form.description.data + origin.auto_rotation = form.auto_rotate.data + origin.updated = datetime.utcnow() + try: + db.session.commit() + flash("Saved changes to group.", "success") + except exc.SQLAlchemyError: + flash("An error occurred saving the changes to the group.", "danger") + return render_template("origin.html.j2", + section="origin", + origin=origin, form=form) + + +@bp.route("/list") +def origin_list(): + origins = Origin.query.order_by(Origin.domain_name).all() + return render_template("list.html.j2", + section="origin", + title="Origins", + item="origin", + new_link=url_for("portal.origin.origin_new"), + items=origins) + + +@bp.route("/destroy/", methods=['GET', 'POST']) +def origin_destroy(origin_id: int): + 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.") + return view_lifecycle( + header=f"Destroy origin {origin.domain_name}", + message=origin.description, + success_message="All proxies from the destroyed origin will shortly be destroyed at their providers.", + success_view="portal.view_origins", + section="origin", + resource=origin, + action="destroy" + ) diff --git a/app/portal/proxy.py b/app/portal/proxy.py index edffde8..931457f 100644 --- a/app/portal/proxy.py +++ b/app/portal/proxy.py @@ -31,7 +31,7 @@ def proxy_block(proxy_id): proxy.deprecate(reason="manual") db.session.commit() flash("Proxy will be shortly replaced.", "success") - return redirect(url_for("portal.edit_origin", origin_id=proxy.origin.id)) + return redirect(url_for("portal.origin.origin_edit", origin_id=proxy.origin.id)) return render_template("lifecycle.html.j2", header=f"Mark proxy for {proxy.origin.domain_name} as blocked?", message=proxy.url, diff --git a/app/portal/templates/base.html.j2 b/app/portal/templates/base.html.j2 index 8756266..dc25510 100644 --- a/app/portal/templates/base.html.j2 +++ b/app/portal/templates/base.html.j2 @@ -78,7 +78,7 @@ diff --git a/app/portal/templates/group.html.j2 b/app/portal/templates/group.html.j2 index 0579ff9..e971720 100644 --- a/app/portal/templates/group.html.j2 +++ b/app/portal/templates/group.html.j2 @@ -11,7 +11,7 @@

Origins

- Create new origin + Create new origin {% if group.origins %} {{ origins_table(group.origins) }} {% endif %} diff --git a/app/portal/templates/tables.html.j2 b/app/portal/templates/tables.html.j2 index 8c7bd3b..042eaad 100644 --- a/app/portal/templates/tables.html.j2 +++ b/app/portal/templates/tables.html.j2 @@ -80,7 +80,7 @@ {{ origin.group.group_name }} - View/Edit @@ -113,7 +113,7 @@ - {{ proxy.origin.domain_name }} + {{ proxy.origin.domain_name }} {{ proxy.origin.group.group_name }} diff --git a/app/portal/util.py b/app/portal/util.py new file mode 100644 index 0000000..cb3dae2 --- /dev/null +++ b/app/portal/util.py @@ -0,0 +1,38 @@ +from flask import Response, render_template, flash, redirect, url_for + +from app import db +from app.models import AbstractResource +from app.portal.forms import LifecycleForm + + +def response_404(message: str): + return Response(render_template("error.html.j2", + header="404 Not Found", + message=message)) + + +def view_lifecycle(*, + header: str, + message: str, + success_message: str, + success_view: str, + section: str, + resource: AbstractResource, + action: str): + form = LifecycleForm() + if form.validate_on_submit(): + if action == "destroy": + resource.destroy() + elif action == "deprecate": + resource.deprecate(reason="manual") + else: + flash("Unknown action") + return redirect(url_for("portal.portal_home")) + db.session.commit() + flash(success_message, "success") + return redirect(url_for(success_view)) + return render_template("lifecycle.html.j2", + header=header, + message=message, + section=section, + form=form) \ No newline at end of file