Semaine 11

This commit is contained in:
gauvainboiche
2026-07-11 21:38:00 +02:00
parent d3d2416dea
commit 0d071d2843
281 changed files with 54412 additions and 0 deletions
+234
View File
@@ -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"])