Initial commit: Shop Database Flask Application

Flask backend with Vue 3 frontend for shop floor machine management.
Includes database schema export for MySQL shopdb_flask database.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-01-13 16:07:34 -05:00
commit 1196de6e88
188 changed files with 19921 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
"""Zabbix service for real-time printer supply lookups."""
import logging
from typing import Dict, List, Optional
import requests
from flask import current_app
logger = logging.getLogger(__name__)
class ZabbixService:
"""
Zabbix API service for real-time printer supply lookups.
Queries Zabbix by IP address to get current supply levels.
No caching - always returns live data.
"""
def __init__(self):
self._url = None
self._token = None
@property
def isconfigured(self) -> bool:
"""Check if Zabbix is configured."""
self._url = current_app.config.get('ZABBIX_URL')
self._token = current_app.config.get('ZABBIX_TOKEN')
return bool(self._url and self._token)
def _apicall(self, method: str, params: Dict) -> Optional[Dict]:
"""Make a Zabbix API call."""
if not self.isconfigured:
return None
payload = {
'jsonrpc': '2.0',
'method': method,
'params': params,
'auth': self._token,
'id': 1
}
try:
response = requests.post(
f"{self._url}/api_jsonrpc.php",
json=payload,
headers={'Content-Type': 'application/json'},
timeout=10
)
response.raise_for_status()
data = response.json()
if 'error' in data:
logger.error(f"Zabbix API error: {data['error']}")
return None
return data.get('result')
except requests.RequestException as e:
logger.error(f"Zabbix API request failed: {e}")
return None
def gethostbyip(self, ip: str) -> Optional[Dict]:
"""Find a Zabbix host by IP address."""
result = self._apicall('host.get', {
'output': ['hostid', 'host', 'name'],
'filter': {'ip': ip},
'selectInterfaces': ['ip']
})
if result:
return result[0] if result else None
return None
def getsuppliesbyip(self, ip: str) -> Optional[List[Dict]]:
"""
Get printer supply levels by IP address.
Returns list of supplies with name and level percentage.
"""
# Find host by IP
host = self.gethostbyip(ip)
if not host:
logger.debug(f"No Zabbix host found for IP {ip}")
return None
hostid = host['hostid']
# Get supply-related items
items = self._apicall('item.get', {
'output': ['itemid', 'name', 'lastvalue', 'key_'],
'hostids': hostid,
'search': {
'key_': 'supply' # Common key pattern for printer supplies
},
'searchWildcardsEnabled': True
})
if not items:
# Try alternate patterns
items = self._apicall('item.get', {
'output': ['itemid', 'name', 'lastvalue', 'key_'],
'hostids': hostid,
'search': {
'name': 'toner'
},
'searchWildcardsEnabled': True
})
if not items:
return []
supplies = []
for item in items:
try:
level = int(float(item.get('lastvalue', 0)))
except (ValueError, TypeError):
level = 0
supplies.append({
'name': item.get('name', 'Unknown'),
'level': level,
'itemid': item.get('itemid'),
'key': item.get('key_'),
})
return supplies
def gethostid(self, ip: str) -> Optional[str]:
"""Get Zabbix host ID for an IP address."""
host = self.gethostbyip(ip)
return host['hostid'] if host else None