diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 41505a8a..cb24baa8 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -297,10 +297,13 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm): system_uuid = self.get_uuid(debug) if system_uuid: snapshot_json['device']['system_uuid'] = system_uuid + self.get_fields_extra(debug, snapshot_json) try: snapshot_json = schema.load(snapshot_json) response = self.build(snapshot_json) + response.device.set_hid() + response.device.binding.device.set_hid() except ValidationError as err: txt = "{}".format(err) self.errors(txt=txt) diff --git a/ereuse_devicehub/migrations/versions/564952310b17_add_vendor_family_in_device.py b/ereuse_devicehub/migrations/versions/564952310b17_add_vendor_family_in_device.py new file mode 100644 index 00000000..c1484d66 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/564952310b17_add_vendor_family_in_device.py @@ -0,0 +1,35 @@ +"""add vendor family in device + +Revision ID: 564952310b17 +Revises: d65745749e34 +Create Date: 2022-11-14 13:12:22.916848 + +""" +import citext +import sqlalchemy as sa +from alembic import context, op + +# revision identifiers, used by Alembic. +revision = '564952310b17' +down_revision = 'd65745749e34' +branch_labels = None +depends_on = None + + +def get_inv(): + INV = context.get_x_argument(as_dictionary=True).get('inventory') + if not INV: + raise ValueError("Inventory value is not specified") + return INV + + +def upgrade(): + op.add_column( + 'device', + sa.Column('family', citext.CIText(), nullable=True), + schema=f'{get_inv()}', + ) + + +def downgrade(): + op.drop_column('device', 'family', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/parser/parser.py b/ereuse_devicehub/parser/parser.py index 49e7dee6..91d0f103 100644 --- a/ereuse_devicehub/parser/parser.py +++ b/ereuse_devicehub/parser/parser.py @@ -547,6 +547,12 @@ class ParseSnapshotLsHw: return action + def get_hid_datas(self): + self.device.family = self.get_family() + + def get_family(self): + return self.dmi.get("System", [{}])[0].get("Family", '') + def errors(self, txt=None, severity=Severity.Error): if not txt: return self._errors diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 87a9d392..a5121748 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -2008,7 +2008,7 @@ def update_components_action_one(target: ActionWithOneDevice, device: Device, __ if isinstance(device, Computer): target.components |= device.components elif isinstance(device, Computer): - device.add_mac_to_hid() + device.set_hid() @event.listens_for( diff --git a/ereuse_devicehub/resources/action/views/snapshot.py b/ereuse_devicehub/resources/action/views/snapshot.py index dd967fee..52cb3d5c 100644 --- a/ereuse_devicehub/resources/action/views/snapshot.py +++ b/ereuse_devicehub/resources/action/views/snapshot.py @@ -72,9 +72,7 @@ class SnapshotMixin: if snapshot_json['software'] == ( SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid ): - components = snapshot_json.pop('components', None) # type: List[Component] - if isinstance(device, Computer) and device.hid: - device.add_mac_to_hid(components_snap=components) + components = snapshot_json.pop('components', None) snapshot = Snapshot(**snapshot_json) # Remove new actions from devices so they don't interfere with sync @@ -151,6 +149,30 @@ class SnapshotMixin: uuid = UUID(hw_uuid) return UUID(bytes_le=uuid.bytes) + def get_fields_extra(self, debug, snapshot_json): + if not debug or not isinstance(debug, dict): + return + + lshw = debug.get('lshw', {}) + + family = lshw.get('configuration', {}).get('family', '') + + snapshot_json['device']['family'] = family + + # lshw_mothers = [] + # for mt in lshw.get('children', []): + # if mt.get('description') == "Motherboard": + # lshw_mothers.append(mt) + + # for comp in snapshot_json.get('components', []): + # if comp.get('type') != 'Motherboard': + # continue + # for mt in lshw_mothers: + # if comp['serialNumber'] == mt.get('serial', ''): + # comp['vendor'] = mt.get('vendor', '') + # comp['product'] = mt.get('product', '') + # comp['version'] = mt.get('version', '') + def errors(self, txt=None, severity=Severity.Error, snapshot=None, commit=False): if not txt: return @@ -187,10 +209,13 @@ class SnapshotView(SnapshotMixin): self.version = snapshot_json.get('version') self.uuid = snapshot_json.get('uuid') self.sid = None - system_uuid = self.get_uuid(snapshot_json.pop('debug', None)) + self.debug = snapshot_json.pop('debug', {}) + system_uuid = self.get_uuid(self.debug) if system_uuid: snapshot_json['device']['system_uuid'] = system_uuid + self.get_fields_extra(self.debug, snapshot_json) + try: self.snapshot_json = resource_def.schema.load(snapshot_json) snapshot = self.build() diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 86d8c834..a23488cf 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1,4 +1,5 @@ import copy +import hashlib import pathlib from contextlib import suppress from fractions import Fraction @@ -181,6 +182,7 @@ class Device(Thing): dhid_bk = db.Column(db.CIText(), nullable=True, unique=False) phid_bk = db.Column(db.CIText(), nullable=True, unique=False) active = db.Column(Boolean, default=True) + family = db.Column(db.CIText()) _NON_PHYSICAL_PROPS = { 'id', @@ -201,6 +203,7 @@ class Device(Thing): 'production_date', 'variant', 'version', + 'family', 'sku', 'image', 'allocated', @@ -735,10 +738,69 @@ class Device(Thing): return "" def set_hid(self): + """ + # product_vendor, + # product_family, + # product_chassis, + # product_number, + # product_version, + # product_sku, + # product_serial, + # product_uuid, + # board_vendor, + # board_number, + # board_serial, + # board_version + """ with suppress(TypeError): - self.hid = Naming.hid( - self.type, self.manufacturer, self.model, self.serial_number - ) + family = (self.family or '').replace(' ', '_') + chassis = self.type + if hasattr(self, 'chassis'): + chassis = self.chassis and self.chassis.name or '' + version = (self.version or '').replace(' ', '_') + sku = (self.sku or '').replace(' ', '_') + system_uuid = '' + if hasattr(self, 'system_uuid'): + system_uuid = str(self.system_uuid or '') + + board = None + board_serial_number = '' + board_version = '' + board_manufacturer = '' + board_model = '' + + if hasattr(self, 'components'): + for c in self.components: + if c.type == 'Motherboard': + board = c + break + + if board: + board_manufacturer = (board.manufacturer or '').replace(' ', '_') + board_model = (board.model or '').replace(' ', '_') + board_serial_number = (board.serial_number or '').replace(' ', '_') + board_version = (board.version or '').replace(' ', '_') + + self.hid = '-'.join( + [ + (self.manufacturer or '').replace(' ', '_'), + family, + chassis, + (self.model or '').replace(' ', '_'), + version, + sku, + self.serial_number, + system_uuid, + board_manufacturer, + board_model, + board_serial_number, + board_version, + ] + ).lower() + + def get_hid(self): + if self.hid: + return hashlib.sha3_512(self.hid.encode()).hexdigest() def last_action_of(self, *types): """Gets the last action of the given types. @@ -1119,6 +1181,7 @@ class Computer(Device): """Returns the Naming.hid with the first mac of network adapter, following an alphabetical order. """ + return self.set_hid() if not self.hid: return diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index 890dd287..c217b3dd 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -120,6 +120,7 @@ class Device(Thing): dhid = SanitizedStr( data_key='devicehubID', description=m.Device.devicehub_id.comment ) + family = SanitizedStr(validate=Length(max=STR_BIG_SIZE)) @pre_load def from_actions_to_actions_one(self, data: dict): diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py index 6896089c..3aa9d9ff 100644 --- a/ereuse_devicehub/resources/device/views.py +++ b/ereuse_devicehub/resources/device/views.py @@ -302,7 +302,7 @@ class DeviceMergeView(View): setattr(self.base_device, field_name, value) self.base_device.hid = self.with_device.hid - self.base_device.add_mac_to_hid() + self.base_device.set_hid() class ManufacturerView(View): diff --git a/ereuse_devicehub/resources/lot/models.py b/ereuse_devicehub/resources/lot/models.py index 461e7c69..051cf08c 100644 --- a/ereuse_devicehub/resources/lot/models.py +++ b/ereuse_devicehub/resources/lot/models.py @@ -93,6 +93,10 @@ class Lot(Thing): ) receiver = db.relationship(User, primaryjoin=receiver_address == User.email) + # __table_args__ = ( + # {'schema': 'dbtest'}, + # ) + def __init__( self, name: str, closed: bool = closed.default.arg, description: str = None ) -> None: