Files
Server_Monitorizare_v2/app/api/wmt.py
2026-04-23 15:55:46 +03:00

171 lines
6.7 KiB
Python

"""
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