Skip to content

Commit

Permalink
gui updates for ApiKey and MachineApiKey
Browse files Browse the repository at this point in the history
  • Loading branch information
jirivrany committed Apr 4, 2024
1 parent 382a83e commit fb25b20
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 4 deletions.
2 changes: 1 addition & 1 deletion flowapp/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.3"
__version__ = "0.8.0"
26 changes: 26 additions & 0 deletions flowapp/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,32 @@ class ApiKeyForm(FlaskForm):
key = HiddenField("GeneratedKey")


class MachineApiKeyForm(FlaskForm):
"""
ApiKey for Machines
Each key / machine pair is unique
Only Admin can create new these keys
"""

machine = StringField(
"Machine address",
validators=[DataRequired(), IPAddress(message="provide valid IP address")],
)

comment = TextAreaField(
"Your comment for this key", validators=[Optional(), Length(max=255)]
)

expires = MultiFormatDateTimeLocalField(
"Key expiration. Leave blank for non expring key (not-recomended).",
format=FORM_TIME_PATTERN, validators=[Optional()], unlimited=True
)

readonly = BooleanField("Read only key", default=False)

key = HiddenField("GeneratedKey")


class OrganizationForm(FlaskForm):
"""
Organization form object
Expand Down
1 change: 1 addition & 0 deletions flowapp/instance_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class InstanceConfig:
],
"admin": [
{"name": "Commands Log", "url": "admin.log"},
{"name": "Machine keys", "url": "admin.machine_keys"},
{
"name": "Users",
"url": "admin.users",
Expand Down
44 changes: 44 additions & 0 deletions flowapp/templates/forms/machine_api_key.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% extends 'layouts/default.html' %}
{% from 'forms/macros.html' import render_field, render_checkbox_field %}
{% block title %}Add New Machine with ApiKey{% endblock %}
{% block content %}
<h2>Add new ApiKey for machine.</h2>
<p>
In general, the keys should be Read Only and with expiration.
If you need to create a full access Read/Write key, consider using usual user form
with your organization settings.
</p>

<div class="row">

<div class="col-sm-12">
<h6>Machine Api Key: {{ generated_key }}</h6>
</div>

<form action="{{ url_for('admin.add_machine_key') }}" method="POST">
{{ form.hidden_tag() if form.hidden_tag }}
<div class="row">
<div class="col-sm-5">
{{ render_field(form.machine) }}
</div>
<div class="col-sm-2">
{{ render_checkbox_field(form.readonly, checked="checked") }}
</div>
<div class="col-sm-5">
{{ render_field(form.expires) }}
</div>
</div>

</div>
<div class="row">
<div class="col-sm-10">
{{ render_field(form.comment) }}
</div>

<div class="row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>

{% endblock %}
2 changes: 1 addition & 1 deletion flowapp/templates/pages/api_key.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ <h1>Your machines and ApiKeys</h1>
{{ row.key }}
</td>
<td>
{{ row.expires }}
{{ row.expires|strftime }}
</td>
<td>
{% if row.readonly %}
Expand Down
55 changes: 55 additions & 0 deletions flowapp/templates/pages/machine_api_key.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{% extends 'layouts/default.html' %}
{% block title %}ExaFS - ApiKeys{% endblock %}
{% block content %}
<h1>Machines and ApiKeys</h1>
<p>
This is the list of all machines and their API keys, created by admin(s).
In general, the keys should be Read Only and with expiration.
If you need to create a full access Read/Write key, use usual user form with your organization settings.
</p>
<table class="table table-hover">
<tr>
<th>Machine address</th>
<th>ApiKey</th>
<th>Created by</th>
<th>Created for</th>
<th>Expires</th>
<th>Read/Write ?</th>
<th>Action</th>
</tr>
{% for row in keys %}
<tr>
<td>
{{ row.machine }}
</td>
<td>
{{ row.key }}
</td>
<td>
{{ row.user.name }}
</td>
<td>
{{ row.comment }}
<td>
{{ row.expires|strftime }}
</td>
<td>
{% if not row.readonly %}
<button type="button" class="btn btn-warning btn-sm" title="Read Only">
<i class="bi bi-exclamation-lg"></i>
</button>

{% endif %}
</td>
<td>
<a class="btn btn-danger btn-sm" href="{{ url_for('admin.delete_machine_key', key_id=row.id) }}" role="button">
<i class="bi bi-x-lg"></i>
</a>
</td>
</tr>
{% endfor %}
</table>
<a class="btn btn-primary" href="{{ url_for('admin.add_machine_key') }}" role="button">
Add new Machine ApiKey
</a>
{% endblock %}
74 changes: 72 additions & 2 deletions flowapp/views/admin.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# flowapp/views/admin.py
from datetime import datetime, timedelta
import secrets

from flask import Blueprint, render_template, redirect, flash, request, url_for
from flask import Blueprint, render_template, redirect, flash, request, session, url_for
from sqlalchemy.exc import IntegrityError

from ..forms import ASPathForm, UserForm, ActionForm, OrganizationForm, CommunityForm
from ..forms import ASPathForm, MachineApiKeyForm, UserForm, ActionForm, OrganizationForm, CommunityForm
from ..models import (
ASPath,
MachineApiKey,
User,
Action,
Organization,
Expand Down Expand Up @@ -42,6 +44,74 @@ def log(page):
return render_template("pages/logs.html", logs=logs)


@admin.route("/machine_keys", methods=["GET"])
@auth_required
@admin_required
def machine_keys():
"""
Display all machine keys, from all admins
"""
keys = db.session.query(MachineApiKey).all()

return render_template("pages/machine_api_key.html", keys=keys)


@admin.route("/add_machine_key", methods=["GET", "POST"])
@auth_required
@admin_required
def add_machine_key():
"""
Add new MachnieApiKey
:return: form or redirect to list of keys
"""
generated = secrets.token_hex(24)
form = MachineApiKeyForm(request.form, key=generated)

if request.method == "POST" and form.validate():
print("Form validated")
# import ipdb; ipdb.set_trace()
model = MachineApiKey(
machine=form.machine.data,
key=form.key.data,
expires=form.expires.data,
readonly=form.readonly.data,
comment=form.comment.data,
user_id=session["user_id"]
)

db.session.add(model)
db.session.commit()
flash("NewKey saved", "alert-success")

return redirect(url_for("admin.machine_keys"))
else:
for field, errors in form.errors.items():
for error in errors:
print(
"Error in the %s field - %s"
% (getattr(form, field).label.text, error)
)

return render_template("forms/machine_api_key.html", form=form, generated_key=generated)


@admin.route("/delete_machine_key/<int:key_id>", methods=["GET"])
@auth_required
@admin_required
def delete_machine_key(key_id):
"""
Delete api_key and machine
:param key_id: integer
"""
model = db.session.query(MachineApiKey).get(key_id)
# delete from db
db.session.delete(model)
db.session.commit()
flash("Key deleted", "alert-success")

return redirect(url_for("admin.machine_keys"))


@admin.route("/user", methods=["GET", "POST"])
@auth_required
@admin_required
Expand Down

0 comments on commit fb25b20

Please sign in to comment.