portal/pool: allow adding and removing origin groups

This commit is contained in:
Iain Learmonth 2022-10-08 19:51:56 +01:00
parent a189e8756c
commit 0cc6cf0eda
3 changed files with 90 additions and 7 deletions

View file

@ -4,26 +4,32 @@ from flask import render_template, url_for, flash, redirect, Response, Blueprint
from flask.typing import ResponseReturnValue from flask.typing import ResponseReturnValue
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
import sqlalchemy import sqlalchemy
from wtforms import StringField, SubmitField from wtforms import StringField, SubmitField, SelectField
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
from app.extensions import db from app.extensions import db
from app.models.base import Pool from app.models.base import Pool, Group
from app.portal.util import LifecycleForm
bp = Blueprint("pool", __name__) bp = Blueprint("pool", __name__)
class NewPoolForm(FlaskForm): # type: ignore class NewPoolForm(FlaskForm): # type: ignore[misc]
group_name = StringField("Short Name", validators=[DataRequired()]) group_name = StringField("Short Name", validators=[DataRequired()])
description = StringField("Description", validators=[DataRequired()]) description = StringField("Description", validators=[DataRequired()])
submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"}) submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"})
class EditPoolForm(FlaskForm): # type: ignore class EditPoolForm(FlaskForm): # type: ignore[misc]
description = StringField("Description", validators=[DataRequired()]) description = StringField("Description", validators=[DataRequired()])
submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"}) submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"})
class GroupSelectForm(FlaskForm): # type: ignore[misc]
group = SelectField("Group", validators=[DataRequired()])
submit = SubmitField('Save Changes', render_kw={"class": "btn btn-success"})
@bp.route("/list") @bp.route("/list")
def pool_list() -> ResponseReturnValue: def pool_list() -> ResponseReturnValue:
pools = Pool.query.order_by(Pool.pool_name).all() pools = Pool.query.order_by(Pool.pool_name).all()
@ -76,3 +82,74 @@ def pool_edit(pool_id: int) -> ResponseReturnValue:
return render_template("pool.html.j2", return render_template("pool.html.j2",
section="pool", section="pool",
pool=pool, form=form) pool=pool, form=form)
@bp.route('/group_remove/<pool_id>/<group_id>', methods=['GET', 'POST'])
def pool_group_remove(pool_id: int, group_id: int) -> ResponseReturnValue:
pool = Pool.query.filter(Pool.id == pool_id).first()
if pool is None:
return Response(render_template("error.html.j2",
section="pool",
header="404 Pool Not Found",
message="The requested pool could not be found."),
status=404)
group = Group.query.filter(Group.id == group_id).first()
if group is None:
return Response(render_template("error.html.j2",
section="pool",
header="404 Group Not Found",
message="The requested group could not be found."),
status=404)
if group not in pool.groups:
return Response(render_template("error.html.j2",
section="pool",
header="404 Group Not In Pool",
message="The requested group could not be found in the specified pool."),
status=404)
form = LifecycleForm()
if form.validate_on_submit():
pool.groups.remove(group)
try:
db.session.commit()
flash("Saved changes to pool.", "success")
return redirect(url_for("portal.pool.pool_edit", pool_id=pool.id))
except sqlalchemy.exc.SQLAlchemyError:
flash("An error occurred saving the changes to the pool.", "danger")
return render_template("lifecycle.html.j2",
header=f"Remove {group.group_name} from the {pool.pool_name} pool?",
message="Resources deployed and available in the pool will be destroyed soon.",
section="pool",
pool=pool, form=form)
@bp.route('/group_add/<pool_id>', methods=['GET', 'POST'])
def pool_group_add(pool_id: int) -> ResponseReturnValue:
pool = Pool.query.filter(Pool.id == pool_id).first()
if pool is None:
return Response(render_template("error.html.j2",
section="pool",
header="404 Pool Not Found",
message="The requested pool could not be found."),
status=404)
form = GroupSelectForm()
form.group.choices = [(x.id, x.group_name) for x in Group.query.all()]
if form.validate_on_submit():
group = Group.query.filter(Group.id == form.group.data).first()
if group is None:
return Response(render_template("error.html.j2",
section="pool",
header="404 Group Not Found",
message="The requested group could not be found."),
status=404)
pool.groups.append(group)
try:
db.session.commit()
flash("Saved changes to pool.", "success")
return redirect(url_for("portal.pool.pool_edit", pool_id=pool.id))
except sqlalchemy.exc.SQLAlchemyError:
flash("An error occurred saving the changes to the pool.", "danger")
return render_template("lifecycle.html.j2",
header=f"Add a group to {pool.pool_name}",
message="Resources will shortly be deployed and available for all origins in this group.",
section="pool",
pool=pool, form=form)

View file

@ -11,7 +11,8 @@
</div> </div>
<h3>Groups</h3> <h3>Groups</h3>
{{ groups_table(pool.groups) }} <p><a href="{{ url_for("portal.pool.pool_group_add", pool_id=pool.id) }}" class="btn btn-sm btn-success">Add Group</a></p>
{{ groups_table(pool.groups, pool) }}
<h3>Distribution Lists</h3> <h3>Distribution Lists</h3>
{{ mirrorlists_table(pool.lists) }} {{ mirrorlists_table(pool.lists) }}

View file

@ -175,7 +175,7 @@
</div> </div>
{% endmacro %} {% endmacro %}
{% macro groups_table(groups) %} {% macro groups_table(groups, pool=None) %}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-sm"> <table class="table table-striped table-sm">
<thead> <thead>
@ -194,7 +194,12 @@
<td>{{ group.description }}</td> <td>{{ group.description }}</td>
<td>{% if group.eotk %}✅{% else %}❌{% endif %}</td> <td>{% if group.eotk %}✅{% else %}❌{% endif %}</td>
<td>{{ group.origins | length }}</td> <td>{{ group.origins | length }}</td>
<td><a href="{{ url_for("portal.group.group_edit", group_id=group.id) }}" class="btn btn-primary btn-sm">View/Edit</a></td> <td>
<a href="{{ url_for("portal.group.group_edit", group_id=group.id) }}" class="btn btn-primary btn-sm">View/Edit</a>
{% if pool %}
<a href="{{ url_for("portal.pool.pool_group_remove", pool_id=pool.id, group_id=group.id) }}" class="btn btn-danger btn-sm">Remove</a>
{% endif %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>