from flask import Flask, request, redirect, url_for, render_template_string, flash, Response
import pymysql
from pymysql.cursors import DictCursor
import os
import ipaddress
import json
app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY", "zmenit-na-vlastni-tajne-heslo")
DB_HOST = os.environ.get("DB_HOST", "localhost")
DB_PORT = int(os.environ.get("DB_PORT", "3306"))
DB_USER = os.environ.get("DB_USER", "ipam_user")
DB_PASSWORD = os.environ.get("DB_PASSWORD", "")
DB_NAME = os.environ.get("DB_NAME", "ipam")
def get_db_connection():
return pymysql.connect(
host=DB_HOST,
port=DB_PORT,
user=DB_USER,
password=DB_PASSWORD,
database=DB_NAME,
cursorclass=DictCursor,
autocommit=True,
charset="utf8mb4"
)
def validate_ipv4(ip_text: str) -> bool:
try:
ipaddress.IPv4Address(ip_text)
return True
except Exception:
return False
INDEX_TEMPLATE = """
IPplan
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
{{ message }}
{% endfor %}
{% endif %}
{% endwith %}
{% if mode == 'list' %}
IPplan
Řazeno podle IP adresy
{% if query %}
Nalezeno záznamů: {{ rows|length }} pro výraz {{ query }}
{% else %}
Celkem záznamů: {{ rows|length }}
{% endif %}
{% if rows %}
| IP adresa |
FQDN |
Účel |
Akce |
{% for row in rows %}
|
{{ row.ipaddress }}
|
{{ row.fqdn or '' }} |
{{ row.purpose or '' }} |
Upravit
|
{% endfor %}
{% else %}
Žádné záznamy nebyly nalezeny.
{% endif %}
{% elif mode == 'edit' %}
{% elif mode == 'add' %}
{% endif %}
"""
@app.route("/")
def index():
query = request.args.get("q", "").strip()
conn = get_db_connection()
try:
with conn.cursor() as cur:
if query:
like_value = f"%{query}%"
cur.execute("""
SELECT id, ipaddress, fqdn, purpose
FROM iplist
WHERE ipaddress LIKE %s
OR fqdn LIKE %s
OR purpose LIKE %s
ORDER BY INET_ATON(ipaddress) ASC
""", (like_value, like_value, like_value))
else:
cur.execute("""
SELECT id, ipaddress, fqdn, purpose
FROM iplist
ORDER BY INET_ATON(ipaddress) ASC
""")
rows = cur.fetchall()
finally:
conn.close()
return render_template_string(
INDEX_TEMPLATE,
mode="list",
rows=rows,
query=query
)
@app.route("/export/json")
def export_json():
query = request.args.get("q", "").strip()
conn = get_db_connection()
try:
with conn.cursor() as cur:
if query:
like_value = f"%{query}%"
cur.execute("""
SELECT ipaddress, fqdn, purpose
FROM iplist
WHERE ipaddress LIKE %s
OR fqdn LIKE %s
OR purpose LIKE %s
ORDER BY INET_ATON(ipaddress) ASC
""", (like_value, like_value, like_value))
else:
cur.execute("""
SELECT ipaddress, fqdn, purpose
FROM iplist
ORDER BY INET_ATON(ipaddress) ASC
""")
rows = cur.fetchall()
finally:
conn.close()
json_data = json.dumps(rows, ensure_ascii=False, indent=2)
return Response(
json_data,
mimetype="application/json",
headers={
"Content-Disposition": "attachment; filename=iplist.json"
}
)
@app.route("/add", methods=["GET", "POST"])
def add_item():
form_data = {
"ipaddress": "",
"fqdn": "",
"purpose": ""
}
if request.method == "POST":
form_data["ipaddress"] = request.form.get("ipaddress", "").strip()
form_data["fqdn"] = request.form.get("fqdn", "").strip()
form_data["purpose"] = request.form.get("purpose", "").strip()
if not validate_ipv4(form_data["ipaddress"]):
flash("Neplatná IPv4 adresa.", "error")
return render_template_string(INDEX_TEMPLATE, mode="add", form_data=form_data)
conn = get_db_connection()
try:
with conn.cursor() as cur:
try:
cur.execute("""
INSERT INTO iplist (ipaddress, fqdn, purpose)
VALUES (%s, %s, %s)
""", (
form_data["ipaddress"],
form_data["fqdn"] or None,
form_data["purpose"] or None
))
flash("Záznam byl přidán.", "success")
return redirect(url_for("index"))
except pymysql.err.IntegrityError:
flash("Tahle IP adresa už v databázi existuje.", "error")
finally:
conn.close()
return render_template_string(INDEX_TEMPLATE, mode="add", form_data=form_data)
@app.route("/edit/", methods=["GET", "POST"])
def edit_item(item_id):
conn = get_db_connection()
try:
with conn.cursor() as cur:
if request.method == "POST":
ipaddress_value = request.form.get("ipaddress", "").strip()
fqdn_value = request.form.get("fqdn", "").strip()
purpose_value = request.form.get("purpose", "").strip()
if not validate_ipv4(ipaddress_value):
flash("Neplatná IPv4 adresa.", "error")
else:
try:
cur.execute("""
UPDATE iplist
SET ipaddress = %s,
fqdn = %s,
purpose = %s
WHERE id = %s
""", (
ipaddress_value,
fqdn_value or None,
purpose_value or None,
item_id
))
flash("Záznam byl uložen.", "success")
return redirect(url_for("index"))
except pymysql.err.IntegrityError:
flash("Tahle IP adresa už v databázi existuje.", "error")
cur.execute("""
SELECT id, ipaddress, fqdn, purpose
FROM iplist
WHERE id = %s
""", (item_id,))
item = cur.fetchone()
if not item:
flash("Záznam nebyl nalezen.", "error")
return redirect(url_for("index"))
finally:
conn.close()
return render_template_string(INDEX_TEMPLATE, mode="edit", item=item)
@app.route("/delete/", methods=["POST"])
def delete_item(item_id):
conn = get_db_connection()
try:
with conn.cursor() as cur:
cur.execute("SELECT ipaddress FROM iplist WHERE id = %s", (item_id,))
item = cur.fetchone()
if not item:
flash("Záznam nebyl nalezen.", "error")
return redirect(url_for("index"))
cur.execute("DELETE FROM iplist WHERE id = %s", (item_id,))
flash(f"Záznam {item['ipaddress']} byl smazán.", "success")
finally:
conn.close()
return redirect(url_for("index"))
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=False)