New Plugins: - USB plugin: Device checkout/checkin with employee lookup, checkout history - Notifications plugin: Announcements with types, scheduling, shopfloor display - Network plugin: Network device management with subnets and VLANs - Equipment and Computers plugins: Asset type separation Frontend: - EmployeeSearch component: Reusable employee lookup with autocomplete - USB views: List, detail, checkout/checkin modals - Notifications views: List, form with recognition mode - Network views: Device list, detail, form - Calendar view with FullCalendar integration - Shopfloor and TV dashboard views - Reports index page - Map editor for asset positioning - Light/dark mode fixes for map tooltips Backend: - Employee search API with external lookup service - Collector API for PowerShell data collection - Reports API endpoints - Slides API for TV dashboard - Fixed AppVersion model (removed BaseModel inheritance) - Added checkout_name column to usbcheckouts table Styling: - Unified detail page styles - Improved pagination (page numbers instead of prev/next) - Dark/light mode theme improvements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
147 lines
4.1 KiB
Python
147 lines
4.1 KiB
Python
"""Subnet and VLAN models for network plugin."""
|
|
|
|
from shopdb.extensions import db
|
|
from shopdb.core.models.base import BaseModel
|
|
|
|
|
|
class VLAN(BaseModel):
|
|
"""
|
|
VLAN definition.
|
|
|
|
Represents a virtual LAN for network segmentation.
|
|
"""
|
|
__tablename__ = 'vlans'
|
|
|
|
vlanid = db.Column(db.Integer, primary_key=True)
|
|
vlannumber = db.Column(db.Integer, unique=True, nullable=False, comment='VLAN ID number')
|
|
name = db.Column(db.String(100), nullable=False, comment='VLAN name')
|
|
description = db.Column(db.Text, nullable=True)
|
|
|
|
# Optional classification
|
|
vlantype = db.Column(
|
|
db.String(50),
|
|
nullable=True,
|
|
comment='Type: data, voice, management, guest, etc.'
|
|
)
|
|
|
|
# Relationships
|
|
subnets = db.relationship('Subnet', backref='vlan', lazy='dynamic')
|
|
|
|
__table_args__ = (
|
|
db.Index('idx_vlan_number', 'vlannumber'),
|
|
)
|
|
|
|
def __repr__(self):
|
|
return f"<VLAN {self.vlannumber} - {self.name}>"
|
|
|
|
def to_dict(self):
|
|
"""Convert to dictionary."""
|
|
result = super().to_dict()
|
|
result['subnetcount'] = self.subnets.count() if self.subnets else 0
|
|
return result
|
|
|
|
|
|
class Subnet(BaseModel):
|
|
"""
|
|
Subnet/IP network definition.
|
|
|
|
Represents an IP subnet with optional VLAN association.
|
|
"""
|
|
__tablename__ = 'subnets'
|
|
|
|
subnetid = db.Column(db.Integer, primary_key=True)
|
|
|
|
# Network definition
|
|
cidr = db.Column(
|
|
db.String(18),
|
|
unique=True,
|
|
nullable=False,
|
|
comment='CIDR notation (e.g., 10.1.1.0/24)'
|
|
)
|
|
name = db.Column(db.String(100), nullable=False, comment='Subnet name')
|
|
description = db.Column(db.Text, nullable=True)
|
|
|
|
# Network details
|
|
gatewayip = db.Column(
|
|
db.String(15),
|
|
nullable=True,
|
|
comment='Default gateway IP address'
|
|
)
|
|
subnetmask = db.Column(
|
|
db.String(15),
|
|
nullable=True,
|
|
comment='Subnet mask (e.g., 255.255.255.0)'
|
|
)
|
|
networkaddress = db.Column(
|
|
db.String(15),
|
|
nullable=True,
|
|
comment='Network address (e.g., 10.1.1.0)'
|
|
)
|
|
broadcastaddress = db.Column(
|
|
db.String(15),
|
|
nullable=True,
|
|
comment='Broadcast address (e.g., 10.1.1.255)'
|
|
)
|
|
|
|
# VLAN association
|
|
vlanid = db.Column(
|
|
db.Integer,
|
|
db.ForeignKey('vlans.vlanid'),
|
|
nullable=True
|
|
)
|
|
|
|
# Classification
|
|
subnettype = db.Column(
|
|
db.String(50),
|
|
nullable=True,
|
|
comment='Type: production, development, management, dmz, etc.'
|
|
)
|
|
|
|
# Location association
|
|
locationid = db.Column(
|
|
db.Integer,
|
|
db.ForeignKey('locations.locationid'),
|
|
nullable=True
|
|
)
|
|
|
|
# DHCP settings
|
|
dhcpenabled = db.Column(db.Boolean, default=True, comment='DHCP enabled for this subnet')
|
|
dhcprangestart = db.Column(db.String(15), nullable=True, comment='DHCP range start IP')
|
|
dhcprangeend = db.Column(db.String(15), nullable=True, comment='DHCP range end IP')
|
|
|
|
# DNS settings
|
|
dns1 = db.Column(db.String(15), nullable=True, comment='Primary DNS server')
|
|
dns2 = db.Column(db.String(15), nullable=True, comment='Secondary DNS server')
|
|
|
|
# Relationships
|
|
location = db.relationship('Location', backref='subnets')
|
|
|
|
__table_args__ = (
|
|
db.Index('idx_subnet_cidr', 'cidr'),
|
|
db.Index('idx_subnet_vlan', 'vlanid'),
|
|
db.Index('idx_subnet_location', 'locationid'),
|
|
)
|
|
|
|
def __repr__(self):
|
|
return f"<Subnet {self.cidr} - {self.name}>"
|
|
|
|
@property
|
|
def vlan_number(self):
|
|
"""Get the VLAN number."""
|
|
return self.vlan.vlannumber if self.vlan else None
|
|
|
|
def to_dict(self):
|
|
"""Convert to dictionary with related data."""
|
|
result = super().to_dict()
|
|
|
|
# Add VLAN info
|
|
if self.vlan:
|
|
result['vlannumber'] = self.vlan.vlannumber
|
|
result['vlanname'] = self.vlan.name
|
|
|
|
# Add location info
|
|
if self.location:
|
|
result['locationname'] = self.location.locationname
|
|
|
|
return result
|