majuna/app/portal/origin.py

129 lines
5.4 KiB
Python

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
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): # type: ignore
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): # type: ignore
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/<group_id>", methods=['GET', 'POST'])
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():
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/<origin_id>', methods=['GET', 'POST'])
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",
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() -> ResponseReturnValue:
origins: List[Origin] = Origin.query.order_by(Origin.domain_name).all()
return render_template("list.html.j2",
section="origin",
title="Web Origins",
item="origin",
new_link=url_for("portal.origin.origin_new"),
items=origins,
extra_buttons=[{
"link": url_for("portal.origin.origin_onion"),
"text": "Onion services",
"style": "onion"
}])
@bp.route("/onion")
def origin_onion() -> ResponseReturnValue:
origins = Origin.query.order_by(Origin.domain_name).all()
return render_template("list.html.j2",
section="origin",
title="Onion Sites",
item="onion service",
new_link=url_for("portal.onion.onion_new"),
items=origins)
@bp.route("/destroy/<origin_id>", methods=['GET', 'POST'])
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.")
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.origin.origin_list",
section="origin",
resource=origin,
action="destroy"
)