"""USB device plugin models.""" from datetime import datetime from shopdb.extensions import db from shopdb.core.models.base import BaseModel, AuditMixin class USBDeviceType(BaseModel): """ USB device type classification. Examples: Flash Drive, External HDD, External SSD, Card Reader """ __tablename__ = 'usbdevicetypes' usbdevicetypeid = db.Column(db.Integer, primary_key=True) typename = db.Column(db.String(50), unique=True, nullable=False) description = db.Column(db.Text) icon = db.Column(db.String(50), default='usb', comment='Icon name for UI') def __repr__(self): return f"" class USBDevice(BaseModel, AuditMixin): """ USB device model. Tracks USB storage devices that can be checked out by users. """ __tablename__ = 'usbdevices' usbdeviceid = db.Column(db.Integer, primary_key=True) # Identification serialnumber = db.Column(db.String(100), unique=True, nullable=False) label = db.Column(db.String(100), nullable=True, comment='Human-readable label') assetnumber = db.Column(db.String(50), nullable=True, comment='Optional asset tag') # Classification usbdevicetypeid = db.Column( db.Integer, db.ForeignKey('usbdevicetypes.usbdevicetypeid'), nullable=True ) # Specifications capacitygb = db.Column(db.Integer, nullable=True, comment='Capacity in GB') vendorid = db.Column(db.String(10), nullable=True, comment='USB Vendor ID (hex)') productid = db.Column(db.String(10), nullable=True, comment='USB Product ID (hex)') manufacturer = db.Column(db.String(100), nullable=True) productname = db.Column(db.String(100), nullable=True) # Current status ischeckedout = db.Column(db.Boolean, default=False) currentuserid = db.Column(db.String(50), nullable=True, comment='SSO of current user') currentusername = db.Column(db.String(100), nullable=True, comment='Name of current user') currentcheckoutdate = db.Column(db.DateTime, nullable=True) # Location storagelocation = db.Column(db.String(200), nullable=True, comment='Where device is stored when not checked out') # Security pin = db.Column(db.String(50), nullable=True, comment='PIN for encrypted devices') # Notes notes = db.Column(db.Text, nullable=True) # Relationships devicetype = db.relationship('USBDeviceType', backref='devices') # Indexes __table_args__ = ( db.Index('idx_usb_serial', 'serialnumber'), db.Index('idx_usb_checkedout', 'ischeckedout'), db.Index('idx_usb_type', 'usbdevicetypeid'), db.Index('idx_usb_currentuser', 'currentuserid'), ) def __repr__(self): return f"" @property def display_name(self): """Get display name (label if set, otherwise serial number).""" return self.label or self.serialnumber def to_dict(self): """Convert to dictionary with related data.""" result = super().to_dict() # Add type info if self.devicetype: result['typename'] = self.devicetype.typename result['typeicon'] = self.devicetype.icon # Add computed property result['displayname'] = self.display_name return result class USBCheckout(BaseModel): """ USB device checkout history. Tracks when devices are checked out and returned. Maps to existing usbcheckouts table from classic ShopDB. """ __tablename__ = 'usbcheckouts' checkoutid = db.Column(db.Integer, primary_key=True) # Device reference (new column linking to usbdevices table) usbdeviceid = db.Column( db.Integer, db.ForeignKey('usbdevices.usbdeviceid', ondelete='CASCADE'), nullable=True ) # Legacy reference to machines table (kept for backward compatibility) machineid = db.Column(db.Integer, nullable=False) # User info sso = db.Column(db.String(20), nullable=False, comment='SSO of user') checkout_name = db.Column(db.String(100), nullable=True, comment='Name of user') # Checkout details checkout_time = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) checkin_time = db.Column(db.DateTime, nullable=True) # Metadata checkout_reason = db.Column(db.Text, nullable=True, comment='Reason for checkout') checkin_notes = db.Column(db.Text, nullable=True) was_wiped = db.Column(db.Boolean, nullable=True, comment='Was device wiped after return') # Relationships device = db.relationship('USBDevice', backref=db.backref('checkouts', lazy='dynamic')) def __repr__(self): return f"" @property def is_active(self): """Check if this checkout is currently active (not returned).""" return self.checkin_time is None @property def duration_days(self): """Get duration of checkout in days.""" end = self.checkin_time or datetime.utcnow() delta = end - self.checkout_time return delta.days def to_dict(self): """Convert to dictionary with computed fields.""" result = super().to_dict() result['isactivecheckout'] = self.is_active result['durationdays'] = self.duration_days # Add device info if loaded if self.device: result['devicelabel'] = self.device.label result['deviceserialnumber'] = self.device.serialnumber return result