portal: allow list destruction

fixes #15
This commit is contained in:
Iain Learmonth 2022-05-11 15:47:39 +01:00
parent b085409e5e
commit efb74ae413
9 changed files with 107 additions and 80 deletions

View file

@ -1,27 +1,27 @@
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from flask import Blueprint, render_template, flash, redirect, url_for, request from flask import Blueprint, render_template, request
from sqlalchemy import exc, desc, or_ from sqlalchemy import desc, or_
from app.extensions import db
from app.models.alarms import Alarm from app.models.alarms import Alarm
from app import Origin, Proxy from app import Origin, Proxy
from app.models.base import Group, MirrorList from app.models.base import Group
from app.portal.forms import LifecycleForm, NewMirrorListForm from app.portal.list import NewMirrorListForm
from app.portal.automation import bp as automation from app.portal.automation import bp as automation
from app.portal.bridgeconf import bp as bridgeconf from app.portal.bridgeconf import bp as bridgeconf
from app.portal.bridge import bp as bridge from app.portal.bridge import bp as bridge
from app.portal.group import bp as group 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.origin import bp as origin
from app.portal.onion import bp as onion from app.portal.onion import bp as onion
from app.portal.proxy import bp as proxy 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 = Blueprint("portal", __name__, template_folder="templates", static_folder="static")
portal.register_blueprint(automation, url_prefix="/automation") portal.register_blueprint(automation, url_prefix="/automation")
portal.register_blueprint(bridgeconf, url_prefix="/bridgeconf") portal.register_blueprint(bridgeconf, url_prefix="/bridgeconf")
portal.register_blueprint(bridge, url_prefix="/bridge") portal.register_blueprint(bridge, url_prefix="/bridge")
portal.register_blueprint(group, url_prefix="/group") portal.register_blueprint(group, url_prefix="/group")
portal.register_blueprint(list_, url_prefix="/list")
portal.register_blueprint(origin, url_prefix="/origin") portal.register_blueprint(origin, url_prefix="/origin")
portal.register_blueprint(onion, url_prefix="/onion") portal.register_blueprint(onion, url_prefix="/onion")
portal.register_blueprint(proxy, url_prefix="/proxy") portal.register_blueprint(proxy, url_prefix="/proxy")
@ -74,58 +74,3 @@ def view_alarms():
items=alarms) items=alarms)
@portal.route('/lists')
def view_mirror_lists():
mirrorlists = MirrorList.query.filter(MirrorList.destroyed == None).all()
return render_template("list.html.j2",
section="list",
title="Mirror Lists",
item="mirror list",
new_link=url_for("portal.new_mirror_list"),
items=mirrorlists)
@portal.route("/list/destroy/<list_id>")
def destroy_mirror_list(list_id):
return "not implemented"
@portal.route("/list/new", methods=['GET', 'POST'])
@portal.route("/list/new/<group_id>", methods=['GET', 'POST'])
def new_mirror_list(group_id=None):
form = NewMirrorListForm()
form.provider.choices = [
("github", "GitHub"),
("gitlab", "GitLab"),
("s3", "AWS S3"),
]
form.format.choices = [
("bc2", "Bypass Censorship v2"),
("bc3", "Bypass Censorship v3"),
("bca", "Bypass Censorship Analytics"),
("bridgelines", "Tor Bridge Lines")
]
form.container.description = "GitHub Project, GitLab Project or AWS S3 bucket name."
form.branch.description = "Ignored for AWS S3."
if form.validate_on_submit():
mirror_list = MirrorList()
mirror_list.provider = form.provider.data
mirror_list.format = form.format.data
mirror_list.description = form.description.data
mirror_list.container = form.container.data
mirror_list.branch = form.branch.data
mirror_list.filename = form.filename.data
mirror_list.created = datetime.utcnow()
mirror_list.updated = datetime.utcnow()
try:
db.session.add(mirror_list)
db.session.commit()
flash(f"Created new mirror list.", "success")
return redirect(url_for("portal.view_mirror_lists"))
except exc.SQLAlchemyError as e:
print(e)
flash("Failed to create new mirror list.", "danger")
return redirect(url_for("portal.view_mirror_lists"))
if group_id:
form.group.data = group_id
return render_template("new.html.j2", section="list", form=form)

View file

@ -4,7 +4,6 @@ from flask import render_template, flash, Response, Blueprint
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from sqlalchemy import exc from sqlalchemy import exc
from wtforms import SubmitField, BooleanField from wtforms import SubmitField, BooleanField
from wtforms.validators import DataRequired
from app.extensions import db from app.extensions import db
from app.models.automation import Automation from app.models.automation import Automation

View file

@ -2,7 +2,7 @@ from flask import render_template, Response, flash, redirect, url_for, Blueprint
from app.extensions import db from app.extensions import db
from app.models.bridges import Bridge from app.models.bridges import Bridge
from app.portal.forms import LifecycleForm from app.portal.util import LifecycleForm
bp = Blueprint("bridge", __name__) bp = Blueprint("bridge", __name__)

View file

@ -1,6 +1,5 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField from wtforms import StringField, SubmitField, SelectField
from wtforms.validators import DataRequired
class EditMirrorForm(FlaskForm): class EditMirrorForm(FlaskForm):
@ -14,15 +13,3 @@ class EditProxyForm(FlaskForm):
submit = SubmitField('Save Changes') submit = SubmitField('Save Changes')
class LifecycleForm(FlaskForm):
submit = SubmitField('Confirm')
class NewMirrorListForm(FlaskForm):
provider = SelectField('Provider', validators=[DataRequired()])
format = SelectField('Distribution Method', validators=[DataRequired()])
description = StringField('Description', validators=[DataRequired()])
container = StringField('Container', validators=[DataRequired()])
branch = StringField('Branch')
filename = StringField('Filename', validators=[DataRequired()])
submit = SubmitField('Save Changes')

91
app/portal/list.py Normal file
View file

@ -0,0 +1,91 @@
from datetime import datetime
from flask import render_template, url_for, flash, redirect, Blueprint
from flask_wtf import FlaskForm
from sqlalchemy import exc
from wtforms import SelectField, StringField, SubmitField
from wtforms.validators import DataRequired
from app import db
from app.models.base import MirrorList
from app.portal.util import response_404, view_lifecycle
bp = Blueprint("list", __name__)
@bp.route('/list')
def list_list():
lists = MirrorList.query.filter(MirrorList.destroyed == None).all()
return render_template("list.html.j2",
section="list",
title="Mirror Lists",
item="mirror list",
new_link=url_for("portal.list.list_new"),
items=lists)
@bp.route("/destroy/<list_id>", methods=['GET', 'POST'])
def list_destroy(list_id: int):
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.")
return view_lifecycle(
header=f"Destroy mirror list?",
message=list_.description,
success_view="portal.list.list_list",
success_message="This list will no longer be updated and may be deleted depending on the provider.",
section="list",
resource=list_,
action="destroy"
)
@bp.route("/new", methods=['GET', 'POST'])
@bp.route("/new/<group_id>", methods=['GET', 'POST'])
def list_new(group_id=None):
form = NewMirrorListForm()
form.provider.choices = [
("github", "GitHub"),
("gitlab", "GitLab"),
("s3", "AWS S3"),
]
form.format.choices = [
("bc2", "Bypass Censorship v2"),
("bc3", "Bypass Censorship v3"),
("bca", "Bypass Censorship Analytics"),
("bridgelines", "Tor Bridge Lines")
]
form.container.description = "GitHub Project, GitLab Project or AWS S3 bucket name."
form.branch.description = "Ignored for AWS S3."
if form.validate_on_submit():
list_ = MirrorList()
list_.provider = form.provider.data
list_.format = form.format.data
list_.description = form.description.data
list_.container = form.container.data
list_.branch = form.branch.data
list_.filename = form.filename.data
list_.created = datetime.utcnow()
list_.updated = datetime.utcnow()
try:
db.session.add(list_)
db.session.commit()
flash(f"Created new mirror list.", "success")
return redirect(url_for("portal.list.list_list"))
except exc.SQLAlchemyError as e:
print(e)
flash("Failed to create new mirror list.", "danger")
return redirect(url_for("portal.list.list_list"))
if group_id:
form.group.data = group_id
return render_template("new.html.j2", section="list", form=form)
class NewMirrorListForm(FlaskForm):
provider = SelectField('Provider', validators=[DataRequired()])
format = SelectField('Distribution Method', validators=[DataRequired()])
description = StringField('Description', validators=[DataRequired()])
container = StringField('Container', validators=[DataRequired()])
branch = StringField('Branch')
filename = StringField('Filename', validators=[DataRequired()])
submit = SubmitField('Save Changes')

View file

@ -3,7 +3,7 @@ from sqlalchemy import desc
from app.extensions import db from app.extensions import db
from app.models.mirrors import Proxy from app.models.mirrors import Proxy
from app.portal.forms import LifecycleForm from app.portal.util import LifecycleForm
bp = Blueprint("proxy", __name__) bp = Blueprint("proxy", __name__)

View file

@ -90,7 +90,7 @@
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link{% if section == "list" %} active{% endif %}" <a class="nav-link{% if section == "list" %} active{% endif %}"
href="{{ url_for("portal.view_mirror_lists") }}"> href="{{ url_for("portal.list.list_list") }}">
Mirror Lists Mirror Lists
</a> </a>
</li> </li>

View file

@ -470,7 +470,7 @@
<td>{{ list.url() }}</td> <td>{{ list.url() }}</td>
<td>{{ list.description }}</td> <td>{{ list.description }}</td>
<td> <td>
<a href="{{ url_for("portal.destroy_mirror_list", list_id=list.id) }}" <a href="{{ url_for("portal.list.list_destroy", list_id=list.id) }}"
class="btn btn-danger btn-sm">Destroy</a> class="btn btn-danger btn-sm">Destroy</a>
</td> </td>
</tr> </tr>

View file

@ -1,8 +1,9 @@
from flask import Response, render_template, flash, redirect, url_for from flask import Response, render_template, flash, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import SubmitField
from app import db from app import db
from app.models import AbstractResource from app.models import AbstractResource
from app.portal.forms import LifecycleForm
def response_404(message: str): def response_404(message: str):
@ -44,3 +45,7 @@ def view_lifecycle(*,
message=message, message=message,
section=section, section=section,
form=form) form=form)
class LifecycleForm(FlaskForm):
submit = SubmitField('Confirm')