Initial commit — Server_Monitorizare_v2
This commit is contained in:
170
app/api/wmt.py
Normal file
170
app/api/wmt.py
Normal file
@@ -0,0 +1,170 @@
|
||||
"""
|
||||
WMT (Workstation Management Terminal) configuration API
|
||||
Handles config distribution and device update requests from WMT clients.
|
||||
"""
|
||||
from flask import Blueprint, request, jsonify
|
||||
from datetime import datetime
|
||||
from app.models import WMTGlobalConfig, Device, WMTUpdateRequest
|
||||
from config.database_config import get_db
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
wmt_api_bp = Blueprint('wmt_api', __name__, url_prefix='/api/wmt')
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _get_or_create_global_config(session):
|
||||
"""Return the single WMTGlobalConfig row, creating it with defaults if absent."""
|
||||
cfg = session.query(WMTGlobalConfig).first()
|
||||
if cfg is None:
|
||||
cfg = WMTGlobalConfig()
|
||||
session.add(cfg)
|
||||
session.flush()
|
||||
return cfg
|
||||
|
||||
|
||||
def _latest_config_ts(session, mac_address):
|
||||
"""Return timestamps for global config and this device's admin-reviewed info."""
|
||||
global_cfg = session.query(WMTGlobalConfig).first()
|
||||
global_ts = global_cfg.updated_at if global_cfg and global_cfg.updated_at else datetime(1970, 1, 1)
|
||||
|
||||
device = session.query(Device).filter_by(mac_address=mac_address).first()
|
||||
# Use info_reviewed_at as the authoritative device-level timestamp
|
||||
device_ts = device.info_reviewed_at if device and device.info_reviewed_at else datetime(1970, 1, 1)
|
||||
|
||||
latest = max(global_ts, device_ts)
|
||||
return global_ts, device_ts, latest
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Endpoints
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@wmt_api_bp.route('/config/timestamp', methods=['GET'])
|
||||
def get_config_timestamp():
|
||||
"""
|
||||
Returns the last-modified timestamps for global config and this device's config.
|
||||
Query param: mac=<mac_address>
|
||||
|
||||
Response:
|
||||
{
|
||||
"global_updated_at": "2026-04-22T10:00:00",
|
||||
"device_updated_at": "2026-04-22T09:00:00", // null if device unknown
|
||||
"latest_updated_at": "2026-04-22T10:00:00"
|
||||
}
|
||||
"""
|
||||
mac = request.args.get('mac', '').strip().lower()
|
||||
if not mac:
|
||||
return jsonify({'error': 'mac query parameter is required'}), 400
|
||||
|
||||
try:
|
||||
with get_db().get_session() as session:
|
||||
global_ts, device_info_reviewed_ts, latest = _latest_config_ts(session, mac)
|
||||
|
||||
return jsonify({
|
||||
'global_updated_at': global_ts.isoformat() if global_ts != datetime(1970, 1, 1) else None,
|
||||
'device_info_reviewed_at': device_info_reviewed_ts.isoformat() if device_info_reviewed_ts != datetime(1970, 1, 1) else None,
|
||||
'latest_updated_at': latest.isoformat(),
|
||||
}), 200
|
||||
except Exception as e:
|
||||
logger.error(f'Error getting WMT config timestamp: {e}')
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@wmt_api_bp.route('/config/<mac_address>', methods=['GET'])
|
||||
def get_device_config(mac_address):
|
||||
"""
|
||||
Returns merged config (global settings + device-specific) for a given MAC.
|
||||
Used by WMT client to pull updated config at startup.
|
||||
|
||||
Response: merged dict consumable by the WMT config.txt writer.
|
||||
"""
|
||||
mac = mac_address.strip().lower()
|
||||
try:
|
||||
with get_db().get_session() as session:
|
||||
global_cfg = _get_or_create_global_config(session)
|
||||
device = session.query(Device).filter_by(mac_address=mac).first()
|
||||
|
||||
# Update last_seen if device is known
|
||||
if device:
|
||||
device.last_seen = datetime.utcnow()
|
||||
|
||||
_, device_ts, latest_ts = _latest_config_ts(session, mac)
|
||||
|
||||
payload = {
|
||||
# Global settings
|
||||
'chrome_url': global_cfg.chrome_url,
|
||||
'chrome_local_url': global_cfg.chrome_local_url or '',
|
||||
'chrome_insecure_origin': global_cfg.chrome_insecure_origin,
|
||||
'card_api_base_url': global_cfg.card_api_base_url,
|
||||
'server_log_url': global_cfg.server_log_url,
|
||||
'internet_check_host': global_cfg.internet_check_host,
|
||||
'update_host': global_cfg.update_host,
|
||||
'update_user': global_cfg.update_user,
|
||||
# Device-specific settings (empty string if unknown)
|
||||
'device_name': device.device_name if device else '',
|
||||
'hostname': device.hostname if device else '',
|
||||
'device_ip': device.device_ip if device else '',
|
||||
'location': device.location if device else '',
|
||||
# Admin-review timestamp for device info (client stores in [device] section)
|
||||
'info_reviewed_at': device.info_reviewed_at.isoformat() if (device and device.info_reviewed_at) else '1970-01-01T00:00:00',
|
||||
# Sync metadata
|
||||
'config_updated_at': latest_ts.isoformat(),
|
||||
}
|
||||
return jsonify(payload), 200
|
||||
except Exception as e:
|
||||
logger.error(f'Error fetching WMT config for {mac}: {e}')
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@wmt_api_bp.route('/config/update_request', methods=['POST'])
|
||||
def submit_update_request():
|
||||
"""
|
||||
WMT client sends current device info as an update request for admin approval.
|
||||
|
||||
Expected JSON:
|
||||
{
|
||||
"mac_address": "b8:27:eb:aa:bb:cc",
|
||||
"device_name": "Masa-01",
|
||||
"hostname": "rpi-masa01",
|
||||
"device_ip": "192.168.1.100",
|
||||
"client_config_mtime": "2026-04-22T09:30:00" // optional
|
||||
}
|
||||
"""
|
||||
if not request.is_json:
|
||||
return jsonify({'error': 'Content-Type must be application/json'}), 400
|
||||
|
||||
data = request.get_json()
|
||||
mac = (data.get('mac_address') or '').strip().lower()
|
||||
if not mac:
|
||||
return jsonify({'error': 'mac_address is required'}), 400
|
||||
|
||||
try:
|
||||
with get_db().get_session() as session:
|
||||
device = session.query(Device).filter_by(mac_address=mac).first()
|
||||
|
||||
req = WMTUpdateRequest(
|
||||
mac_address=mac,
|
||||
device_id=device.id if device else None,
|
||||
proposed_device_name=data.get('device_name'),
|
||||
proposed_hostname=data.get('hostname'),
|
||||
proposed_device_ip=data.get('device_ip'),
|
||||
client_config_mtime=data.get('client_config_mtime'),
|
||||
submitted_at=datetime.utcnow(),
|
||||
status='pending',
|
||||
)
|
||||
session.add(req)
|
||||
|
||||
# Update device last_seen
|
||||
if device:
|
||||
device.last_seen = datetime.utcnow()
|
||||
|
||||
logger.info(f'WMT update request received from {mac}')
|
||||
return jsonify({'status': 'received', 'message': 'Update request queued for admin review'}), 201
|
||||
except Exception as e:
|
||||
logger.error(f'Error saving WMT update request from {mac}: {e}')
|
||||
return jsonify({'error': str(e)}), 500
|
||||
Reference in New Issue
Block a user