resource pool system
This commit is contained in:
parent
dc989dd7cb
commit
16f7e2199d
19 changed files with 382 additions and 105 deletions
|
@ -21,6 +21,7 @@ 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.onion import bp as onion
|
||||
from app.portal.pool import bp as pool
|
||||
from app.portal.proxy import bp as proxy
|
||||
from app.portal.smart_proxy import bp as smart_proxy
|
||||
from app.portal.webhook import bp as webhook
|
||||
|
@ -34,6 +35,7 @@ portal.register_blueprint(group, url_prefix="/group")
|
|||
portal.register_blueprint(list_, url_prefix="/list")
|
||||
portal.register_blueprint(origin, url_prefix="/origin")
|
||||
portal.register_blueprint(onion, url_prefix="/onion")
|
||||
portal.register_blueprint(pool, url_prefix="/pool")
|
||||
portal.register_blueprint(proxy, url_prefix="/proxy")
|
||||
portal.register_blueprint(smart_proxy, url_prefix="/smart")
|
||||
portal.register_blueprint(webhook, url_prefix="/webhook")
|
||||
|
|
|
@ -74,6 +74,7 @@ def automation_kick(automation_id: int) -> ResponseReturnValue:
|
|||
return view_lifecycle(
|
||||
header="Kick automation timer?",
|
||||
message=automation.description,
|
||||
section="automation",
|
||||
success_view="portal.automation.automation_list",
|
||||
success_message="This automation job will next run within 1 minute.",
|
||||
resource=automation,
|
||||
|
|
|
@ -6,8 +6,3 @@ class EditMirrorForm(FlaskForm): # type: ignore
|
|||
origin = SelectField('Origin')
|
||||
url = StringField('URL')
|
||||
submit = SubmitField('Save Changes')
|
||||
|
||||
|
||||
class EditProxyForm(FlaskForm): # type: ignore
|
||||
origin = SelectField('Origin')
|
||||
submit = SubmitField('Save Changes')
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import json
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
|
||||
from flask import render_template, url_for, flash, redirect, Blueprint, Response
|
||||
from flask.typing import ResponseReturnValue
|
||||
|
@ -13,7 +13,7 @@ from app.extensions import db
|
|||
from app.lists.bc2 import mirror_sites
|
||||
from app.lists.bridgelines import bridgelines
|
||||
from app.lists.mirror_mapping import mirror_mapping
|
||||
from app.models.base import MirrorList
|
||||
from app.models.base import MirrorList, Pool
|
||||
from app.portal.util import response_404, view_lifecycle
|
||||
|
||||
bp = Blueprint("list", __name__)
|
||||
|
@ -96,6 +96,7 @@ def list_new(group_id: Optional[int] = None) -> ResponseReturnValue:
|
|||
form.encoding.choices = list(MirrorList.encodings_supported.items())
|
||||
if form.validate_on_submit():
|
||||
list_ = MirrorList()
|
||||
list_.pool_id = form.pool.data
|
||||
list_.provider = form.provider.data
|
||||
list_.format = form.format.data
|
||||
list_.encoding = form.encoding.data
|
||||
|
@ -122,6 +123,7 @@ def list_new(group_id: Optional[int] = None) -> ResponseReturnValue:
|
|||
|
||||
|
||||
class NewMirrorListForm(FlaskForm): # type: ignore
|
||||
pool = SelectField('Resource Pool', validators=[DataRequired()])
|
||||
provider = SelectField('Provider', validators=[DataRequired()])
|
||||
format = SelectField('Distribution Method', validators=[DataRequired()])
|
||||
encoding = SelectField('Encoding', validators=[DataRequired()])
|
||||
|
@ -136,6 +138,12 @@ class NewMirrorListForm(FlaskForm): # type: ignore
|
|||
filename = StringField('Filename', validators=[DataRequired()])
|
||||
submit = SubmitField('Save Changes')
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.pool.choices = [
|
||||
(pool.id, pool.pool_name) for pool in Pool.query.all()
|
||||
]
|
||||
|
||||
|
||||
@bp.route('/edit/<list_id>', methods=['GET', 'POST'])
|
||||
def list_edit(list_id: int) -> ResponseReturnValue:
|
||||
|
@ -160,6 +168,7 @@ def list_edit(list_id: int) -> ResponseReturnValue:
|
|||
form.format.choices = list(MirrorList.formats_supported.items())
|
||||
form.encoding.choices = list(MirrorList.encodings_supported.items())
|
||||
if form.validate_on_submit():
|
||||
list_.pool_id = form.pool.data
|
||||
list_.provider = form.provider.data
|
||||
list_.format = form.format.data
|
||||
list_.encoding = form.encoding.data
|
||||
|
|
78
app/portal/pool.py
Normal file
78
app/portal/pool.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
from datetime import datetime
|
||||
|
||||
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.validators import DataRequired
|
||||
|
||||
from app.extensions import db
|
||||
from app.models.base import Pool
|
||||
|
||||
bp = Blueprint("pool", __name__)
|
||||
|
||||
|
||||
class NewPoolForm(FlaskForm): # type: ignore
|
||||
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
|
||||
description = StringField("Description", 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()
|
||||
return render_template("list.html.j2",
|
||||
section="pool",
|
||||
title="Resource Pools",
|
||||
item="pool",
|
||||
items=pools,
|
||||
new_link=url_for("portal.pool.pool_new"))
|
||||
|
||||
|
||||
@bp.route("/new", methods=['GET', 'POST'])
|
||||
def pool_new() -> ResponseReturnValue:
|
||||
form = NewPoolForm()
|
||||
if form.validate_on_submit():
|
||||
pool = Pool()
|
||||
pool.pool_name = form.group_name.data
|
||||
pool.description = form.description.data
|
||||
pool.created = datetime.utcnow()
|
||||
pool.updated = datetime.utcnow()
|
||||
try:
|
||||
db.session.add(pool)
|
||||
db.session.commit()
|
||||
flash(f"Created new pool {pool.pool_name}.", "success")
|
||||
return redirect(url_for("portal.pool.pool_edit", pool_id=pool.id))
|
||||
except sqlalchemy.exc.SQLAlchemyError:
|
||||
flash("Failed to create new pool.", "danger")
|
||||
return redirect(url_for("portal.pool.pool_list"))
|
||||
return render_template("new.html.j2", section="pool", form=form)
|
||||
|
||||
|
||||
@bp.route('/edit/<pool_id>', methods=['GET', 'POST'])
|
||||
def pool_edit(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 = EditPoolForm(description=pool.description)
|
||||
if form.validate_on_submit():
|
||||
pool.description = form.description.data
|
||||
pool.updated = datetime.utcnow()
|
||||
try:
|
||||
db.session.commit()
|
||||
flash("Saved changes to pool.", "success")
|
||||
except sqlalchemy.exc.SQLAlchemyError:
|
||||
flash("An error occurred saving the changes to the pool.", "danger")
|
||||
return render_template("pool.html.j2",
|
||||
section="pool",
|
||||
pool=pool, form=form)
|
|
@ -87,6 +87,12 @@
|
|||
{{ icon("collection") }} Groups
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if section == "pool" %} active{% endif %}"
|
||||
href="{{ url_for("portal.pool.pool_list") }}">
|
||||
{{ icon("stack") }} Resource Pools
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link{% if section == "origin" %} active{% endif %}"
|
||||
href="{{ url_for("portal.origin.origin_list") }}">
|
||||
|
|
|
@ -98,5 +98,10 @@
|
|||
<path d="M1.333 6.334v3C1.333 10.805 4.318 12 8 12s6.667-1.194 6.667-2.667V6.334a6.51 6.51 0 0 1-1.458.79C11.81 7.684 9.967 8 8 8c-1.966 0-3.809-.317-5.208-.876a6.508 6.508 0 0 1-1.458-.79z"/>
|
||||
<path d="M14.667 11.668a6.51 6.51 0 0 1-1.458.789c-1.4.56-3.242.876-5.21.876-1.966 0-3.809-.316-5.208-.876a6.51 6.51 0 0 1-1.458-.79v1.666C1.333 14.806 4.318 16 8 16s6.667-1.194 6.667-2.667v-1.665z"/>
|
||||
</svg>
|
||||
{% elif i == "stack" %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stack" viewBox="0 0 16 16">
|
||||
<path d="m14.12 10.163 1.715.858c.22.11.22.424 0 .534L8.267 15.34a.598.598 0 0 1-.534 0L.165 11.555a.299.299 0 0 1 0-.534l1.716-.858 5.317 2.659c.505.252 1.1.252 1.604 0l5.317-2.66zM7.733.063a.598.598 0 0 1 .534 0l7.568 3.784a.3.3 0 0 1 0 .535L8.267 8.165a.598.598 0 0 1-.534 0L.165 4.382a.299.299 0 0 1 0-.535L7.733.063z"/>
|
||||
<path d="m14.12 6.576 1.715.858c.22.11.22.424 0 .534l-7.568 3.784a.598.598 0 0 1-.534 0L.165 7.968a.299.299 0 0 1 0-.534l1.716-.858 5.317 2.659c.505.252 1.1.252 1.604 0l5.317-2.659z"/>
|
||||
</svg>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html.j2" %}
|
||||
{% from "tables.html.j2" import alarms_table, automations_table, bridgeconfs_table, bridges_table, eotk_table,
|
||||
groups_table, instances_table, mirrorlists_table, origins_table, origin_onion_table, onions_table, proxies_table,
|
||||
webhook_table %}
|
||||
groups_table, instances_table, mirrorlists_table, origins_table, origin_onion_table, onions_table, pools_table,
|
||||
proxies_table, webhook_table %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="h2 mt-3">{{ title }}</h1>
|
||||
|
@ -33,6 +33,8 @@
|
|||
{% endif %}
|
||||
{% elif item == "origin" %}
|
||||
{{ origins_table(items) }}
|
||||
{% elif item == "pool" %}
|
||||
{{ pools_table(items) }}
|
||||
{% elif item == "proxy" %}
|
||||
{{ proxies_table(items) }}
|
||||
{% elif item == "smart proxy" %}
|
||||
|
|
21
app/portal/templates/pool.html.j2
Normal file
21
app/portal/templates/pool.html.j2
Normal file
|
@ -0,0 +1,21 @@
|
|||
{% extends "base.html.j2" %}
|
||||
{% from 'bootstrap5/form.html' import render_form %}
|
||||
{% from "tables.html.j2" import groups_table, mirrorlists_table, proxies_table %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="h2 mt-3">Resource Pool</h1>
|
||||
<h2 class="h3">{{ pool.pool_name }}</h2>
|
||||
|
||||
<div style="border: 1px solid #666;" class="p-3">
|
||||
{{ render_form(form) }}
|
||||
</div>
|
||||
|
||||
<h3>Groups</h3>
|
||||
{{ groups_table(pool.groups) }}
|
||||
|
||||
<h3>Distribution Lists</h3>
|
||||
{{ mirrorlists_table(pool.lists) }}
|
||||
|
||||
<h3>Simple Proxies</h3>
|
||||
{{ proxies_table(pool.proxies) }}
|
||||
{% endblock %}
|
|
@ -334,6 +334,29 @@
|
|||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro pools_table(pools) %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for pool in pools %}
|
||||
<tr>
|
||||
<td>{{ pool.pool_name }}</td>
|
||||
<td>{{ pool.description }}</td>
|
||||
<td><a href="{{ url_for("portal.pool.pool_edit", pool_id=pool.id) }}" class="btn btn-primary btn-sm">View/Edit</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro proxies_table(proxies) %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue