diff --git a/Data/Engine/interfaces/http/devices.py b/Data/Engine/interfaces/http/devices.py index 4c10c2c..5523575 100644 --- a/Data/Engine/interfaces/http/devices.py +++ b/Data/Engine/interfaces/http/devices.py @@ -64,6 +64,12 @@ def get_device_by_guid(guid: str) -> object: return jsonify(device) +@blueprint.route("/api/device/details/", methods=["GET"]) +def get_device_details(hostname: str) -> object: + payload = _inventory().get_device_details(hostname) + return jsonify(payload) + + @blueprint.route("/api/device/description/", methods=["POST"]) def set_device_description(hostname: str) -> object: payload = request.get_json(silent=True) or {} diff --git a/Data/Engine/services/devices/device_inventory_service.py b/Data/Engine/services/devices/device_inventory_service.py index e06208e..862ca28 100644 --- a/Data/Engine/services/devices/device_inventory_service.py +++ b/Data/Engine/services/devices/device_inventory_service.py @@ -75,6 +75,70 @@ class DeviceInventoryService: devices = self._repo.fetch_devices(hostname=snapshot.get("hostname")) return devices[0] if devices else None + def get_device_details(self, hostname: str) -> Dict[str, object]: + normalized_host = clean_device_str(hostname) + if not normalized_host: + return {} + + snapshot = self._repo.load_snapshot(hostname=normalized_host) + if not snapshot: + return {} + + summary = dict(snapshot.get("summary") or {}) + + payload: Dict[str, Any] = { + "details": snapshot.get("details", {}), + "summary": summary, + "description": snapshot.get("description") + or summary.get("description") + or "", + "created_at": snapshot.get("created_at") or 0, + "agent_hash": snapshot.get("agent_hash") + or summary.get("agent_hash") + or "", + "agent_guid": snapshot.get("agent_guid") + or summary.get("agent_guid") + or "", + "memory": snapshot.get("memory", []), + "network": snapshot.get("network", []), + "software": snapshot.get("software", []), + "storage": snapshot.get("storage", []), + "cpu": snapshot.get("cpu", {}), + "device_type": snapshot.get("device_type") + or summary.get("device_type") + or "", + "domain": snapshot.get("domain") + or summary.get("domain") + or "", + "external_ip": snapshot.get("external_ip") + or summary.get("external_ip") + or "", + "internal_ip": snapshot.get("internal_ip") + or summary.get("internal_ip") + or "", + "last_reboot": snapshot.get("last_reboot") + or summary.get("last_reboot") + or "", + "last_seen": snapshot.get("last_seen") + or summary.get("last_seen") + or 0, + "last_user": snapshot.get("last_user") + or summary.get("last_user") + or "", + "operating_system": snapshot.get("operating_system") + or summary.get("operating_system") + or summary.get("agent_operating_system") + or "", + "uptime": snapshot.get("uptime") + or summary.get("uptime") + or 0, + "agent_id": snapshot.get("agent_id") + or summary.get("agent_id") + or "", + } + + return payload + def collect_agent_hash_records(self) -> List[Dict[str, object]]: records: List[Dict[str, object]] = [] key_to_index: Dict[str, int] = {} diff --git a/Data/Engine/tests/test_http_sites_devices.py b/Data/Engine/tests/test_http_sites_devices.py index 2afe32a..99322f3 100644 --- a/Data/Engine/tests/test_http_sites_devices.py +++ b/Data/Engine/tests/test_http_sites_devices.py @@ -1,3 +1,4 @@ +import json from datetime import datetime, timezone import sqlite3 import time @@ -149,3 +150,89 @@ def test_device_description_update(prepared_app, engine_settings): assert row is not None assert row[0] == "Primary workstation" + + +def test_device_details_returns_inventory(prepared_app, engine_settings): + client = prepared_app.test_client() + _ensure_admin_session(client) + + hostname = "inventory-1" + guid = "B9F0A1C2-D3E4-5F67-890A-BCDEF1234567" + now = int(time.time()) + + memory = [{"slot": "DIMM1", "size_gb": 16}] + network = [{"name": "Ethernet", "mac": "AA:BB:CC:DD:EE:FF"}] + software = [{"name": "Agent", "version": "1.0.0"}] + storage = [{"model": "Disk", "size_gb": 512}] + cpu = {"model": "Intel", "cores": 8} + + conn = sqlite3.connect(engine_settings.database.path) + cur = conn.cursor() + cur.execute( + """ + INSERT INTO devices ( + guid, + hostname, + description, + created_at, + agent_hash, + memory, + network, + software, + storage, + cpu, + device_type, + domain, + external_ip, + internal_ip, + last_reboot, + last_seen, + last_user, + operating_system, + uptime, + agent_id + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + guid, + hostname, + "Workstation", + now, + "hashvalue", + json.dumps(memory), + json.dumps(network), + json.dumps(software), + json.dumps(storage), + json.dumps(cpu), + "Laptop", + "ACME", + "203.0.113.10", + "192.0.2.10", + "2024-01-01 12:00:00", + now, + "ACME\\tech", + "Windows 11", + 7200, + "agent-001", + ), + ) + conn.commit() + conn.close() + + resp = client.get(f"/api/device/details/{hostname}") + assert resp.status_code == 200 + data = resp.get_json() + + assert data["memory"] == memory + assert data["network"] == network + assert data["software"] == software + assert data["storage"] == storage + assert data["cpu"] == cpu + assert data["description"] == "Workstation" + assert data["agent_hash"] == "hashvalue" + assert data["agent_guid"].lower() == guid.lower() + assert data["last_user"] == "ACME\\tech" + assert data["operating_system"] == "Windows 11" + assert data["uptime"] == 7200 + assert data["summary"]["hostname"] == hostname + assert data["details"]["memory"] == memory