feat: entry creation % details

This commit is contained in:
2023-07-02 16:20:38 +02:00
parent 8fc4fca2a1
commit af6c3ff0eb
7 changed files with 271 additions and 27 deletions

View File

@@ -1,5 +1,6 @@
#!/usr/bin/python3
import time
import flask
import json
import argparse
@@ -7,6 +8,12 @@ import os
import datetime
import pytimeparse.timeparse as timeparse
import sys
import secrets
import flask_wtf
from flask_wtf import FlaskForm, CSRFProtect
from wtforms import StringField, SubmitField, BooleanField, DecimalField
from wtforms.validators import DataRequired, Length
from sqlalchemy import Column, Integer, String, Boolean, or_, and_
from sqlalchemy.orm import sessionmaker
@@ -17,6 +24,9 @@ from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql.expression import func
app = flask.Flask("Icinga Report In Gateway")
CSRFProtect(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config['JSON_CONFIG_FILE'] = 'services.json'
app.config['JSON_CONFIG_DIR'] = 'config'
@@ -40,6 +50,10 @@ class Status(db.Model):
status = Column(String)
info_text = Column(String)
def human_date(self):
dt = datetime.datetime.fromtimestamp(self.timestamp)
return dt.strftime("%d-%m%-%y %H:%M")
def buildReponseDict(status, service=None):
if not status:
@@ -56,6 +70,8 @@ def buildReponseDict(status, service=None):
@app.route('/overview')
def overview():
user = flask.request.headers.get("X-Preferred-Username")
# query all services #
services = db.session.query(Service).all()
@@ -83,7 +99,54 @@ def overview():
status_unique_results.append(status)
return flask.render_template("overview.html", status_list=status_unique_results,
datetime=datetime.datetime)
datetime=datetime.datetime, user=user)
class EntryForm(FlaskForm):
service = StringField("Service Name", validators=[DataRequired()])
timeout = DecimalField("Timeout in days", default=30)
def create_entry(form, user):
# TODO add entry to icinga
token = secrets.token_urlsafe(16)
print(form.timeout.data)
service = Service(service=form.service.data, timeout=int(form.timeout.data),
owner=user, token=token)
db.session.merge(service)
db.session.commit()
@app.route("/service-details")
def service_details():
user = flask.request.headers.get("X-Preferred-Username")
service = flask.request.args.get("service")
# query service #
service = db.session.query(Service).filter(Service.service==service).first()
# validate #
if not service:
return ("{} not found".format("service"), 404)
if service.owner and service.owner != user:
return ("Services is not owned by {}".format(user))
status_list = db.session.query()
return flask.render_template("service_info.html", service=service, flask=flask,
user=user)
@app.route("/entry-form", methods=["GET", "POST"])
def create_interface():
user = flask.request.headers.get("X-Preferred-Username")
form = EntryForm()
if form.validate_on_submit():
create_entry(form, user)
return flask.redirect('/service-details?service={}'.format(form.service.data))
return flask.render_template('add_modify_service.html', form=form)
@app.route('/alive')
def alive():
@@ -188,6 +251,8 @@ def create_app():
db.create_all()
config = {}
app.config["SECRET_KEY"] = secrets.token_urlsafe(64)
if os.path.isfile(app.config["JSON_CONFIG_FILE"]):
with open(app.config["JSON_CONFIG_FILE"]) as f:
config |= json.load(f)

79
static/site.css Normal file
View File

@@ -0,0 +1,79 @@
body{
background: radial-gradient(ellipse at center, #47918a 0%, #0b3161 100%);
color: aliceblue !important;
}
.navbar{
width: 100%;
background: rgba(0,0,0,0);
display: block;
box-shadow: none;
padding: 20px;
}
.navbar-el{
float: right;
display: inline-block;
background: rgba(0,0,0,0);
color: aliceblue;
}
.navbar-el:hover{
color: darkgray;
}
.overview-tile{
color: black;
}
.last-status{
margin-top: 10px;
box-shadow: 0px 0px 4px 3px rgba(0,0,0,0.5);
background: linear-gradient(to top, #cfc6b054 0%, #cfcfcfc4 100%);
padding: 8px;
width: fit-content;
font-family: monospace;
font-weight: 500;
}
.last-status p{
margin-bottom: 0;
}
.service-name{
margin: auto;
max-width: 1000px;
width: fit-content;
padding-top: 30px;
padding-bottom: 30px;
}
.service-timeout{
}
.service-token{
}
.example{
font-family: monospace;
font-size: 12px;
border-style: solid;
border-width: 1px;
padding: 10px;
}
.example-indent{
padding-left: 20px;
}
.example-indent-double{
padding-left: 50px;
}
.status-table{
margin: auto;
width: 100%;
text-align: center;
}

View File

@@ -0,0 +1,24 @@
{% include "head.html" %}
<body>
<div class="container mt-5">
<button class="mt-4 mb-4 btn btn-secondary" onclick="window.location.href='/'">
Back
</button>
{% if form.service.errors %}
<ul class="errors">
{% for error in form.service.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<form method="POST" action="/entry-form">
{{ form.csrf_token }}
{{ form.service.label }} {{ form.service(size=20) }} </br>
{{ form.timeout.label }} {{ form.timeout() }} </br>
<input type="submit" value="Go">
</form>
</div>
</body>
</html>

24
templates/head.html Normal file
View File

@@ -0,0 +1,24 @@
<head>
<link rel="stylesheet" type="text/css" href="/static/site.css">
<link rel="shortcut icon" href="/static/defaultFavicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- needed for @media-css mofiers -->
<meta content="width=device-width, initial-scale=1" name="viewport" />
<!-- Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
<!-- Bootstrap core CSS -->
<link href="https://cdn.atlantishq.de/css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="https://cdn.atlantishq.de/css/mdb.min.css" rel="stylesheet">
<script src="https://cdn.atlantishq.de/js/jquery.js"></script>
<script src="https://cdn.atlantishq.de/js/popper.js"></script>
<script src="https://cdn.atlantishq.de/js/bootstrap.js"></script>
<script src="https://cdn.atlantishq.de/js/mdb.min.js"></script>
<script src="https://cdn.atlantishq.de/js/addons/datatables.min.js" type="text/javascript">
</script>
</head>

12
templates/navbar.html Normal file
View File

@@ -0,0 +1,12 @@
<div class="navbar">
{% if user %}
<div style="float: left;" class="navbar-el">{{ user }}</div>
{% endif %}
<a href="/overview" style="float: left;" class="navbar-el">Overview</a>
<a href="/entry-form" style="float: left;" class="navbar-el">Create Service</a>
{% if user %}
<a href="/oauth2/sign_out" class="navbar-el">Logout</a>
{% else %}
<div class="navbar-el placeholder"></div>
{% endif %}
</div>

View File

@@ -1,33 +1,12 @@
<head>
<link rel="stylesheet" type="text/css" href="/static/site.css">
<link rel="shortcut icon" href="/static/defaultFavicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- needed for @media-css mofiers -->
<meta content="width=device-width, initial-scale=1" name="viewport" />
<!-- Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
<!-- Bootstrap core CSS -->
<link href="https://cdn.atlantishq.de/css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="https://cdn.atlantishq.de/css/mdb.min.css" rel="stylesheet">
<script src="https://cdn.atlantishq.de/js/jquery.js"></script>
<script src="https://cdn.atlantishq.de/js/popper.js"></script>
<script src="https://cdn.atlantishq.de/js/bootstrap.js"></script>
<script src="https://cdn.atlantishq.de/js/mdb.min.js"></script>
<script src="https://cdn.atlantishq.de/js/addons/datatables.min.js" type="text/javascript">
</script>
</head>
{% include "head.html" %}
<html>
<body>
{% include "navbar.html" %}
<div class="container">
<div class="row">
{% for status in status_list %}
<div class="col-md-5 m-3 p-2 border rounded"
<a href="/service-details?service={{ status.service}}"
class="col-md-5 m-3 p-2 border rounded overview-tile"
{% if status.status == "OK" %}
style="background-color: lightgreen;"
{% elif status.status == "WARNING" %}
@@ -44,7 +23,7 @@
{% else %}
{{ datetime.fromtimestamp(status.timestamp).strftime("%H:%M %d.%m.%y") }}
{% endif %}
</div>
</a>
{% endfor %}
</div>
</div>

View File

@@ -0,0 +1,61 @@
{% include "head.html" %}
<html>
<body>
{% include "navbar.html" %}
<div class="container">
<h2 class="service-name">Service: {{ service.service }}</h2>
<div class="service-timeout">Timeout: {{ service.timeout }}d</div>
<div class="service-token">Secret Token: {{ service.token }}</div>
<div class="last-status">
{% if status_list | length > 0 %}
<p>{{ status_list[0].status }} submitted on {{ status_list[0].timestamp }}</i>
{% else %}
<p style="color: darkred;">No status for this service submitted</i>
{% endif %}
</div>
<h5 class="my-4">Curl</h5>
<div class="ml-3 example">
curl -X POST \ <br>
<div class="example-indent">
-H "application/json" \ <br>
-d '{ "service_name" : "{{ service.service }}",
"token" : "{{ service.token }}", \<br>
"status" : "OK", "info" : "Free Text Information here" }' \<br>
{{ flask.request.url_root }}
</div>
</div>
<h5 class="my-4">Python</h5>
<div class="ml-3 example">
import requests
requests.post("{{ flask.request.url_root }}",<br>
<div class="example-indent-double">
json= { "service_name" : "{{ service.service }}", <br>
<div class="example-indent-double">
"token" : "{{ service.token }}", <br>
"status" : "OK", </br>
"info" : "additional information" })
</div>
</div>
</div>
<table class="mb-4 mt-5 status-table">
<thead>
<th>Date</th>
<th>Status</th>
<th>Info</th>
</thead>
<tbody>
{% for status in status_list %}
<td>status.human_date()<td>
<td>status.status</td>
<td>status.info</td>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>