"""Dashboard default model: display-PC-IP -> display role (+ business unit). A single "display" PC image resolves what it should show from its own IP: the role (shopfloor dashboard, lobby slideshow, or 3D-parts kiosk) and, for the dashboard role, which business unit. Powers the visitor-location + display-role lookups the kiosks call at launch. """ from shopdb.extensions import db from .base import BaseModel # Display role -> the frontend kiosk path it maps to. Kept here so the API and # any consumer resolve a role to a URL the same way. DISPLAY_ROLE_PATHS = { 'dashboard': '/shopfloor', 'lobby': '/tv', 'partskiosk': '/parts-kiosk', } DISPLAY_ROLES = tuple(DISPLAY_ROLE_PATHS.keys()) # GE device naming: a PC's DNS name is 'F' + its BIOS serial under the device # domain, e.g. FABC1234.device.geaerospace.net. The domain is a setting so other # sites can point elsewhere; the collector already reports the serial, so the # server derives the stable FQDN without the kiosk having to report it. DEFAULT_DISPLAY_FQDN_DOMAIN = 'device.geaerospace.net' def derive_display_fqdn(serialnumber): """FQDN for a display PC from its BIOS serial: F. (lower). Returns None when there is no serial. Domain from the display_fqdn_domain setting, falling back to DEFAULT_DISPLAY_FQDN_DOMAIN. """ serial = (serialnumber or '').strip() if not serial: return None from .setting import Setting domain = (Setting.get('display_fqdn_domain', DEFAULT_DISPLAY_FQDN_DOMAIN) or DEFAULT_DISPLAY_FQDN_DOMAIN).strip().strip('.') return f'F{serial}.{domain}'.lower() class DashboardDefault(BaseModel): """Maps a display PC (by FQDN, or IP) to its display role (+ location).""" __tablename__ = 'dashboarddefaults' dashboarddefaultid = db.Column(db.Integer, primary_key=True) # A mapping is keyed by FQDN (stable, DHCP-proof) and/or IP. At least one is # required (enforced in the API). FQDN is preferred; IP is the fallback for a # manual entry or a PC not yet reporting a serial. # 191 = the utf8mb4-safe unique-index length (191*4 < 767) so the index does # not depend on innodb_large_prefix; FQDNs (F.) fit easily. fqdn = db.Column(db.String(191), unique=True, nullable=True, index=True) ipaddress = db.Column(db.String(50), unique=True, nullable=True) # Which display the mapping drives. Only the dashboard role uses businessunitid. displayrole = db.Column(db.String(20), nullable=False, default='dashboard') businessunitid = db.Column( db.Integer, db.ForeignKey('businessunits.businessunitid'), nullable=True ) description = db.Column(db.String(255)) businessunit = db.relationship('BusinessUnit') @property def displaypath(self): return DISPLAY_ROLE_PATHS.get(self.displayrole) def __repr__(self): return f" {self.displayrole}>"