Semaine 11
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
from flask import Flask, jsonify, request, render_template, redirect, url_for, flash
|
||||
|
||||
from classes import Equipment, Interface
|
||||
from database import (
|
||||
init_database,
|
||||
reset_database,
|
||||
prompt_reset,
|
||||
fetch_all_equipments,
|
||||
fetch_equipment_by_id,
|
||||
insert_equipment,
|
||||
update_equipment,
|
||||
delete_equipment,
|
||||
)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def _required_env(key: str) -> str:
|
||||
value = os.environ.get(key)
|
||||
if not value:
|
||||
raise RuntimeError(
|
||||
f"Variable d'environnement {key!r} manquante. "
|
||||
f"Vérifiez votre fichier .env (voir .env.example)."
|
||||
)
|
||||
return value
|
||||
|
||||
app.config["SECRET_KEY"] = _required_env("FLASK_SECRET_KEY")
|
||||
app.config["DEBUG"] = os.environ.get("FLASK_DEBUG", "False").lower() in {"1", "true", "yes"}
|
||||
app.config["DATABASE_PATH"] = os.environ.get("DATABASE_PATH", "databases/inventory.db")
|
||||
|
||||
ALLOWED_TYPES = {"Server", "Instance", "Switch", "Gateway", "Router", "WAF", "Database"}
|
||||
|
||||
def _parse_form_equipment(form) -> tuple[Equipment | None, str | None]:
|
||||
hostname = (form.get("hostname") or "").strip()
|
||||
if not hostname:
|
||||
return None, "Hostname requis."
|
||||
|
||||
eq_type = form.get("type", "Server")
|
||||
if eq_type not in ALLOWED_TYPES:
|
||||
return None, f"Type invalide : {eq_type}."
|
||||
|
||||
ip = (form.get("ip_address") or "").strip() or "255.255.255.0"
|
||||
is_active = form.get("is_active") == "on"
|
||||
|
||||
latency_raw = (form.get("latency") or "").strip()
|
||||
latency = None
|
||||
if latency_raw:
|
||||
try:
|
||||
latency = float(latency_raw)
|
||||
if latency < 0:
|
||||
return None, "Latence doit être positive."
|
||||
except ValueError:
|
||||
return None, "Latence invalide."
|
||||
|
||||
ports = form.getlist("ports[]")
|
||||
services = form.getlist("services[]")
|
||||
interfaces: list[Interface] = []
|
||||
for port_raw, service in zip(ports, services):
|
||||
if not port_raw:
|
||||
continue
|
||||
try:
|
||||
port = int(port_raw)
|
||||
if not (0 <= port <= 65535):
|
||||
return None, f"Port invalide : {port_raw}."
|
||||
except ValueError:
|
||||
return None, f"Port non numérique : {port_raw}."
|
||||
if not service.strip():
|
||||
return None, "Service requis pour chaque interface."
|
||||
interfaces.append(Interface(port=port, service=service.strip()))
|
||||
|
||||
return Equipment(
|
||||
hostname=hostname,
|
||||
type=eq_type,
|
||||
ip_address=ip,
|
||||
is_active=is_active,
|
||||
latency=latency,
|
||||
interfaces=interfaces,
|
||||
), None
|
||||
|
||||
def _equipment_to_dict(eq: Equipment) -> dict:
|
||||
return {
|
||||
"id": eq.id,
|
||||
"hostname": eq.hostname,
|
||||
"type": eq.type,
|
||||
"ip_address": eq.ip_address,
|
||||
"is_active": eq.is_active,
|
||||
"latency": eq.latency,
|
||||
"interfaces": [
|
||||
{"id": i.id, "port": i.port, "service": i.service}
|
||||
for i in eq.interfaces
|
||||
],
|
||||
}
|
||||
|
||||
# Partie FRONT
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/equipments', methods=['GET'])
|
||||
def equipments_page():
|
||||
equipments = fetch_all_equipments()
|
||||
return render_template('equipments.html', equipments=equipments, types=sorted(ALLOWED_TYPES))
|
||||
|
||||
@app.route('/equipments', methods=['POST'])
|
||||
def create_equipment_form():
|
||||
eq, err = _parse_form_equipment(request.form)
|
||||
if err:
|
||||
flash(err, "error")
|
||||
return redirect(url_for('equipments_page'))
|
||||
insert_equipment(eq)
|
||||
flash(f"Équipement « {eq.hostname} » créé.", "success")
|
||||
return redirect(url_for('equipments_page'))
|
||||
|
||||
@app.route('/equipments/<int:equipment_id>/toggle', methods=['POST'])
|
||||
def toggle_equipment(equipment_id: int):
|
||||
eq = fetch_equipment_by_id(equipment_id)
|
||||
if eq is None:
|
||||
flash(f"Équipement {equipment_id} introuvable.", "error")
|
||||
return redirect(url_for('equipments_page'))
|
||||
eq.is_active = not eq.is_active
|
||||
update_equipment(eq)
|
||||
flash(f"État de « {eq.hostname} » mis à jour.", "success")
|
||||
return redirect(url_for('equipments_page'))
|
||||
|
||||
@app.route('/equipments/<int:equipment_id>/delete', methods=['POST'])
|
||||
def delete_equipment_form(equipment_id: int):
|
||||
eq = fetch_equipment_by_id(equipment_id)
|
||||
if eq is None:
|
||||
flash(f"Équipement {equipment_id} introuvable.", "error")
|
||||
return redirect(url_for('equipments_page'))
|
||||
delete_equipment(equipment_id)
|
||||
flash(f"Équipement « {eq.hostname} » supprimé.", "success")
|
||||
return redirect(url_for('equipments_page'))
|
||||
|
||||
# Partie API
|
||||
|
||||
@app.get("/api/equipments")
|
||||
def list_equipments_api():
|
||||
return jsonify([_equipment_to_dict(eq) for eq in fetch_all_equipments()])
|
||||
|
||||
@app.get("/api/equipments/<int:equipment_id>")
|
||||
def get_equipment_api(equipment_id: int):
|
||||
eq = fetch_equipment_by_id(equipment_id)
|
||||
if eq is None:
|
||||
return jsonify({"error": "Équipement introuvable."}), 404
|
||||
return jsonify(_equipment_to_dict(eq))
|
||||
|
||||
@app.post("/api/equipments")
|
||||
def create_equipment_api():
|
||||
data = request.get_json(silent=True) or {}
|
||||
hostname = (data.get("hostname") or "").strip()
|
||||
if not hostname:
|
||||
return jsonify({"error": "Hostname requis."}), 400
|
||||
eq_type = data.get("type", "Server")
|
||||
if eq_type not in ALLOWED_TYPES:
|
||||
return jsonify({"error": f"Type invalide : {eq_type}."}), 400
|
||||
eq = Equipment(
|
||||
hostname=hostname,
|
||||
type=eq_type,
|
||||
ip_address=(data.get("ip_address") or "255.255.255.0").strip(),
|
||||
is_active=bool(data.get("is_active", True)),
|
||||
latency=data.get("latency"),
|
||||
interfaces=[],
|
||||
)
|
||||
new_id = insert_equipment(eq)
|
||||
eq.id = new_id
|
||||
return jsonify(_equipment_to_dict(eq)), 201
|
||||
|
||||
@app.put("/api/equipments/<int:equipment_id>")
|
||||
def update_equipment_api(equipment_id: int):
|
||||
eq = fetch_equipment_by_id(equipment_id)
|
||||
if eq is None:
|
||||
return jsonify({"error": f"Équipement {equipment_id} introuvable."}), 404
|
||||
|
||||
data = request.get_json(silent=True) or {}
|
||||
hostname = (data.get("hostname") or "").strip()
|
||||
if not hostname:
|
||||
return jsonify({"error": "Hostname requis."}), 400
|
||||
|
||||
eq_type = data.get("type", "Server")
|
||||
if eq_type not in ALLOWED_TYPES:
|
||||
return jsonify({"error": f"Type invalide : {eq_type}."}), 400
|
||||
|
||||
latency = data.get("latency")
|
||||
if latency is not None:
|
||||
try:
|
||||
latency = float(latency)
|
||||
if latency < 0:
|
||||
return jsonify({"error": "Latence doit être positive."}), 400
|
||||
except (ValueError, TypeError):
|
||||
return jsonify({"error": "Latence invalide."}), 400
|
||||
|
||||
eq.hostname = hostname
|
||||
eq.type = eq_type
|
||||
eq.ip_address = (data.get("ip_address") or "255.255.255.0").strip()
|
||||
eq.is_active = bool(data.get("is_active", True))
|
||||
eq.latency = latency
|
||||
|
||||
update_equipment(eq)
|
||||
return jsonify(_equipment_to_dict(eq)), 200
|
||||
|
||||
@app.patch("/api/equipments/<int:equipment_id>/toggle")
|
||||
def toggle_equipment_api(equipment_id: int):
|
||||
eq = fetch_equipment_by_id(equipment_id)
|
||||
if eq is None:
|
||||
return jsonify({"error": f"Équipement {equipment_id} introuvable."}), 404
|
||||
eq.is_active = not eq.is_active
|
||||
update_equipment(eq)
|
||||
return jsonify(_equipment_to_dict(eq)), 200
|
||||
|
||||
@app.delete("/api/equipments/<int:equipment_id>")
|
||||
def delete_equipment_api(equipment_id: int):
|
||||
eq = fetch_equipment_by_id(equipment_id)
|
||||
if eq is None:
|
||||
return jsonify({"error": f"Équipement {equipment_id} introuvable."}), 404
|
||||
delete_equipment(equipment_id)
|
||||
return jsonify({"message": f"Équipement « {eq.hostname} » supprimé."}), 200
|
||||
|
||||
if __name__ == '__main__':
|
||||
host = os.environ.get("FLASK_HOST", "127.0.0.1")
|
||||
port = int(os.environ.get("FLASK_PORT", "5000"))
|
||||
|
||||
if prompt_reset():
|
||||
reset_database()
|
||||
print("Base réinitialisée.")
|
||||
else:
|
||||
init_database()
|
||||
|
||||
app.run(host=host, port=port, debug=app.config["DEBUG"])
|
||||
Reference in New Issue
Block a user