Protection multi-postes + reorganisation dashboard Vision

Imposing Tool :
- Genere un ID machine unique (hash hostname + MAC)
- Envoie machine_id + hostname NetBIOS au check de licence
- Bloque si nombre max de postes atteint

Vision (LXC 112) :
- Table license_devices (machine_id, hostname, first/last_seen)
- Colonne max_devices dans licenses (defaut 1)
- API : verifie le nombre de postes, enregistre chaque device
- API : endpoint devices (liste + suppression par poste)
- Dashboard : colonne "Postes" cliquable (X/max) avec modal
- Modal devices : liste des postes avec hostname, suppression
- Champ "Postes max" dans le modal licence
- Onglet 1 = Licences (copycaisse + imposing unifies)
- Onglet 2 = Clients (gestion clients)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jules
2026-03-20 13:23:04 +01:00
parent bd309a07aa
commit 057b6c1d3c

28
main.py
View File

@@ -21,10 +21,34 @@ sys.path.insert(0, BUNDLE_DIR)
from PyQt6.QtWidgets import QApplication, QInputDialog, QMessageBox, QLineEdit
import hashlib
import platform
import socket
import uuid
LICENSE_API = "https://vision.copydev.fr/api/license.php"
LICENSE_FILE = os.path.join(BASE_DIR, ".license")
def _get_machine_id():
"""Generer un identifiant unique pour cette machine."""
raw = ""
try:
raw += platform.node()
raw += str(uuid.getnode()) # MAC address
except Exception:
raw += "unknown"
return hashlib.sha256(raw.encode()).hexdigest()[:32]
def _get_hostname():
"""Recuperer le nom NetBIOS / hostname."""
try:
return platform.node() or socket.gethostname()
except Exception:
return "inconnu"
def _load_license_cache():
"""Charger le cache de licence local."""
if not os.path.exists(LICENSE_FILE):
@@ -48,7 +72,9 @@ def _save_license_cache(data):
def _check_license_online(key):
"""Verifier la licence aupres du serveur Vision."""
try:
url = f"{LICENSE_API}?key={urllib.parse.quote(key)}"
mid = _get_machine_id()
hname = _get_hostname()
url = f"{LICENSE_API}?key={urllib.parse.quote(key)}&machine_id={urllib.parse.quote(mid)}&hostname={urllib.parse.quote(hname)}"
req = urllib.request.Request(url, headers={"User-Agent": "CopydevImposingTool/1.0"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode())