From 0cc6cf0eda767463b309bcf3fead1e0b767acbf2 Mon Sep 17 00:00:00 2001 From: Iain Learmonth Date: Sat, 8 Oct 2022 19:51:56 +0100 Subject: [PATCH] portal/pool: allow adding and removing origin groups --- app/portal/pool.py | 85 +++++++++++++++++++++++++++-- app/portal/templates/pool.html.j2 | 3 +- app/portal/templates/tables.html.j2 | 9 ++- 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/app/portal/pool.py b/app/portal/pool.py index b2c9422..af1cd63 100644 --- a/app/portal/pool.py +++ b/app/portal/pool.py @@ -4,26 +4,32 @@ from flask import render_template, url_for, flash, redirect, Response, Blueprint from flask.typing import ResponseReturnValue from flask_wtf import FlaskForm import sqlalchemy -from wtforms import StringField, SubmitField +from wtforms import StringField, SubmitField, SelectField from wtforms.validators import DataRequired 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__) -class NewPoolForm(FlaskForm): # type: ignore +class NewPoolForm(FlaskForm): # type: ignore[misc] group_name = StringField("Short Name", validators=[DataRequired()]) description = StringField("Description", validators=[DataRequired()]) 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()]) 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") def pool_list() -> ResponseReturnValue: 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", section="pool", pool=pool, form=form) + + +@bp.route('/group_remove//', 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/', 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) diff --git a/app/portal/templates/pool.html.j2 b/app/portal/templates/pool.html.j2 index c6c0104..0064ded 100644 --- a/app/portal/templates/pool.html.j2 +++ b/app/portal/templates/pool.html.j2 @@ -11,7 +11,8 @@

Groups

- {{ groups_table(pool.groups) }} +

Add Group

+ {{ groups_table(pool.groups, pool) }}

Distribution Lists

{{ mirrorlists_table(pool.lists) }} diff --git a/app/portal/templates/tables.html.j2 b/app/portal/templates/tables.html.j2 index fbd656d..8ba5d50 100644 --- a/app/portal/templates/tables.html.j2 +++ b/app/portal/templates/tables.html.j2 @@ -175,7 +175,7 @@ {% endmacro %} -{% macro groups_table(groups) %} +{% macro groups_table(groups, pool=None) %}
@@ -194,7 +194,12 @@ - + {% endfor %}
{{ group.description }} {% if group.eotk %}✅{% else %}❌{% endif %} {{ group.origins | length }}View/Edit + View/Edit + {% if pool %} + Remove + {% endif %} +