From 236fcac0b81b45aa06c783e1920977b0a76c6120 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 16 Nov 2022 11:51:31 +0100 Subject: [PATCH 01/39] add new hid in devices --- ereuse_devicehub/inventory/forms.py | 3 + ...64952310b17_add_vendor_family_in_device.py | 35 ++++++++++ ereuse_devicehub/parser/parser.py | 6 ++ ereuse_devicehub/resources/action/models.py | 2 +- .../resources/action/views/snapshot.py | 33 +++++++-- ereuse_devicehub/resources/device/models.py | 69 ++++++++++++++++++- ereuse_devicehub/resources/device/schemas.py | 1 + ereuse_devicehub/resources/device/views.py | 2 +- ereuse_devicehub/resources/lot/models.py | 4 ++ 9 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 ereuse_devicehub/migrations/versions/564952310b17_add_vendor_family_in_device.py 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: From d030ed9b239804a3da11fab258608df8a44341ae Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 16 Nov 2022 13:47:50 +0100 Subject: [PATCH 02/39] set_old_hid --- ereuse_devicehub/resources/device/models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index a23488cf..3df44688 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -802,6 +802,12 @@ class Device(Thing): if self.hid: return hashlib.sha3_512(self.hid.encode()).hexdigest() + def set_old_hid(self): + with suppress(TypeError): + self.hid = Naming.hid( + self.type, self.manufacturer, self.model, self.serial_number + ) + def last_action_of(self, *types): """Gets the last action of the given types. @@ -1181,7 +1187,6 @@ 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 From 81b28b2663d7d532b0f7702f1f294c33e0507f52 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 16 Nov 2022 13:48:19 +0100 Subject: [PATCH 03/39] add script --- scripts/create_new_hid.py | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 scripts/create_new_hid.py diff --git a/scripts/create_new_hid.py b/scripts/create_new_hid.py new file mode 100644 index 00000000..0be8c5c1 --- /dev/null +++ b/scripts/create_new_hid.py @@ -0,0 +1,46 @@ +import json +import sys + +from ereuse_devicehub.db import db +from ereuse_devicehub.devicehub import Devicehub +from ereuse_devicehub.resources.action.models import Snapshot + + +def open_snapshot(): + path = sys.argv[2] + f = open(path) + txt = f.read() + return json.loads(txt) + + +def get_family(snapshot): + debug = snapshot.get('debug', {}) + lshw = debug.get('lshw', {}) + return lshw.get('configuration', {}).get('family', '') + + +def get_device(uuid): + snapshot = Snapshot.query.filter_by(uuid=uuid).first() + if snapshot: + return snapshot.device + + +def main(): + schema = sys.argv[1] + app = Devicehub(inventory=schema) + app.app_context().push() + snapshot = open_snapshot() + uuid = snapshot.get('uuid') + if not uuid: + return + family = get_family(snapshot) + device = get_device(uuid) + if not device: + return + device.family = family + device.set_hid() + db.session.commit() + + +if __name__ == '__main__': + main() From f0ffe27671023c1280ee86b3111df3e66bc8d4f7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 16 Nov 2022 17:40:35 +0100 Subject: [PATCH 04/39] fix device set_hid --- ereuse_devicehub/api/views.py | 2 ++ ereuse_devicehub/resources/action/views/snapshot.py | 2 ++ ereuse_devicehub/resources/device/sync.py | 1 + 3 files changed, 5 insertions(+) diff --git a/ereuse_devicehub/api/views.py b/ereuse_devicehub/api/views.py index c566be00..23414b38 100644 --- a/ereuse_devicehub/api/views.py +++ b/ereuse_devicehub/api/views.py @@ -58,6 +58,8 @@ class InventoryView(LoginMixin, SnapshotMixin): self.snapshot_json = ParseSnapshotLsHw(snapshot_json).get_snapshot() snapshot = self.build() + snapshot.device.set_hid() + snapshot.device.binding.device.set_hid() db.session.add(snapshot) snap_log = SnapshotsLog( diff --git a/ereuse_devicehub/resources/action/views/snapshot.py b/ereuse_devicehub/resources/action/views/snapshot.py index 52cb3d5c..b3c4d744 100644 --- a/ereuse_devicehub/resources/action/views/snapshot.py +++ b/ereuse_devicehub/resources/action/views/snapshot.py @@ -219,6 +219,8 @@ class SnapshotView(SnapshotMixin): try: self.snapshot_json = resource_def.schema.load(snapshot_json) snapshot = self.build() + snapshot.device.set_hid() + snapshot.device.binding.device.set_hid() except Exception as err: txt = "{}".format(err) self.errors(txt=txt, commit=True) diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 613f0b39..65731583 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -86,6 +86,7 @@ class Sync: if motherboard: for c in db_device.components: if c.type == "Motherboard" and motherboard.hid != c.hid: + # import pdb; pdb.set_trace() raise ValidationError(err_motherboard) db_components, actions = OrderedSet(), OrderedSet() From 9b08c083cee4b1a6a63a414f46872f0c43ec384d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 16 Nov 2022 17:40:59 +0100 Subject: [PATCH 05/39] set hid to components --- scripts/create_new_hid.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/create_new_hid.py b/scripts/create_new_hid.py index 0be8c5c1..3e9ff4ff 100644 --- a/scripts/create_new_hid.py +++ b/scripts/create_new_hid.py @@ -39,6 +39,14 @@ def main(): return device.family = family device.set_hid() + for c in device.components: + c.set_hid() + + if device.binding: + device.binding.device.family = family + device.binding.device.set_hid() + for c in device.binding.device.components: + c.set_hid() db.session.commit() From 905716f74bbeba82b407445f46bf48444dec8c60 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 18 Nov 2022 10:20:57 +0100 Subject: [PATCH 06/39] fix live view --- ereuse_devicehub/resources/action/views/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/action/views/views.py b/ereuse_devicehub/resources/action/views/views.py index afbeb665..25814b4a 100644 --- a/ereuse_devicehub/resources/action/views/views.py +++ b/ereuse_devicehub/resources/action/views/views.py @@ -142,11 +142,14 @@ class LiveView(View): return hid if macs: mac = "-{mac}".format(mac=macs[0]) - hid += mac + # hid += mac return hid def live(self, snapshot): """If the device.allocated == True, then this snapshot create an action live.""" + for c in snapshot['components']: + c.parent = snapshot['device'] + snapshot['device'].set_hid() hid = self.get_hid(snapshot) if not hid or not Device.query.filter(Device.hid == hid).count(): raise ValidationError('Device not exist.') From 94a586f00b6d6f07ca6dd6c24c89f858b6301f1a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 2 Dec 2022 10:08:03 +0100 Subject: [PATCH 07/39] filter correct values --- ereuse_devicehub/resources/device/models.py | 17 +++++++++-------- ereuse_devicehub/resources/device/schemas.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 61e8cae7..a983643b 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -747,13 +747,13 @@ class Device(Thing): def set_hid(self): """ - # product_vendor, - # product_family, - # product_chassis, - # product_number, + # product_vendor, is a manufacturer + # product_family, is a model but from dmidecode + # product_chassis, is a type of chassis + # product_number, is a ?? # product_version, # product_sku, - # product_serial, + # product_serial, is a serial number # product_uuid, # board_vendor, # board_number, @@ -762,6 +762,8 @@ class Device(Thing): """ with suppress(TypeError): family = (self.family or '').replace(' ', '_') + model = ((self.model or '').replace(' ', '_'),) + model = model or family chassis = self.type if hasattr(self, 'chassis'): chassis = self.chassis and self.chassis.name or '' @@ -792,12 +794,11 @@ class Device(Thing): self.hid = '-'.join( [ (self.manufacturer or '').replace(' ', '_'), - family, + model, chassis, - (self.model or '').replace(' ', '_'), + self.serial_number, version, sku, - self.serial_number, system_uuid, board_manufacturer, board_model, diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index 76a1fee2..604da213 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -208,6 +208,21 @@ class Computer(Device): receiver_id = UUID(data_key='receiverID') system_uuid = UUID(required=False) + @post_load + def validate_hid(self, data): + """Validates than exist model manufacturer and system_uuid.""" + + minimum = [ + data['manufacturer'], + data['model'], + data['system_uuid'], + ] + + if not all(minimum): + txt = 'You can not register one device with out minimum datas, ' + txt += 'you can to do one placeholder.' + raise ValidationError(txt) + class Desktop(Computer): __doc__ = m.Desktop.__doc__ From e3f01f4795547fe733a3174e985cc00e226ef216 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 5 Dec 2022 09:58:12 +0100 Subject: [PATCH 08/39] fix --- ereuse_devicehub/resources/device/models.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index a983643b..8e8f7fa1 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -748,9 +748,9 @@ class Device(Thing): def set_hid(self): """ # product_vendor, is a manufacturer - # product_family, is a model but from dmidecode + # product_family, is a new field of lshw # product_chassis, is a type of chassis - # product_number, is a ?? + # product_number, is a model # product_version, # product_sku, # product_serial, is a serial number @@ -763,7 +763,6 @@ class Device(Thing): with suppress(TypeError): family = (self.family or '').replace(' ', '_') model = ((self.model or '').replace(' ', '_'),) - model = model or family chassis = self.type if hasattr(self, 'chassis'): chassis = self.chassis and self.chassis.name or '' From 4b13995b4f4aabe540015b917431776e13cce367 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 5 Dec 2022 12:40:26 +0100 Subject: [PATCH 09/39] . --- ereuse_devicehub/resources/device/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 8e8f7fa1..3b8aef05 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -747,6 +747,7 @@ class Device(Thing): def set_hid(self): """ + The order is important # product_vendor, is a manufacturer # product_family, is a new field of lshw # product_chassis, is a type of chassis @@ -793,11 +794,12 @@ class Device(Thing): self.hid = '-'.join( [ (self.manufacturer or '').replace(' ', '_'), - model, + family, chassis, - self.serial_number, + model, version, sku, + self.serial_number, system_uuid, board_manufacturer, board_model, From d6bee33601f9cdb84c91868bab5cde7cff4fd66c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 5 Dec 2022 17:33:22 +0100 Subject: [PATCH 10/39] fix new hid in build --- ereuse_devicehub/inventory/forms.py | 2 -- ereuse_devicehub/resources/action/views/snapshot.py | 10 ++++++++-- ereuse_devicehub/resources/device/models.py | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 0769796d..8d6f0b8b 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -318,8 +318,6 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm): 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/resources/action/views/snapshot.py b/ereuse_devicehub/resources/action/views/snapshot.py index b3c4d744..16a89bed 100644 --- a/ereuse_devicehub/resources/action/views/snapshot.py +++ b/ereuse_devicehub/resources/action/views/snapshot.py @@ -8,6 +8,7 @@ from uuid import UUID from flask import current_app as app from flask import g +from marshmallow import ValidationError from sqlalchemy.util import OrderedSet from ereuse_devicehub.db import db @@ -115,6 +116,13 @@ class SnapshotMixin: self.is_server_erase(snapshot) + snapshot.device.set_hid() + snapshot.device.binding.device.set_hid() + if not snapshot.device.hid: + txt = "Not exist the basic fields for to do an device. " + txt += "Please do one placeholder instead of one snapshot" + raise ValidationError(txt) + return snapshot def is_server_erase(self, snapshot): @@ -219,8 +227,6 @@ class SnapshotView(SnapshotMixin): try: self.snapshot_json = resource_def.schema.load(snapshot_json) snapshot = self.build() - snapshot.device.set_hid() - snapshot.device.binding.device.set_hid() except Exception as err: txt = "{}".format(err) self.errors(txt=txt, commit=True) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 3b8aef05..82adf8e7 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -772,6 +772,8 @@ class Device(Thing): system_uuid = '' if hasattr(self, 'system_uuid'): system_uuid = str(self.system_uuid or '') + if not system_uuid or not self.manufacturer: + return '' board = None board_serial_number = '' From 5e8cf78751ad4f62c8783c89c96bcfe6c8f06400 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 5 Dec 2022 19:17:54 +0100 Subject: [PATCH 11/39] put the forze of validation in the schemas --- .../versions/564952310b17_add_vendor_family_in_device.py | 4 ++-- ereuse_devicehub/resources/action/views/snapshot.py | 5 ----- ereuse_devicehub/resources/device/schemas.py | 6 +++--- 3 files changed, 5 insertions(+), 10 deletions(-) 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 index c1484d66..f37ae2f3 100644 --- a/ereuse_devicehub/migrations/versions/564952310b17_add_vendor_family_in_device.py +++ b/ereuse_devicehub/migrations/versions/564952310b17_add_vendor_family_in_device.py @@ -1,7 +1,7 @@ """add vendor family in device Revision ID: 564952310b17 -Revises: d65745749e34 +Revises: af038a8a388c Create Date: 2022-11-14 13:12:22.916848 """ @@ -11,7 +11,7 @@ from alembic import context, op # revision identifiers, used by Alembic. revision = '564952310b17' -down_revision = 'd65745749e34' +down_revision = 'af038a8a388c' branch_labels = None depends_on = None diff --git a/ereuse_devicehub/resources/action/views/snapshot.py b/ereuse_devicehub/resources/action/views/snapshot.py index 16a89bed..c5df4838 100644 --- a/ereuse_devicehub/resources/action/views/snapshot.py +++ b/ereuse_devicehub/resources/action/views/snapshot.py @@ -8,7 +8,6 @@ from uuid import UUID from flask import current_app as app from flask import g -from marshmallow import ValidationError from sqlalchemy.util import OrderedSet from ereuse_devicehub.db import db @@ -118,10 +117,6 @@ class SnapshotMixin: snapshot.device.set_hid() snapshot.device.binding.device.set_hid() - if not snapshot.device.hid: - txt = "Not exist the basic fields for to do an device. " - txt += "Please do one placeholder instead of one snapshot" - raise ValidationError(txt) return snapshot diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index 604da213..e34502f5 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -213,9 +213,9 @@ class Computer(Device): """Validates than exist model manufacturer and system_uuid.""" minimum = [ - data['manufacturer'], - data['model'], - data['system_uuid'], + data.get('manufacturer'), + data.get('model'), + data.get('system_uuid'), ] if not all(minimum): From 4debac4fbe6d0fe5a43f874bb15b636cb0f0d051 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 12 Dec 2022 10:36:33 +0100 Subject: [PATCH 12/39] fix dummy --- ereuse_devicehub/dummy/dummy.py | 3 +++ ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml | 1 + .../dummy/files/asus-eee-1000h.snapshot.11.yaml | 1 + .../dummy/files/dell-optiplexgx520.snapshot.11.yaml | 1 + ereuse_devicehub/dummy/files/hp1.snapshot.11.yaml | 1 + ereuse_devicehub/dummy/files/hp2.snapshot.11.yaml | 1 + .../dummy/files/laptop-with-2-hid.snapshot.11.yaml | 1 + .../dummy/files/lenovo-3493BAG.snapshot.11.yaml | 1 + ereuse_devicehub/dummy/files/nec.snapshot.11.yaml | 1 + ereuse_devicehub/dummy/files/oreo.snapshot.yaml | 6 +++--- ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml | 2 +- .../dummy/files/real-eee-1001pxd.snapshot.11.yaml | 1 + .../dummy/files/real-hp-quad-core.snapshot.11.yaml | 1 + ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml | 1 + ereuse_devicehub/dummy/files/real-toshiba.snapshot.11.yaml | 1 + 15 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py index ee7f7c15..ec276de4 100644 --- a/ereuse_devicehub/dummy/dummy.py +++ b/ereuse_devicehub/dummy/dummy.py @@ -1,5 +1,6 @@ import itertools import json +import uuid from pathlib import Path import click @@ -113,6 +114,8 @@ class Dummy: for path in bar: with path.open() as f: snapshot = yaml.load(f) + if snapshot['device']['type'] in ['Desktop', 'Laptop']: + snapshot['device']['system_uuid'] = uuid.uuid4() s, _ = user1.post(res=m.Snapshot, data=self.json_encode(snapshot)) if s.get('uuid', None) == 'ec23c11b-80b6-42cd-ac5c-73ba7acddbc4': sample_pc = s['device']['id'] diff --git a/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml b/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml index f3f907fa..866fc8cc 100644 --- a/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/asus-1001pxd.snapshot.11.yaml @@ -178,6 +178,7 @@ ], "type": "Laptop" }, + "debug": {"lshw": {"configuration": {"uuid": "79c5098f-bc44-4834-8a59-9ea61d956c31"}}}, "elapsed": 14725, "endTime": "2018-11-24T18:06:37.611704+00:00", "software": "Workbench", diff --git a/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml b/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml index f3c848e1..ae5a268e 100644 --- a/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/asus-eee-1000h.snapshot.11.yaml @@ -119,6 +119,7 @@ "manufacturer": "ASUSTeK Computer INC." } ], + "debug": {"lshw": {"configuration": {"uuid": "645f00bf-1ec0-4fdb-9608-b5ac73e285f6"}}}, "version": "11.0a4", "elapsed": 6, "endTime": "2016-11-03T17:17:17.266543+00:00" diff --git a/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml b/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml index 98b23bb8..625884b3 100644 --- a/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/dell-optiplexgx520.snapshot.11.yaml @@ -148,6 +148,7 @@ "model": "0UG982" } ], + "debug": {"lshw": {"configuration": {"uuid": "5dcdd380-5a54-48bc-99bf-aff6019e8491"}}}, "version": "11.0a3", "closed": false, "elapsed": 1512, diff --git a/ereuse_devicehub/dummy/files/hp1.snapshot.11.yaml b/ereuse_devicehub/dummy/files/hp1.snapshot.11.yaml index 86489428..95311cbe 100644 --- a/ereuse_devicehub/dummy/files/hp1.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/hp1.snapshot.11.yaml @@ -132,5 +132,6 @@ "model": "HP Compaq 8100 Elite SFF", "manufacturer": "Hewlett-Packard" }, + "debug": {"lshw": {"configuration": {"uuid": "f6cfe48a-93d5-4e94-ab7b-3ee371e4d048"}}}, "version": "11.0a3" } diff --git a/ereuse_devicehub/dummy/files/hp2.snapshot.11.yaml b/ereuse_devicehub/dummy/files/hp2.snapshot.11.yaml index 80591b42..1e263ce6 100644 --- a/ereuse_devicehub/dummy/files/hp2.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/hp2.snapshot.11.yaml @@ -170,5 +170,6 @@ }, "software": "Workbench", "endTime": "2018-07-11T10:30:22.395958+00:00", + "debug": {"lshw": {"configuration": {"uuid": "75dcb454-ae80-4a87-a192-185d3b0250c0"}}}, "elapsed": 2766 } diff --git a/ereuse_devicehub/dummy/files/laptop-with-2-hid.snapshot.11.yaml b/ereuse_devicehub/dummy/files/laptop-with-2-hid.snapshot.11.yaml index 8cf37d51..8ca0798a 100644 --- a/ereuse_devicehub/dummy/files/laptop-with-2-hid.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/laptop-with-2-hid.snapshot.11.yaml @@ -146,6 +146,7 @@ "pcmcia": 0 } ], + "debug": {"lshw": {"configuration": {"uuid": "fcaf784e-5e57-43a2-b03f-8c56dabd0415"}}}, "uuid": "a01eacdb-db01-43ec-b6fb-a9b8cd21492d", "type": "Snapshot", "version": "11.0a4", diff --git a/ereuse_devicehub/dummy/files/lenovo-3493BAG.snapshot.11.yaml b/ereuse_devicehub/dummy/files/lenovo-3493BAG.snapshot.11.yaml index c73871ad..e7fb82f0 100644 --- a/ereuse_devicehub/dummy/files/lenovo-3493BAG.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/lenovo-3493BAG.snapshot.11.yaml @@ -4,6 +4,7 @@ "closed": false, "endTime": "2018-07-11T13:26:29.365504+00:00", "type": "Snapshot", + "debug": {"lshw": {"configuration": {"uuid": "4f256440-e43f-429a-a2c6-1e8f3365de56"}}}, "device": { "serialNumber": "PB357N0", "actions": [ diff --git a/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml b/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml index d846eb7a..5ec32875 100644 --- a/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/nec.snapshot.11.yaml @@ -148,6 +148,7 @@ "slots": 4 } ], + "debug": {"lshw": {"configuration": {"uuid": "077cad5d-ae1b-4156-a9a1-98bca6fa5c35"}}}, "version": "11.0a3", "endTime": "2018-07-11T10:28:55.879745+00:00", "type": "Snapshot", diff --git a/ereuse_devicehub/dummy/files/oreo.snapshot.yaml b/ereuse_devicehub/dummy/files/oreo.snapshot.yaml index 348c9420..1e3da274 100644 --- a/ereuse_devicehub/dummy/files/oreo.snapshot.yaml +++ b/ereuse_devicehub/dummy/files/oreo.snapshot.yaml @@ -136,8 +136,8 @@ ], "elapsed": 203, "device": { - "manufacturer": null, - "model": null, + "manufacturer": "Asus", + "model": "P7P55D", "chassis": "Tower", "type": "Desktop", "serialNumber": null, @@ -158,7 +158,7 @@ ] }, "version": "11.0a6", - + "debug": {"lshw": {"configuration": {"uuid": "59ca9a2a-65bd-4802-89bb-315156a9352b"}}}, "type": "Snapshot", "closed": true, "software": "Workbench" diff --git a/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml b/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml index a4f76e6f..86127bc1 100644 --- a/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml @@ -142,7 +142,7 @@ }, "elapsed": 238, "endTime": "2018-10-15T13:59:37.431309+00:00", - + "debug": {"lshw": {"configuration": {"uuid": "43686b8e-e1ae-4e4e-bc51-f98f51e97c2d"}}}, "software": "Workbench", "type": "Snapshot", "uuid": "ec23c11b-80b6-42cd-ac5c-73ba7acddbc4", diff --git a/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml b/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml index a807c7f0..5a90e00a 100644 --- a/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/real-eee-1001pxd.snapshot.11.yaml @@ -158,5 +158,6 @@ } ] }, + "debug": {"lshw": {"configuration": {"uuid": "a0cef731-9a78-4087-889c-dfb6ba5c2e9b"}}}, "closed": false } diff --git a/ereuse_devicehub/dummy/files/real-hp-quad-core.snapshot.11.yaml b/ereuse_devicehub/dummy/files/real-hp-quad-core.snapshot.11.yaml index 91aa12d6..8d921acd 100644 --- a/ereuse_devicehub/dummy/files/real-hp-quad-core.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/real-hp-quad-core.snapshot.11.yaml @@ -114,6 +114,7 @@ } ], "version": "11.0a3", + "debug": {"lshw": {"configuration": {"uuid": "f2c50acd-501a-4f0b-b07c-58254b2ab8c9"}}}, "device": { "type": "Desktop", "model": "HP Compaq 8000 Elite SFF", diff --git a/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml b/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml index 7158225e..8f9b2333 100644 --- a/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/real-hp.snapshot.11.yaml @@ -1,6 +1,7 @@ { "closed": false, "uuid": "f9e5e587-baee-44e1-9a94-255d216bbda9", + "debug": {"lshw": {"configuration": {"uuid": "4d21dd26-aa45-4902-a5f2-8a06e364cf25"}}}, "components": [ { "actions": [], diff --git a/ereuse_devicehub/dummy/files/real-toshiba.snapshot.11.yaml b/ereuse_devicehub/dummy/files/real-toshiba.snapshot.11.yaml index 1a274d30..db83c5b2 100644 --- a/ereuse_devicehub/dummy/files/real-toshiba.snapshot.11.yaml +++ b/ereuse_devicehub/dummy/files/real-toshiba.snapshot.11.yaml @@ -131,6 +131,7 @@ "model": "NB200" }, "uuid": "918726ae-c6bc-40aa-97cf-ad80d69268f9", + "debug": {"lshw": {"configuration": {"uuid": "33627ef0-89a9-4659-bb29-faa936727e0b"}}}, "closed": false, "type": "Snapshot" } From fac6380bcf5cd5ac13edd83db66020daa8cd306c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 12 Dec 2022 14:10:17 +0100 Subject: [PATCH 13/39] . --- ereuse_devicehub/resources/device/models.py | 15 +++++++++++++-- ereuse_devicehub/resources/device/schemas.py | 15 --------------- ereuse_devicehub/resources/device/sync.py | 15 +++------------ 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 82adf8e7..df331e70 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -745,7 +745,7 @@ class Device(Thing): return "" - def set_hid(self): + def set_new_hid(self): """ The order is important # product_vendor, is a manufacturer @@ -814,7 +814,18 @@ class Device(Thing): if self.hid: return hashlib.sha3_512(self.hid.encode()).hexdigest() - def set_old_hid(self): + def get_from_db(self): + if not self.hid: + return + + return Device.query.filter_by( + hid=self.hid, + owner_id=g.user.id, + active=True, + placeholder=None, + ).first() + + def set_hid(self): with suppress(TypeError): self.hid = Naming.hid( self.type, self.manufacturer, self.model, self.serial_number diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index e34502f5..76a1fee2 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -208,21 +208,6 @@ class Computer(Device): receiver_id = UUID(data_key='receiverID') system_uuid = UUID(required=False) - @post_load - def validate_hid(self, data): - """Validates than exist model manufacturer and system_uuid.""" - - minimum = [ - data.get('manufacturer'), - data.get('model'), - data.get('system_uuid'), - ] - - if not all(minimum): - txt = 'You can not register one device with out minimum datas, ' - txt += 'you can to do one placeholder.' - raise ValidationError(txt) - class Desktop(Computer): __doc__ = m.Desktop.__doc__ diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 65731583..f88a62ba 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -212,19 +212,10 @@ class Sync: placeholder=None, ).one() # if no there are any Computer by uuid search by hid - if not db_device and device.hid: - with suppress(ResourceNotFound): - db_device = Device.query.filter_by( - hid=device.hid, - owner_id=g.user.id, - active=True, - placeholder=None, - ).one() + if not db_device: + db_device = device.get_from_db() elif device.hid: - with suppress(ResourceNotFound): - db_device = Device.query.filter_by( - hid=device.hid, owner_id=g.user.id, active=True, placeholder=None - ).one() + db_device = device.get_from_db() if db_device and db_device.allocated: raise ResourceNotFound('device is actually allocated {}'.format(device)) From 756925d65766190826d2a50f4b7d9842b0619a70 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 13 Dec 2022 14:02:38 +0100 Subject: [PATCH 14/39] migrations and get_from_db --- .../93daff872771_add_hash_hid_to_device.py | 67 +++++++++++++++++++ ereuse_devicehub/resources/device/sync.py | 25 ++----- 2 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py diff --git a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py new file mode 100644 index 00000000..e6c436d9 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py @@ -0,0 +1,67 @@ +"""add hash hid to device + +Revision ID: 93daff872771 +Revises: 564952310b17 +Create Date: 2022-12-13 10:14:45.500087 + +""" +from alembic import context, op +import sqlalchemy as sa +import citext +import hashlib + + +# revision identifiers, used by Alembic. +revision = '93daff872771' +down_revision = '564952310b17' +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_data(): + con = op.get_bind() + sql = f"update {get_inv()}.computer set user_trusts='t';" + con.execute(sql) + + dev_sql = f"select id, hid from {get_inv()}.device;" + for d in con.execute(dev_sql): + if not d.hid: + continue + dev_id = d.id + chid = hashlib.sha3_256(d.hid.encode('utf-8')).hexdigest() + sql = f"update {get_inv()}.device set chid={chid} where id={dev_id};" + + +def upgrade(): + op.add_column( + 'computer', + sa.Column('user_trusts', sa.Boolean(), default=True, nullable=True), + schema=f'{get_inv()}', + ) + + op.add_column( + 'device', + sa.Column('chid', citext.CIText(), nullable=True), + schema=f'{get_inv()}', + ) + + upgrade_data() + + op.alter_column( + 'computer', + 'user_trusts', + nullable=False, + schema=f'{get_inv()}' + ) + + +def downgrade(): + op.drop_column('computer', 'user_trusts', schema=f'{get_inv()}') + op.drop_column('device', 'chid', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index f88a62ba..189d6468 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -1,6 +1,5 @@ import copy import difflib -from contextlib import suppress from itertools import groupby from typing import Iterable, Set @@ -16,13 +15,18 @@ from ereuse_devicehub.db import db from ereuse_devicehub.resources.action.models import Remove from ereuse_devicehub.resources.device.models import ( Component, - Computer, DataStorage, Device, Placeholder, ) from ereuse_devicehub.resources.tag.model import Tag +try: + from modules.device.models import Computer +except: + from ereuse_devicehub.resources.device.models import Computer + + DEVICES_ALLOW_DUPLICITY = [ 'RamModule', 'Display', @@ -200,22 +204,7 @@ class Sync: assert all( inspect(tag).transient for tag in device.tags ), 'Tags cannot be synced from DB' - db_device = None - if isinstance(device, Computer): - # first search by uuid - if device.system_uuid: - with suppress(ResourceNotFound): - db_device = Computer.query.filter_by( - system_uuid=device.system_uuid, - owner_id=g.user.id, - active=True, - placeholder=None, - ).one() - # if no there are any Computer by uuid search by hid - if not db_device: - db_device = device.get_from_db() - elif device.hid: - db_device = device.get_from_db() + db_device = device.get_from_db() if db_device and db_device.allocated: raise ResourceNotFound('device is actually allocated {}'.format(device)) From 27910f2c20ee458cedeb5f90ef45d93f5096c49f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 13 Dec 2022 14:25:44 +0100 Subject: [PATCH 15/39] clean --- ereuse_devicehub/resources/device/sync.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 189d6468..650d8036 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -15,18 +15,12 @@ from ereuse_devicehub.db import db from ereuse_devicehub.resources.action.models import Remove from ereuse_devicehub.resources.device.models import ( Component, - DataStorage, + Computer, Device, Placeholder, ) from ereuse_devicehub.resources.tag.model import Tag -try: - from modules.device.models import Computer -except: - from ereuse_devicehub.resources.device.models import Computer - - DEVICES_ALLOW_DUPLICITY = [ 'RamModule', 'Display', From da1feef74636c359594503e9f08fe69172181700 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 13 Dec 2022 14:29:52 +0100 Subject: [PATCH 16/39] fix migration --- .../93daff872771_add_hash_hid_to_device.py | 13 +-- ereuse_devicehub/resources/device/models.py | 91 +++++-------------- 2 files changed, 26 insertions(+), 78 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py index e6c436d9..ea1d2037 100644 --- a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py +++ b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py @@ -5,11 +5,11 @@ Revises: 564952310b17 Create Date: 2022-12-13 10:14:45.500087 """ -from alembic import context, op -import sqlalchemy as sa -import citext import hashlib +import citext +import sqlalchemy as sa +from alembic import context, op # revision identifiers, used by Alembic. revision = '93daff872771' @@ -54,12 +54,7 @@ def upgrade(): upgrade_data() - op.alter_column( - 'computer', - 'user_trusts', - nullable=False, - schema=f'{get_inv()}' - ) + op.alter_column('computer', 'user_trusts', nullable=False, schema=f'{get_inv()}') def downgrade(): diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index df331e70..0b13d733 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -183,6 +183,7 @@ class Device(Thing): phid_bk = db.Column(db.CIText(), nullable=True, unique=False) active = db.Column(Boolean, default=True) family = db.Column(db.CIText()) + chid = db.Column(db.CIText()) _NON_PHYSICAL_PROPS = { 'id', @@ -212,6 +213,7 @@ class Device(Thing): 'active', 'phid_bk', 'dhid_bk', + 'chid', } __table_args__ = ( @@ -745,76 +747,14 @@ class Device(Thing): return "" - def set_new_hid(self): - """ - The order is important - # product_vendor, is a manufacturer - # product_family, is a new field of lshw - # product_chassis, is a type of chassis - # product_number, is a model - # product_version, - # product_sku, - # product_serial, is a serial number - # product_uuid, - # board_vendor, - # board_number, - # board_serial, - # board_version - """ - with suppress(TypeError): - family = (self.family or '').replace(' ', '_') - model = ((self.model 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 '') - if not system_uuid or not self.manufacturer: - return '' - - 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, - model, - 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 get_from_db(self): + try: + from modules.device.utils import get_from_db + + return get_from_db(self) + except Exception: + pass + if not self.hid: return @@ -826,11 +766,23 @@ class Device(Thing): ).first() def set_hid(self): + try: + from modules.device.utils import set_hid + + self.hid = set_hid(self) + return + except Exception: + pass + with suppress(TypeError): self.hid = Naming.hid( self.type, self.manufacturer, self.model, self.serial_number ) + def set_chid(self): + if self.hid: + self.chid = hashlib.sha3_256(self.hid.encode()).hexdigest() + def last_action_of(self, *types): """Gets the last action of the given types. @@ -1107,6 +1059,7 @@ class Computer(Device): receiver_id = db.Column(UUID(as_uuid=True), db.ForeignKey(User.id), nullable=True) receiver = db.relationship(User, primaryjoin=receiver_id == User.id) system_uuid = db.Column(UUID(as_uuid=True), nullable=True) + user_trusts = db.Column(Boolean(), default=True) def __init__(self, *args, **kwargs) -> None: if args: From 1b11162522e8bd31ac321ad9f1d3788d41b02f5d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 13 Dec 2022 20:40:28 +0100 Subject: [PATCH 17/39] clean sync class --- ereuse_devicehub/resources/device/sync.py | 123 +++------------------- 1 file changed, 15 insertions(+), 108 deletions(-) diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 650d8036..8b27a85f 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -30,13 +30,6 @@ DEVICES_ALLOW_DUPLICITY = [ 'GraphicCard', ] -err_motherboard = "Error: We have detected that a there is a device" -err_motherboard += " in your inventory with this system UUID. " -err_motherboard += "We proceed to block this snapshot to prevent its" -err_motherboard += " information from being updated incorrectly." -err_motherboard += " The solution we offer you to inventory this device " -err_motherboard += "is to do it by creating a placeholder." - class Sync: """Synchronizes the device and components with the database.""" @@ -74,18 +67,10 @@ class Sync: of the passed-in components. 2. A list of Add / Remove (not yet added to session). """ + device.components = OrderedSet(components) + device.set_hid() + device.components = OrderedSet() db_device = self.execute_register(device) - motherboard = None - if components: - for c in components: - if c.type == "Motherboard": - motherboard = c - - if motherboard: - for c in db_device.components: - if c.type == "Motherboard" and motherboard.hid != c.hid: - # import pdb; pdb.set_trace() - raise ValidationError(err_motherboard) db_components, actions = OrderedSet(), OrderedSet() if components is not None: # We have component info (see above) @@ -93,12 +78,9 @@ class Sync: # Until a good reason is given, we synthetically forbid # non-computers with components raise ValidationError('Only computers can have components.') - blacklist = set() # type: Set[int] not_new_components = set() for component in components: - db_component, is_new = self.execute_register_component( - component, blacklist, parent=db_device - ) + db_component, is_new = self.execute_register_component(component) db_components.add(db_component) if not is_new: not_new_components.add(db_component) @@ -109,9 +91,7 @@ class Sync: self.create_placeholder(db_device) return db_device, actions - def execute_register_component( - self, component: Component, blacklist: Set[int], parent: Computer - ): + def execute_register_component(self, component: Component): """Synchronizes one component to the DB. This method is a specialization of :meth:`.execute_register` @@ -141,30 +121,18 @@ class Sync: is_new = True return component, is_new - # if not, then continue with the traditional behaviour - try: - if component.hid: - db_component = Device.query.filter_by( - hid=component.hid, owner_id=g.user.id, placeholder=None - ).one() - assert isinstance( - db_component, Device - ), '{} must be a component'.format(db_component) - else: - # Is there a component similar to ours? - db_component = component.similar_one(parent, blacklist) - # We blacklist this component so we - # ensure we don't get it again for another component - # with the same physical properties - blacklist.add(db_component.id) - except ResourceNotFound: + if component.hid: + db_component = Device.query.filter_by( + hid=component.hid, owner_id=g.user.id, placeholder=None + ).first() + assert isinstance(db_component, Device), '{} must be a component'.format( + db_component + ) + is_new = False + else: db.session.add(component) - # db.session.flush() db_component = component is_new = True - else: - self.merge(component, db_component) - is_new = False return db_component, is_new def execute_register(self, device: Device) -> Device: @@ -194,53 +162,15 @@ class Sync: :raise DatabaseError: Any other error from the DB. :return: The synced device from the db with the tags linked. """ - assert inspect(device).transient, 'Device cannot be already synced from DB' - assert all( - inspect(tag).transient for tag in device.tags - ), 'Tags cannot be synced from DB' db_device = device.get_from_db() if db_device and db_device.allocated: raise ResourceNotFound('device is actually allocated {}'.format(device)) - try: - tags = { - Tag.from_an_id(tag.id).one() for tag in device.tags - } # type: Set[Tag] - except ResourceNotFound: - raise ResourceNotFound('tag you are linking to device {}'.format(device)) - linked_tags = {tag for tag in tags if tag.device_id} # type: Set[Tag] - if linked_tags: - sample_tag = next(iter(linked_tags)) - for tag in linked_tags: - if tag.device_id != sample_tag.device_id: - raise MismatchBetweenTags( - tag, sample_tag - ) # Tags linked to different devices - if db_device: # Device from hid - if ( - sample_tag.device_id != db_device.id - ): # Device from hid != device from tags - raise MismatchBetweenTagsAndHid(db_device.id, db_device.hid) - else: # There was no device from hid - if sample_tag.device.physical_properties != device.physical_properties: - # Incoming physical props of device != props from tag's device - # which means that the devices are not the same - raise MismatchBetweenProperties( - sample_tag.device.physical_properties, - device.physical_properties, - ) - db_device = sample_tag.device - - if db_device: # Device from hid or tags - self.merge(device, db_device) - else: # Device is new and tags are not linked to a device + if not db_device: device.tags.clear() # We don't want to add the transient dummy tags db.session.add(device) db_device = device - db_device.tags |= ( - tags # Union of tags the device had plus the (potentially) new ones - ) try: db.session.flush() except IntegrityError as e: @@ -258,29 +188,6 @@ class Sync: assert db_device is not None return db_device - @staticmethod - def merge(device: Device, db_device: Device): - """Copies the physical properties of the device to the db_device. - - This method mutates db_device. - """ - if db_device.owner_id != g.user.id: - return - - if device.placeholder and not db_device.placeholder: - return - - for field_name, value in device.physical_properties.items(): - if value is not None: - setattr(db_device, field_name, value) - - # if device.system_uuid and db_device.system_uuid and device.system_uuid != db_device.system_uuid: - # TODO @cayop send error to sentry.io - # there are 2 computers duplicate get db_device for hid - - if hasattr(device, 'system_uuid') and device.system_uuid: - db_device.system_uuid = device.system_uuid - @staticmethod def create_placeholder(device: Device): """If the device is new, we need create automaticaly a new placeholder""" From a0c1cce69a1b115de817c53cff5c114f17ab75b7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 13 Dec 2022 20:40:53 +0100 Subject: [PATCH 18/39] fix template snapshots logs --- ereuse_devicehub/templates/inventory/snapshots_list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/templates/inventory/snapshots_list.html b/ereuse_devicehub/templates/inventory/snapshots_list.html index 126d3ac3..7eae8605 100644 --- a/ereuse_devicehub/templates/inventory/snapshots_list.html +++ b/ereuse_devicehub/templates/inventory/snapshots_list.html @@ -91,7 +91,7 @@ {% if snap.get_device() %} - + {{ snap.get_device() }} {% endif %} From fc362181245991ad211fe6ae7f5d83d09e02ea0f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 13 Dec 2022 20:41:15 +0100 Subject: [PATCH 19/39] fix set_chid --- ereuse_devicehub/resources/device/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 0b13d733..c8d1eab8 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -770,6 +770,7 @@ class Device(Thing): from modules.device.utils import set_hid self.hid = set_hid(self) + self.set_chid() return except Exception: pass @@ -778,6 +779,7 @@ class Device(Thing): self.hid = Naming.hid( self.type, self.manufacturer, self.model, self.serial_number ) + self.set_chid() def set_chid(self): if self.hid: From 2cc677a55582142c4e64c1a912cda82a751eb6a8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 14 Dec 2022 11:42:11 +0100 Subject: [PATCH 20/39] fix sync --- ereuse_devicehub/resources/device/sync.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 8b27a85f..a82be1b1 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -67,9 +67,10 @@ class Sync: of the passed-in components. 2. A list of Add / Remove (not yet added to session). """ - device.components = OrderedSet(components) - device.set_hid() - device.components = OrderedSet() + if components: + device.components = OrderedSet(components) + device.set_hid() + device.components = OrderedSet() db_device = self.execute_register(device) db_components, actions = OrderedSet(), OrderedSet() @@ -113,7 +114,6 @@ class Sync: - A flag stating if the device is new or it already existed in the DB. """ - # if device.serial_number == 'b8oaas048286': assert inspect(component).transient, 'Component should not be synced from DB' # if not is a DataStorage, then need build a new one if component.t in DEVICES_ALLOW_DUPLICITY: @@ -121,15 +121,14 @@ class Sync: is_new = True return component, is_new + db_component = None + if component.hid: db_component = Device.query.filter_by( hid=component.hid, owner_id=g.user.id, placeholder=None ).first() - assert isinstance(db_component, Device), '{} must be a component'.format( - db_component - ) is_new = False - else: + if not db_component: db.session.add(component) db_component = component is_new = True @@ -177,7 +176,7 @@ class Sync: # Manage 'one tag per organization' unique constraint if 'One tag per organization' in e.args[0]: # todo test for this - id = int(e.args[0][135 : e.args[0].index(',', 135)]) + id = int(e.args[0][135 : e.args[0].index(',', 135)]) # noqa: E203 raise ValidationError( 'The device is already linked to tag {} ' 'from the same organization.'.format(id), From c066d8a2af78f185e4848690df7a6d865678faf6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 14 Dec 2022 16:57:59 +0100 Subject: [PATCH 21/39] fix tests --- .../resources/documents/device_row.py | 10 ++--- tests/files/export_devices.csv | 2 +- tests/files/real-eee-1001pxd.snapshot.12.yaml | 1 + tests/test_render_2_0.py | 45 +++++++++++-------- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index 2e13d327..5aea1f04 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -285,7 +285,7 @@ class DeviceRow(BaseDeviceRow): self['Tag {} ID'.format(i)] = tag.id self['Tag {} Organization'.format(i)] = tag.org.name - self['Device Hardware ID'] = device.hid + self['Device Hardware ID'] = device.chid self['Device Type'] = device.t if isinstance(device, d.Computer) and not device.placeholder: self['Device Chassis'] = device.chassis.name @@ -433,12 +433,12 @@ class DeviceRow(BaseDeviceRow): ] erasure = erasures[-1] if erasures else None if not erasure: - self['Erasure {} {}'.format(ctype, i)] = none2str(component.hid) + self['Erasure {} {}'.format(ctype, i)] = none2str(component.chid) serial_number = none2str(component.serial_number) self['Erasure {} {} Serial Number'.format(ctype, i)] = serial_number self['Erasure {} {} Size (MB)'.format(ctype, i)] = none2str(component.size) elif hasattr(erasure, 'type') and erasure.type == 'DataWipe': - self['Erasure {} {}'.format(ctype, i)] = none2str(component.hid) + self['Erasure {} {}'.format(ctype, i)] = none2str(component.chid) serial_number = none2str(component.serial_number) self['Erasure {} {} Serial Number'.format(ctype, i)] = serial_number self['Erasure {} {} Size (MB)'.format(ctype, i)] = none2str(component.size) @@ -448,7 +448,7 @@ class DeviceRow(BaseDeviceRow): erasure.document.url and erasure.document.url.to_text() or '' ) else: - self['Erasure {} {}'.format(ctype, i)] = none2str(component.hid) + self['Erasure {} {}'.format(ctype, i)] = none2str(component.chid) serial_number = none2str(component.serial_number) self['Erasure {} {} Serial Number'.format(ctype, i)] = serial_number self['Erasure {} {} Size (MB)'.format(ctype, i)] = none2str(component.size) @@ -594,7 +594,7 @@ class ActionRow(OrderedDict): super().__init__() # General information about allocates, deallocate and lives self['DHID'] = allocate['devicehubID'] - self['Hid'] = allocate['hid'] + self['Hid'] = allocate['chid'] self['Document-Name'] = allocate['document_name'] self['Action-Type'] = allocate['action_type'] self['Action-User-LastOwner-Supplier'] = allocate['trade_supplier'] diff --git a/tests/files/export_devices.csv b/tests/files/export_devices.csv index 2e04a391..e40624f7 100644 --- a/tests/files/export_devices.csv +++ b/tests/files/export_devices.csv @@ -1,2 +1,2 @@ "PHID";"DHID";"Type";"Placeholder Palet";"Placeholder Id Supplier";"Placeholder Info";"Placeholder Components";"Placeholder Type";"Placeholder Serial Number";"Placeholder Part Number";"Placeholder Model";"Placeholder Manufacturer";"DocumentID";"Public Link";"Tag 1 Type";"Tag 1 ID";"Tag 1 Organization";"Tag 2 Type";"Tag 2 ID";"Tag 2 Organization";"Tag 3 Type";"Tag 3 ID";"Tag 3 Organization";"Device Hardware ID";"Device Type";"Device Chassis";"Device Serial Number";"Device Model";"Device Manufacturer";"Registered in";"Registered (process)";"Updated in (software)";"Updated in (web)";"Physical state";"Allocate state";"Lifecycle state";"Processor";"RAM (MB)";"Data Storage Size (MB)";"Processor 1";"Processor 1 Manufacturer";"Processor 1 Model";"Processor 1 Serial Number";"Processor 1 Number of cores";"Processor 1 Speed (GHz)";"Benchmark Processor 1 (points)";"Benchmark ProcessorSysbench Processor 1 (points)";"Processor 2";"Processor 2 Manufacturer";"Processor 2 Model";"Processor 2 Serial Number";"Processor 2 Number of cores";"Processor 2 Speed (GHz)";"Benchmark Processor 2 (points)";"Benchmark ProcessorSysbench Processor 2 (points)";"RamModule 1";"RamModule 1 Manufacturer";"RamModule 1 Model";"RamModule 1 Serial Number";"RamModule 1 Size (MB)";"RamModule 1 Speed (MHz)";"RamModule 2";"RamModule 2 Manufacturer";"RamModule 2 Model";"RamModule 2 Serial Number";"RamModule 2 Size (MB)";"RamModule 2 Speed (MHz)";"RamModule 3";"RamModule 3 Manufacturer";"RamModule 3 Model";"RamModule 3 Serial Number";"RamModule 3 Size (MB)";"RamModule 3 Speed (MHz)";"RamModule 4";"RamModule 4 Manufacturer";"RamModule 4 Model";"RamModule 4 Serial Number";"RamModule 4 Size (MB)";"RamModule 4 Speed (MHz)";"DataStorage 1";"DataStorage 1 Manufacturer";"DataStorage 1 Model";"DataStorage 1 Serial Number";"DataStorage 1 Size (MB)";"Erasure DataStorage 1";"Erasure DataStorage 1 Serial Number";"Erasure DataStorage 1 Size (MB)";"Erasure DataStorage 1 Software";"Erasure DataStorage 1 Result";"Erasure DataStorage 1 Certificate URL";"Erasure DataStorage 1 Type";"Erasure DataStorage 1 Method";"Erasure DataStorage 1 Elapsed (hours)";"Erasure DataStorage 1 Date";"Erasure DataStorage 1 Steps";"Erasure DataStorage 1 Steps Start Time";"Erasure DataStorage 1 Steps End Time";"Benchmark DataStorage 1 Read Speed (MB/s)";"Benchmark DataStorage 1 Writing speed (MB/s)";"Test DataStorage 1 Software";"Test DataStorage 1 Type";"Test DataStorage 1 Result";"Test DataStorage 1 Power cycle count";"Test DataStorage 1 Lifetime (days)";"Test DataStorage 1 Power on hours";"DataStorage 2";"DataStorage 2 Manufacturer";"DataStorage 2 Model";"DataStorage 2 Serial Number";"DataStorage 2 Size (MB)";"Erasure DataStorage 2";"Erasure DataStorage 2 Serial Number";"Erasure DataStorage 2 Size (MB)";"Erasure DataStorage 2 Software";"Erasure DataStorage 2 Result";"Erasure DataStorage 2 Certificate URL";"Erasure DataStorage 2 Type";"Erasure DataStorage 2 Method";"Erasure DataStorage 2 Elapsed (hours)";"Erasure DataStorage 2 Date";"Erasure DataStorage 2 Steps";"Erasure DataStorage 2 Steps Start Time";"Erasure DataStorage 2 Steps End Time";"Benchmark DataStorage 2 Read Speed (MB/s)";"Benchmark DataStorage 2 Writing speed (MB/s)";"Test DataStorage 2 Software";"Test DataStorage 2 Type";"Test DataStorage 2 Result";"Test DataStorage 2 Power cycle count";"Test DataStorage 2 Lifetime (days)";"Test DataStorage 2 Power on hours";"DataStorage 3";"DataStorage 3 Manufacturer";"DataStorage 3 Model";"DataStorage 3 Serial Number";"DataStorage 3 Size (MB)";"Erasure DataStorage 3";"Erasure DataStorage 3 Serial Number";"Erasure DataStorage 3 Size (MB)";"Erasure DataStorage 3 Software";"Erasure DataStorage 3 Result";"Erasure DataStorage 3 Certificate URL";"Erasure DataStorage 3 Type";"Erasure DataStorage 3 Method";"Erasure DataStorage 3 Elapsed (hours)";"Erasure DataStorage 3 Date";"Erasure DataStorage 3 Steps";"Erasure DataStorage 3 Steps Start Time";"Erasure DataStorage 3 Steps End Time";"Benchmark DataStorage 3 Read Speed (MB/s)";"Benchmark DataStorage 3 Writing speed (MB/s)";"Test DataStorage 3 Software";"Test DataStorage 3 Type";"Test DataStorage 3 Result";"Test DataStorage 3 Power cycle count";"Test DataStorage 3 Lifetime (days)";"Test DataStorage 3 Power on hours";"DataStorage 4";"DataStorage 4 Manufacturer";"DataStorage 4 Model";"DataStorage 4 Serial Number";"DataStorage 4 Size (MB)";"Erasure DataStorage 4";"Erasure DataStorage 4 Serial Number";"Erasure DataStorage 4 Size (MB)";"Erasure DataStorage 4 Software";"Erasure DataStorage 4 Result";"Erasure DataStorage 4 Certificate URL";"Erasure DataStorage 4 Type";"Erasure DataStorage 4 Method";"Erasure DataStorage 4 Elapsed (hours)";"Erasure DataStorage 4 Date";"Erasure DataStorage 4 Steps";"Erasure DataStorage 4 Steps Start Time";"Erasure DataStorage 4 Steps End Time";"Benchmark DataStorage 4 Read Speed (MB/s)";"Benchmark DataStorage 4 Writing speed (MB/s)";"Test DataStorage 4 Software";"Test DataStorage 4 Type";"Test DataStorage 4 Result";"Test DataStorage 4 Power cycle count";"Test DataStorage 4 Lifetime (days)";"Test DataStorage 4 Power on hours";"Motherboard 1";"Motherboard 1 Manufacturer";"Motherboard 1 Model";"Motherboard 1 Serial Number";"Display 1";"Display 1 Manufacturer";"Display 1 Model";"Display 1 Serial Number";"GraphicCard 1";"GraphicCard 1 Manufacturer";"GraphicCard 1 Model";"GraphicCard 1 Serial Number";"GraphicCard 1 Memory (MB)";"GraphicCard 2";"GraphicCard 2 Manufacturer";"GraphicCard 2 Model";"GraphicCard 2 Serial Number";"GraphicCard 2 Memory (MB)";"NetworkAdapter 1";"NetworkAdapter 1 Manufacturer";"NetworkAdapter 1 Model";"NetworkAdapter 1 Serial Number";"NetworkAdapter 2";"NetworkAdapter 2 Manufacturer";"NetworkAdapter 2 Model";"NetworkAdapter 2 Serial Number";"SoundCard 1";"SoundCard 1 Manufacturer";"SoundCard 1 Model";"SoundCard 1 Serial Number";"SoundCard 2";"SoundCard 2 Manufacturer";"SoundCard 2 Model";"SoundCard 2 Serial Number";"Device Rate";"Device Range";"Processor Rate";"Processor Range";"RAM Rate";"RAM Range";"Data Storage Rate";"Data Storage Range";"Benchmark RamSysbench (points)" -"10";"E39W3";"Snapshot";"";"";"";"";"Laptop";"b8oaas048285";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b";"Laptop";"Netbook";"b8oaas048285";"1001pxd";"asustek computer inc.";"Wed Sep 21 13:10:21 2022";"Workbench 11.0a2";"2022-09-21 13:10:21.174981+02:00";"";"";"";"";"intel atom cpu n455 @ 2.66ghz";"1024";"238475";"Processor 7: model intel atom cpu n455 @ 2.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 2.66ghz";"";"1";"2.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 11: model None, S/N None";"";"";"";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 12: model hts54322, S/N e2024242cv86mm";"hitachi";"hts54322";"e2024242cv86mm";"238475";"harddrive-hitachi-hts54322-e2024242cv86mm";"e2024242cv86mm";"238475";"Workbench 11.0a2";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-09-21 13:10:21.126373+02:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0a2";"Short";"Failure";"";"";"0";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 13: model 1001pxd, S/N eee0123456720";"asustek computer inc.";"1001pxd";"eee0123456720";"";"";"";"";"GraphicCard 8: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 5: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c9";"NetworkAdapter 6: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7b";"SoundCard 9: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 10: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" +"10";"E39W3";"Snapshot";"";"";"";"";"Laptop";"b8oaas048285";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"49b3920735c11693c43cef6199af95798ac00dbd61cc3224eae5e9f04d3313fb";"Laptop";"Netbook";"b8oaas048285";"1001pxd";"asustek computer inc.";"Wed Dec 14 12:28:44 2022";"Workbench 11.0a2";"2022-12-14 12:28:44.757147+01:00";"";"";"";"";"intel atom cpu n455 @ 2.66ghz";"1024";"238475";"Processor 7: model intel atom cpu n455 @ 2.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 2.66ghz";"";"1";"2.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 11: model None, S/N None";"";"";"";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 12: model hts54322, S/N e2024242cv86mm";"hitachi";"hts54322";"e2024242cv86mm";"238475";"8558ea99955f34c788cb72174c0ec165e0398306efbc0efe40b280b65d16d0d0";"e2024242cv86mm";"238475";"Workbench 11.0a2";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-12-14 12:28:44.712329+01:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0a2";"Short";"Failure";"";"";"0";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 13: model 1001pxd, S/N eee0123456720";"asustek computer inc.";"1001pxd";"eee0123456720";"";"";"";"";"GraphicCard 8: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 5: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c9";"NetworkAdapter 6: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7b";"SoundCard 9: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 10: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" diff --git a/tests/files/real-eee-1001pxd.snapshot.12.yaml b/tests/files/real-eee-1001pxd.snapshot.12.yaml index 6dc974bd..425a270c 100644 --- a/tests/files/real-eee-1001pxd.snapshot.12.yaml +++ b/tests/files/real-eee-1001pxd.snapshot.12.yaml @@ -158,5 +158,6 @@ } ] }, + "debug": {"lshw": {"configuration": {"uuid": "79c5098f-bc44-4834-8a59-9ea61d956c31"}}}, "closed": false } diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index f9f2299e..b970aa1a 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -12,7 +12,6 @@ from flask_wtf.csrf import generate_csrf from ereuse_devicehub.client import UserClient, UserClientFlask from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub -from ereuse_devicehub.parser.models import SnapshotsLog from ereuse_devicehub.resources.action.models import Snapshot from ereuse_devicehub.resources.device.models import Device, Placeholder from ereuse_devicehub.resources.lot.models import Lot @@ -714,7 +713,9 @@ def test_add_laptop(user3: UserClientFlask): assert typ == 'Laptop' assert dev.placeholder.id_device_supplier == "b2" - assert dev.hid == 'laptop-samsung-lc27t55-aaaab' + assert ( + dev.chid == '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + ) assert phid == '1' assert dhid == 'O48N2' @@ -753,7 +754,10 @@ def test_add_with_ammount_laptops(user3: UserClientFlask): for dev in Device.query.all(): assert dev.type == 'Laptop' assert dev.placeholder.id_device_supplier is None - assert dev.hid is None + assert ( + dev.chid + == 'ab606f8b822dcd9276a6c492161fe592047ea98816387d149b2ccfbb5a7ebd30' + ) assert dev.placeholder.phid in [str(x) for x in range(1, num + 1)] assert Device.query.count() == num @@ -1729,7 +1733,8 @@ def test_add_placeholder_excel(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - assert dev.hid == 'laptop-sony-vaio-12345678' + chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' assert dev.placeholder.pallet == '24A' @@ -1755,7 +1760,8 @@ def test_add_placeholder_csv(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - assert dev.hid == 'laptop-sony-vaio-12345678' + chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' assert dev.placeholder.pallet == '24A' @@ -1781,7 +1787,8 @@ def test_add_placeholder_ods(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - assert dev.hid == 'laptop-sony-vaio-12345678' + chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' assert dev.placeholder.pallet == '24A' @@ -1809,7 +1816,8 @@ def test_add_placeholder_office_open_xml(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - assert dev.hid == 'laptop-sony-vaio-12345678' + chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' assert dev.placeholder.pallet == '24A' @@ -1847,7 +1855,8 @@ def test_edit_laptop(user3: UserClientFlask): assert typ == 'Laptop' assert dev.placeholder.id_device_supplier == "b2" - assert dev.hid == 'laptop-samsung-lc27t55-aaaab' + chid = '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + assert dev.chid == chid assert dev.serial_number == 'aaaab' assert dev.model == 'lc27t55' assert phid == '1' @@ -1879,7 +1888,7 @@ def test_edit_laptop(user3: UserClientFlask): assert 'Device "Laptop" edited successfully!' in body dev = Device.query.one() assert dev.type == 'Laptop' - assert dev.hid == 'laptop-samsung-lc27t55-aaaab' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.id_device_supplier == 'a2' assert dev.serial_number == 'aaaac' @@ -2077,7 +2086,8 @@ def test_add_placeholder_excel_from_lot(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - assert dev.hid == 'laptop-sony-vaio-12345678' + chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' assert dev.placeholder.pallet == '24A' @@ -2116,7 +2126,8 @@ def test_add_new_placeholder_from_lot(user3: UserClientFlask): } user3.post(uri, data=data) dev = Device.query.one() - assert dev.hid == 'laptop-samsung-lc27t55-aaaab' + chid = '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert len(lot.devices) == 1 @@ -2141,7 +2152,8 @@ def test_manual_binding(user3: UserClientFlask): } user3.post(uri, data=data) dev = Device.query.one() - assert dev.hid == 'laptop-samsung-lc27t55-aaaab' + chid = '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.is_abstract is False @@ -2153,8 +2165,8 @@ def test_manual_binding(user3: UserClientFlask): assert dev_wb.binding.is_abstract is True assert ( - dev_wb.hid - == 'laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b' + dev_wb.chid + == '49b3920735c11693c43cef6199af95798ac00dbd61cc3224eae5e9f04d3313fb' ) assert dev_wb.binding.phid == '11' old_placeholder = dev_wb.binding @@ -2653,10 +2665,7 @@ def test_system_uuid_motherboard(user3: UserClientFlask): } user3.post(uri, data=data, content_type="multipart/form-data") snapshot2 = Snapshot.query.filter_by(uuid=snapshot_json['uuid']).first() - assert snapshot2 is None + assert snapshot2.device != snapshot.device for c in snapshot.device.components: if c.type == 'Motherboard': assert c.serial_number == 'eee0123456720' - - txt = "We have detected that a there is a device in your inventory" - assert txt in SnapshotsLog.query.all()[-1].description From 84e937026e3ac3e06c2fd5106dad6829ef6f3156 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 19 Dec 2022 20:03:34 +0100 Subject: [PATCH 22/39] fix tests --- ereuse_devicehub/inventory/forms.py | 1 + ereuse_devicehub/inventory/views.py | 1 - ereuse_devicehub/resources/device/metrics.py | 46 +-- ereuse_devicehub/resources/device/models.py | 19 +- .../resources/documents/device_row.py | 2 +- tests/files/basic.csv | 2 +- tests/files/export_devices.csv | 2 +- tests/files/proposal_extended_csv_report.csv | 4 +- tests/test_action.py | 2 +- tests/test_device.py | 275 +----------------- tests/test_metrics.py | 216 ++++++++------ tests/test_render_2_0.py | 33 ++- tests/test_snapshot.py | 18 +- tests/test_system_uuid.py | 156 +++------- tests/test_tag.py | 33 --- tests/test_workbench.py | 22 +- 16 files changed, 243 insertions(+), 589 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 8d6f0b8b..7f51bebf 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -580,6 +580,7 @@ class NewDeviceForm(FlaskForm): device.image = URL(self.image.data) device.placeholder = self.get_placeholder() + device.set_hid() db.session.add(device) placeholder_log = PlaceholdersLog( diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index b9c3a659..ed3939be 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -67,7 +67,6 @@ class DeviceListMixin(GenericMixin): page = int(request.args.get('page', 1)) per_page = int(request.args.get('per_page', PER_PAGE)) filter = request.args.get('filter', "All+Computers") - # import pdb; pdb.set_trace() lots = self.context['lots'] form_filter = FilterForm(lots, lot_id, all_devices=all_devices) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index bf118da6..fa43818e 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -21,27 +21,29 @@ class MetricsMix: """ This is a template of a row. """ - return {'type': '', - 'action_type': 'Status', - 'document_name': '', - 'status_receiver': self.status_receiver, - 'status_supplier': self.status_supplier, - 'status_receiver_created': '', - 'status_supplier_created': '', - 'trade_supplier': '', - 'trade_receiver': self.act.author.email, - 'trade_confirmed': '', - 'trade_weight': 0, - 'action_create_by': self.action_create_by, - 'devicehubID': self.devicehub_id, - 'hid': self.hid, - 'finalUserCode': '', - 'numEndUsers': 0, - 'liveCreate': 0, - 'usageTimeHdd': self.lifetime, - 'created': self.act.created, - 'start': '', - 'usageTimeAllocate': 0} + return { + 'type': '', + 'action_type': 'Status', + 'document_name': '', + 'status_receiver': self.status_receiver, + 'status_supplier': self.status_supplier, + 'status_receiver_created': '', + 'status_supplier_created': '', + 'trade_supplier': '', + 'trade_receiver': self.act.author.email, + 'trade_confirmed': '', + 'trade_weight': 0, + 'action_create_by': self.action_create_by, + 'devicehubID': self.devicehub_id, + 'hid': self.hid, + 'finalUserCode': '', + 'numEndUsers': 0, + 'liveCreate': 0, + 'usageTimeHdd': self.lifetime, + 'created': self.act.created, + 'start': '', + 'usageTimeAllocate': 0, + } def get_metrics(self): """ @@ -57,7 +59,7 @@ class Metrics(MetricsMix): self.device = kwargs.pop('device') self.actions = copy.copy(self.device.actions) super().__init__(*args, **kwargs) - self.hid = self.device.hid + self.hid = self.device.chid self.devicehub_id = self.device.devicehub_id def get_action_status(self): diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index c8d1eab8..e715342e 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -214,6 +214,10 @@ class Device(Thing): 'phid_bk', 'dhid_bk', 'chid', + 'user_trusts', + 'chassis', + 'transfer_state', + 'receiver_id', } __table_args__ = ( @@ -775,12 +779,19 @@ class Device(Thing): except Exception: pass - with suppress(TypeError): - self.hid = Naming.hid( - self.type, self.manufacturer, self.model, self.serial_number - ) + self.hid = "{}-{}-{}-{}".format( + self._clean_string(self.type), + self._clean_string(self.manufacturer), + self._clean_string(self.model), + self._clean_string(self.serial_number), + ).lower() self.set_chid() + def _clean_string(self, s): + if not s: + return '' + return s.replace(' ', '_') + def set_chid(self): if self.hid: self.chid = hashlib.sha3_256(self.hid.encode()).hexdigest() diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index 5aea1f04..d4efda46 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -594,7 +594,7 @@ class ActionRow(OrderedDict): super().__init__() # General information about allocates, deallocate and lives self['DHID'] = allocate['devicehubID'] - self['Hid'] = allocate['chid'] + self['Hid'] = allocate['hid'] self['Document-Name'] = allocate['document_name'] self['Action-Type'] = allocate['action_type'] self['Action-User-LastOwner-Supplier'] = allocate['trade_supplier'] diff --git a/tests/files/basic.csv b/tests/files/basic.csv index 13efc342..3ceda076 100644 --- a/tests/files/basic.csv +++ b/tests/files/basic.csv @@ -1,2 +1,2 @@ "PHID";"DHID";"Type";"Placeholder Palet";"Placeholder Id Supplier";"Placeholder Info";"Placeholder Components";"Placeholder Type";"Placeholder Serial Number";"Placeholder Part Number";"Placeholder Model";"Placeholder Manufacturer";"DocumentID";"Public Link";"Tag 1 Type";"Tag 1 ID";"Tag 1 Organization";"Tag 2 Type";"Tag 2 ID";"Tag 2 Organization";"Tag 3 Type";"Tag 3 ID";"Tag 3 Organization";"Device Hardware ID";"Device Type";"Device Chassis";"Device Serial Number";"Device Model";"Device Manufacturer";"Registered in";"Registered (process)";"Updated in (software)";"Updated in (web)";"Physical state";"Allocate state";"Lifecycle state";"Processor";"RAM (MB)";"Data Storage Size (MB)";"Processor 1";"Processor 1 Manufacturer";"Processor 1 Model";"Processor 1 Serial Number";"Processor 1 Number of cores";"Processor 1 Speed (GHz)";"Benchmark Processor 1 (points)";"Benchmark ProcessorSysbench Processor 1 (points)";"Processor 2";"Processor 2 Manufacturer";"Processor 2 Model";"Processor 2 Serial Number";"Processor 2 Number of cores";"Processor 2 Speed (GHz)";"Benchmark Processor 2 (points)";"Benchmark ProcessorSysbench Processor 2 (points)";"RamModule 1";"RamModule 1 Manufacturer";"RamModule 1 Model";"RamModule 1 Serial Number";"RamModule 1 Size (MB)";"RamModule 1 Speed (MHz)";"RamModule 2";"RamModule 2 Manufacturer";"RamModule 2 Model";"RamModule 2 Serial Number";"RamModule 2 Size (MB)";"RamModule 2 Speed (MHz)";"RamModule 3";"RamModule 3 Manufacturer";"RamModule 3 Model";"RamModule 3 Serial Number";"RamModule 3 Size (MB)";"RamModule 3 Speed (MHz)";"RamModule 4";"RamModule 4 Manufacturer";"RamModule 4 Model";"RamModule 4 Serial Number";"RamModule 4 Size (MB)";"RamModule 4 Speed (MHz)";"DataStorage 1";"DataStorage 1 Manufacturer";"DataStorage 1 Model";"DataStorage 1 Serial Number";"DataStorage 1 Size (MB)";"Erasure DataStorage 1";"Erasure DataStorage 1 Serial Number";"Erasure DataStorage 1 Size (MB)";"Erasure DataStorage 1 Software";"Erasure DataStorage 1 Result";"Erasure DataStorage 1 Certificate URL";"Erasure DataStorage 1 Type";"Erasure DataStorage 1 Method";"Erasure DataStorage 1 Elapsed (hours)";"Erasure DataStorage 1 Date";"Erasure DataStorage 1 Steps";"Erasure DataStorage 1 Steps Start Time";"Erasure DataStorage 1 Steps End Time";"Benchmark DataStorage 1 Read Speed (MB/s)";"Benchmark DataStorage 1 Writing speed (MB/s)";"Test DataStorage 1 Software";"Test DataStorage 1 Type";"Test DataStorage 1 Result";"Test DataStorage 1 Power cycle count";"Test DataStorage 1 Lifetime (days)";"Test DataStorage 1 Power on hours";"DataStorage 2";"DataStorage 2 Manufacturer";"DataStorage 2 Model";"DataStorage 2 Serial Number";"DataStorage 2 Size (MB)";"Erasure DataStorage 2";"Erasure DataStorage 2 Serial Number";"Erasure DataStorage 2 Size (MB)";"Erasure DataStorage 2 Software";"Erasure DataStorage 2 Result";"Erasure DataStorage 2 Certificate URL";"Erasure DataStorage 2 Type";"Erasure DataStorage 2 Method";"Erasure DataStorage 2 Elapsed (hours)";"Erasure DataStorage 2 Date";"Erasure DataStorage 2 Steps";"Erasure DataStorage 2 Steps Start Time";"Erasure DataStorage 2 Steps End Time";"Benchmark DataStorage 2 Read Speed (MB/s)";"Benchmark DataStorage 2 Writing speed (MB/s)";"Test DataStorage 2 Software";"Test DataStorage 2 Type";"Test DataStorage 2 Result";"Test DataStorage 2 Power cycle count";"Test DataStorage 2 Lifetime (days)";"Test DataStorage 2 Power on hours";"DataStorage 3";"DataStorage 3 Manufacturer";"DataStorage 3 Model";"DataStorage 3 Serial Number";"DataStorage 3 Size (MB)";"Erasure DataStorage 3";"Erasure DataStorage 3 Serial Number";"Erasure DataStorage 3 Size (MB)";"Erasure DataStorage 3 Software";"Erasure DataStorage 3 Result";"Erasure DataStorage 3 Certificate URL";"Erasure DataStorage 3 Type";"Erasure DataStorage 3 Method";"Erasure DataStorage 3 Elapsed (hours)";"Erasure DataStorage 3 Date";"Erasure DataStorage 3 Steps";"Erasure DataStorage 3 Steps Start Time";"Erasure DataStorage 3 Steps End Time";"Benchmark DataStorage 3 Read Speed (MB/s)";"Benchmark DataStorage 3 Writing speed (MB/s)";"Test DataStorage 3 Software";"Test DataStorage 3 Type";"Test DataStorage 3 Result";"Test DataStorage 3 Power cycle count";"Test DataStorage 3 Lifetime (days)";"Test DataStorage 3 Power on hours";"DataStorage 4";"DataStorage 4 Manufacturer";"DataStorage 4 Model";"DataStorage 4 Serial Number";"DataStorage 4 Size (MB)";"Erasure DataStorage 4";"Erasure DataStorage 4 Serial Number";"Erasure DataStorage 4 Size (MB)";"Erasure DataStorage 4 Software";"Erasure DataStorage 4 Result";"Erasure DataStorage 4 Certificate URL";"Erasure DataStorage 4 Type";"Erasure DataStorage 4 Method";"Erasure DataStorage 4 Elapsed (hours)";"Erasure DataStorage 4 Date";"Erasure DataStorage 4 Steps";"Erasure DataStorage 4 Steps Start Time";"Erasure DataStorage 4 Steps End Time";"Benchmark DataStorage 4 Read Speed (MB/s)";"Benchmark DataStorage 4 Writing speed (MB/s)";"Test DataStorage 4 Software";"Test DataStorage 4 Type";"Test DataStorage 4 Result";"Test DataStorage 4 Power cycle count";"Test DataStorage 4 Lifetime (days)";"Test DataStorage 4 Power on hours";"Motherboard 1";"Motherboard 1 Manufacturer";"Motherboard 1 Model";"Motherboard 1 Serial Number";"Display 1";"Display 1 Manufacturer";"Display 1 Model";"Display 1 Serial Number";"GraphicCard 1";"GraphicCard 1 Manufacturer";"GraphicCard 1 Model";"GraphicCard 1 Serial Number";"GraphicCard 1 Memory (MB)";"GraphicCard 2";"GraphicCard 2 Manufacturer";"GraphicCard 2 Model";"GraphicCard 2 Serial Number";"GraphicCard 2 Memory (MB)";"NetworkAdapter 1";"NetworkAdapter 1 Manufacturer";"NetworkAdapter 1 Model";"NetworkAdapter 1 Serial Number";"NetworkAdapter 2";"NetworkAdapter 2 Manufacturer";"NetworkAdapter 2 Model";"NetworkAdapter 2 Serial Number";"SoundCard 1";"SoundCard 1 Manufacturer";"SoundCard 1 Model";"SoundCard 1 Serial Number";"SoundCard 2";"SoundCard 2 Manufacturer";"SoundCard 2 Model";"SoundCard 2 Serial Number";"Device Rate";"Device Range";"Processor Rate";"Processor Range";"RAM Rate";"RAM Range";"Data Storage Rate";"Data Storage Range";"Benchmark RamSysbench (points)" -"4";"E39W3";"Snapshot";"";"";"";"";"Desktop";"d1s";"";"d1ml";"d1mr";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"desktop-d1mr-d1ml-d1s";"Desktop";"Microtower";"d1s";"d1ml";"d1mr";"Wed Sep 21 15:39:24 2022";"Workbench 11.0";"2022-09-21 15:39:24.321860+02:00";"";"";"";"";"p1ml";"0";"0";"Processor 7: model p1ml, S/N p1s";"p1mr";"p1ml";"p1s";"";"1.6";"2410.0";"";"";"";"";"";"";"";"";"";"RamModule 6: model rm1ml, S/N rm1s";"rm1mr";"rm1ml";"rm1s";"";"1333";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"GraphicCard 5: model gc1ml, S/N gc1s";"gc1mr";"gc1ml";"gc1s";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"" +"4";"E39W3";"Snapshot";"";"";"";"";"Desktop";"d1s";"";"d1ml";"d1mr";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"0de0de8ed27a9a67e937a12a65799f6c5c69731c9bcd282054cd21a2faf980db";"Desktop";"Microtower";"d1s";"d1ml";"d1mr";"Wed Sep 21 15:39:24 2022";"Workbench 11.0";"2022-09-21 15:39:24.321860+02:00";"";"";"";"";"p1ml";"0";"0";"Processor 7: model p1ml, S/N p1s";"p1mr";"p1ml";"p1s";"";"1.6";"2410.0";"";"";"";"";"";"";"";"";"";"RamModule 6: model rm1ml, S/N rm1s";"rm1mr";"rm1ml";"rm1s";"";"1333";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"GraphicCard 5: model gc1ml, S/N gc1s";"gc1mr";"gc1ml";"gc1s";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"" diff --git a/tests/files/export_devices.csv b/tests/files/export_devices.csv index e40624f7..5754ab48 100644 --- a/tests/files/export_devices.csv +++ b/tests/files/export_devices.csv @@ -1,2 +1,2 @@ "PHID";"DHID";"Type";"Placeholder Palet";"Placeholder Id Supplier";"Placeholder Info";"Placeholder Components";"Placeholder Type";"Placeholder Serial Number";"Placeholder Part Number";"Placeholder Model";"Placeholder Manufacturer";"DocumentID";"Public Link";"Tag 1 Type";"Tag 1 ID";"Tag 1 Organization";"Tag 2 Type";"Tag 2 ID";"Tag 2 Organization";"Tag 3 Type";"Tag 3 ID";"Tag 3 Organization";"Device Hardware ID";"Device Type";"Device Chassis";"Device Serial Number";"Device Model";"Device Manufacturer";"Registered in";"Registered (process)";"Updated in (software)";"Updated in (web)";"Physical state";"Allocate state";"Lifecycle state";"Processor";"RAM (MB)";"Data Storage Size (MB)";"Processor 1";"Processor 1 Manufacturer";"Processor 1 Model";"Processor 1 Serial Number";"Processor 1 Number of cores";"Processor 1 Speed (GHz)";"Benchmark Processor 1 (points)";"Benchmark ProcessorSysbench Processor 1 (points)";"Processor 2";"Processor 2 Manufacturer";"Processor 2 Model";"Processor 2 Serial Number";"Processor 2 Number of cores";"Processor 2 Speed (GHz)";"Benchmark Processor 2 (points)";"Benchmark ProcessorSysbench Processor 2 (points)";"RamModule 1";"RamModule 1 Manufacturer";"RamModule 1 Model";"RamModule 1 Serial Number";"RamModule 1 Size (MB)";"RamModule 1 Speed (MHz)";"RamModule 2";"RamModule 2 Manufacturer";"RamModule 2 Model";"RamModule 2 Serial Number";"RamModule 2 Size (MB)";"RamModule 2 Speed (MHz)";"RamModule 3";"RamModule 3 Manufacturer";"RamModule 3 Model";"RamModule 3 Serial Number";"RamModule 3 Size (MB)";"RamModule 3 Speed (MHz)";"RamModule 4";"RamModule 4 Manufacturer";"RamModule 4 Model";"RamModule 4 Serial Number";"RamModule 4 Size (MB)";"RamModule 4 Speed (MHz)";"DataStorage 1";"DataStorage 1 Manufacturer";"DataStorage 1 Model";"DataStorage 1 Serial Number";"DataStorage 1 Size (MB)";"Erasure DataStorage 1";"Erasure DataStorage 1 Serial Number";"Erasure DataStorage 1 Size (MB)";"Erasure DataStorage 1 Software";"Erasure DataStorage 1 Result";"Erasure DataStorage 1 Certificate URL";"Erasure DataStorage 1 Type";"Erasure DataStorage 1 Method";"Erasure DataStorage 1 Elapsed (hours)";"Erasure DataStorage 1 Date";"Erasure DataStorage 1 Steps";"Erasure DataStorage 1 Steps Start Time";"Erasure DataStorage 1 Steps End Time";"Benchmark DataStorage 1 Read Speed (MB/s)";"Benchmark DataStorage 1 Writing speed (MB/s)";"Test DataStorage 1 Software";"Test DataStorage 1 Type";"Test DataStorage 1 Result";"Test DataStorage 1 Power cycle count";"Test DataStorage 1 Lifetime (days)";"Test DataStorage 1 Power on hours";"DataStorage 2";"DataStorage 2 Manufacturer";"DataStorage 2 Model";"DataStorage 2 Serial Number";"DataStorage 2 Size (MB)";"Erasure DataStorage 2";"Erasure DataStorage 2 Serial Number";"Erasure DataStorage 2 Size (MB)";"Erasure DataStorage 2 Software";"Erasure DataStorage 2 Result";"Erasure DataStorage 2 Certificate URL";"Erasure DataStorage 2 Type";"Erasure DataStorage 2 Method";"Erasure DataStorage 2 Elapsed (hours)";"Erasure DataStorage 2 Date";"Erasure DataStorage 2 Steps";"Erasure DataStorage 2 Steps Start Time";"Erasure DataStorage 2 Steps End Time";"Benchmark DataStorage 2 Read Speed (MB/s)";"Benchmark DataStorage 2 Writing speed (MB/s)";"Test DataStorage 2 Software";"Test DataStorage 2 Type";"Test DataStorage 2 Result";"Test DataStorage 2 Power cycle count";"Test DataStorage 2 Lifetime (days)";"Test DataStorage 2 Power on hours";"DataStorage 3";"DataStorage 3 Manufacturer";"DataStorage 3 Model";"DataStorage 3 Serial Number";"DataStorage 3 Size (MB)";"Erasure DataStorage 3";"Erasure DataStorage 3 Serial Number";"Erasure DataStorage 3 Size (MB)";"Erasure DataStorage 3 Software";"Erasure DataStorage 3 Result";"Erasure DataStorage 3 Certificate URL";"Erasure DataStorage 3 Type";"Erasure DataStorage 3 Method";"Erasure DataStorage 3 Elapsed (hours)";"Erasure DataStorage 3 Date";"Erasure DataStorage 3 Steps";"Erasure DataStorage 3 Steps Start Time";"Erasure DataStorage 3 Steps End Time";"Benchmark DataStorage 3 Read Speed (MB/s)";"Benchmark DataStorage 3 Writing speed (MB/s)";"Test DataStorage 3 Software";"Test DataStorage 3 Type";"Test DataStorage 3 Result";"Test DataStorage 3 Power cycle count";"Test DataStorage 3 Lifetime (days)";"Test DataStorage 3 Power on hours";"DataStorage 4";"DataStorage 4 Manufacturer";"DataStorage 4 Model";"DataStorage 4 Serial Number";"DataStorage 4 Size (MB)";"Erasure DataStorage 4";"Erasure DataStorage 4 Serial Number";"Erasure DataStorage 4 Size (MB)";"Erasure DataStorage 4 Software";"Erasure DataStorage 4 Result";"Erasure DataStorage 4 Certificate URL";"Erasure DataStorage 4 Type";"Erasure DataStorage 4 Method";"Erasure DataStorage 4 Elapsed (hours)";"Erasure DataStorage 4 Date";"Erasure DataStorage 4 Steps";"Erasure DataStorage 4 Steps Start Time";"Erasure DataStorage 4 Steps End Time";"Benchmark DataStorage 4 Read Speed (MB/s)";"Benchmark DataStorage 4 Writing speed (MB/s)";"Test DataStorage 4 Software";"Test DataStorage 4 Type";"Test DataStorage 4 Result";"Test DataStorage 4 Power cycle count";"Test DataStorage 4 Lifetime (days)";"Test DataStorage 4 Power on hours";"Motherboard 1";"Motherboard 1 Manufacturer";"Motherboard 1 Model";"Motherboard 1 Serial Number";"Display 1";"Display 1 Manufacturer";"Display 1 Model";"Display 1 Serial Number";"GraphicCard 1";"GraphicCard 1 Manufacturer";"GraphicCard 1 Model";"GraphicCard 1 Serial Number";"GraphicCard 1 Memory (MB)";"GraphicCard 2";"GraphicCard 2 Manufacturer";"GraphicCard 2 Model";"GraphicCard 2 Serial Number";"GraphicCard 2 Memory (MB)";"NetworkAdapter 1";"NetworkAdapter 1 Manufacturer";"NetworkAdapter 1 Model";"NetworkAdapter 1 Serial Number";"NetworkAdapter 2";"NetworkAdapter 2 Manufacturer";"NetworkAdapter 2 Model";"NetworkAdapter 2 Serial Number";"SoundCard 1";"SoundCard 1 Manufacturer";"SoundCard 1 Model";"SoundCard 1 Serial Number";"SoundCard 2";"SoundCard 2 Manufacturer";"SoundCard 2 Model";"SoundCard 2 Serial Number";"Device Rate";"Device Range";"Processor Rate";"Processor Range";"RAM Rate";"RAM Range";"Data Storage Rate";"Data Storage Range";"Benchmark RamSysbench (points)" -"10";"E39W3";"Snapshot";"";"";"";"";"Laptop";"b8oaas048285";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"49b3920735c11693c43cef6199af95798ac00dbd61cc3224eae5e9f04d3313fb";"Laptop";"Netbook";"b8oaas048285";"1001pxd";"asustek computer inc.";"Wed Dec 14 12:28:44 2022";"Workbench 11.0a2";"2022-12-14 12:28:44.757147+01:00";"";"";"";"";"intel atom cpu n455 @ 2.66ghz";"1024";"238475";"Processor 7: model intel atom cpu n455 @ 2.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 2.66ghz";"";"1";"2.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 11: model None, S/N None";"";"";"";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 12: model hts54322, S/N e2024242cv86mm";"hitachi";"hts54322";"e2024242cv86mm";"238475";"8558ea99955f34c788cb72174c0ec165e0398306efbc0efe40b280b65d16d0d0";"e2024242cv86mm";"238475";"Workbench 11.0a2";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-12-14 12:28:44.712329+01:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0a2";"Short";"Failure";"";"";"0";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 13: model 1001pxd, S/N eee0123456720";"asustek computer inc.";"1001pxd";"eee0123456720";"";"";"";"";"GraphicCard 8: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 5: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c9";"NetworkAdapter 6: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7b";"SoundCard 9: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 10: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" +"10";"E39W3";"Snapshot";"";"";"";"";"Laptop";"b8oaas048285";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"83cb9066430a8ea7def04af61d521d6517193a486c02ea3bc914c9eaeb2b718b";"Laptop";"Netbook";"b8oaas048285";"1001pxd";"asustek computer inc.";"Wed Dec 14 12:28:44 2022";"Workbench 11.0a2";"2022-12-14 12:28:44.757147+01:00";"";"";"";"";"intel atom cpu n455 @ 2.66ghz";"1024";"238475";"Processor 7: model intel atom cpu n455 @ 2.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 2.66ghz";"";"1";"2.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 11: model None, S/N None";"";"";"";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 12: model hts54322, S/N e2024242cv86mm";"hitachi";"hts54322";"e2024242cv86mm";"238475";"8558ea99955f34c788cb72174c0ec165e0398306efbc0efe40b280b65d16d0d0";"e2024242cv86mm";"238475";"Workbench 11.0a2";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-12-14 12:28:44.712329+01:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0a2";"Short";"Failure";"";"";"0";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 13: model 1001pxd, S/N eee0123456720";"asustek computer inc.";"1001pxd";"eee0123456720";"";"";"";"";"GraphicCard 8: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 5: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c9";"NetworkAdapter 6: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7b";"SoundCard 9: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 10: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" diff --git a/tests/files/proposal_extended_csv_report.csv b/tests/files/proposal_extended_csv_report.csv index 64ed1795..73608689 100644 --- a/tests/files/proposal_extended_csv_report.csv +++ b/tests/files/proposal_extended_csv_report.csv @@ -1,3 +1,3 @@ "PHID";"DHID";"Type";"Placeholder Palet";"Placeholder Id Supplier";"Placeholder Info";"Placeholder Components";"Placeholder Type";"Placeholder Serial Number";"Placeholder Part Number";"Placeholder Model";"Placeholder Manufacturer";"DocumentID";"Public Link";"Tag 1 Type";"Tag 1 ID";"Tag 1 Organization";"Tag 2 Type";"Tag 2 ID";"Tag 2 Organization";"Tag 3 Type";"Tag 3 ID";"Tag 3 Organization";"Device Hardware ID";"Device Type";"Device Chassis";"Device Serial Number";"Device Model";"Device Manufacturer";"Registered in";"Registered (process)";"Updated in (software)";"Updated in (web)";"Physical state";"Allocate state";"Lifecycle state";"Processor";"RAM (MB)";"Data Storage Size (MB)";"Processor 1";"Processor 1 Manufacturer";"Processor 1 Model";"Processor 1 Serial Number";"Processor 1 Number of cores";"Processor 1 Speed (GHz)";"Benchmark Processor 1 (points)";"Benchmark ProcessorSysbench Processor 1 (points)";"Processor 2";"Processor 2 Manufacturer";"Processor 2 Model";"Processor 2 Serial Number";"Processor 2 Number of cores";"Processor 2 Speed (GHz)";"Benchmark Processor 2 (points)";"Benchmark ProcessorSysbench Processor 2 (points)";"RamModule 1";"RamModule 1 Manufacturer";"RamModule 1 Model";"RamModule 1 Serial Number";"RamModule 1 Size (MB)";"RamModule 1 Speed (MHz)";"RamModule 2";"RamModule 2 Manufacturer";"RamModule 2 Model";"RamModule 2 Serial Number";"RamModule 2 Size (MB)";"RamModule 2 Speed (MHz)";"RamModule 3";"RamModule 3 Manufacturer";"RamModule 3 Model";"RamModule 3 Serial Number";"RamModule 3 Size (MB)";"RamModule 3 Speed (MHz)";"RamModule 4";"RamModule 4 Manufacturer";"RamModule 4 Model";"RamModule 4 Serial Number";"RamModule 4 Size (MB)";"RamModule 4 Speed (MHz)";"DataStorage 1";"DataStorage 1 Manufacturer";"DataStorage 1 Model";"DataStorage 1 Serial Number";"DataStorage 1 Size (MB)";"Erasure DataStorage 1";"Erasure DataStorage 1 Serial Number";"Erasure DataStorage 1 Size (MB)";"Erasure DataStorage 1 Software";"Erasure DataStorage 1 Result";"Erasure DataStorage 1 Certificate URL";"Erasure DataStorage 1 Type";"Erasure DataStorage 1 Method";"Erasure DataStorage 1 Elapsed (hours)";"Erasure DataStorage 1 Date";"Erasure DataStorage 1 Steps";"Erasure DataStorage 1 Steps Start Time";"Erasure DataStorage 1 Steps End Time";"Benchmark DataStorage 1 Read Speed (MB/s)";"Benchmark DataStorage 1 Writing speed (MB/s)";"Test DataStorage 1 Software";"Test DataStorage 1 Type";"Test DataStorage 1 Result";"Test DataStorage 1 Power cycle count";"Test DataStorage 1 Lifetime (days)";"Test DataStorage 1 Power on hours";"DataStorage 2";"DataStorage 2 Manufacturer";"DataStorage 2 Model";"DataStorage 2 Serial Number";"DataStorage 2 Size (MB)";"Erasure DataStorage 2";"Erasure DataStorage 2 Serial Number";"Erasure DataStorage 2 Size (MB)";"Erasure DataStorage 2 Software";"Erasure DataStorage 2 Result";"Erasure DataStorage 2 Certificate URL";"Erasure DataStorage 2 Type";"Erasure DataStorage 2 Method";"Erasure DataStorage 2 Elapsed (hours)";"Erasure DataStorage 2 Date";"Erasure DataStorage 2 Steps";"Erasure DataStorage 2 Steps Start Time";"Erasure DataStorage 2 Steps End Time";"Benchmark DataStorage 2 Read Speed (MB/s)";"Benchmark DataStorage 2 Writing speed (MB/s)";"Test DataStorage 2 Software";"Test DataStorage 2 Type";"Test DataStorage 2 Result";"Test DataStorage 2 Power cycle count";"Test DataStorage 2 Lifetime (days)";"Test DataStorage 2 Power on hours";"DataStorage 3";"DataStorage 3 Manufacturer";"DataStorage 3 Model";"DataStorage 3 Serial Number";"DataStorage 3 Size (MB)";"Erasure DataStorage 3";"Erasure DataStorage 3 Serial Number";"Erasure DataStorage 3 Size (MB)";"Erasure DataStorage 3 Software";"Erasure DataStorage 3 Result";"Erasure DataStorage 3 Certificate URL";"Erasure DataStorage 3 Type";"Erasure DataStorage 3 Method";"Erasure DataStorage 3 Elapsed (hours)";"Erasure DataStorage 3 Date";"Erasure DataStorage 3 Steps";"Erasure DataStorage 3 Steps Start Time";"Erasure DataStorage 3 Steps End Time";"Benchmark DataStorage 3 Read Speed (MB/s)";"Benchmark DataStorage 3 Writing speed (MB/s)";"Test DataStorage 3 Software";"Test DataStorage 3 Type";"Test DataStorage 3 Result";"Test DataStorage 3 Power cycle count";"Test DataStorage 3 Lifetime (days)";"Test DataStorage 3 Power on hours";"DataStorage 4";"DataStorage 4 Manufacturer";"DataStorage 4 Model";"DataStorage 4 Serial Number";"DataStorage 4 Size (MB)";"Erasure DataStorage 4";"Erasure DataStorage 4 Serial Number";"Erasure DataStorage 4 Size (MB)";"Erasure DataStorage 4 Software";"Erasure DataStorage 4 Result";"Erasure DataStorage 4 Certificate URL";"Erasure DataStorage 4 Type";"Erasure DataStorage 4 Method";"Erasure DataStorage 4 Elapsed (hours)";"Erasure DataStorage 4 Date";"Erasure DataStorage 4 Steps";"Erasure DataStorage 4 Steps Start Time";"Erasure DataStorage 4 Steps End Time";"Benchmark DataStorage 4 Read Speed (MB/s)";"Benchmark DataStorage 4 Writing speed (MB/s)";"Test DataStorage 4 Software";"Test DataStorage 4 Type";"Test DataStorage 4 Result";"Test DataStorage 4 Power cycle count";"Test DataStorage 4 Lifetime (days)";"Test DataStorage 4 Power on hours";"Motherboard 1";"Motherboard 1 Manufacturer";"Motherboard 1 Model";"Motherboard 1 Serial Number";"Display 1";"Display 1 Manufacturer";"Display 1 Model";"Display 1 Serial Number";"GraphicCard 1";"GraphicCard 1 Manufacturer";"GraphicCard 1 Model";"GraphicCard 1 Serial Number";"GraphicCard 1 Memory (MB)";"GraphicCard 2";"GraphicCard 2 Manufacturer";"GraphicCard 2 Model";"GraphicCard 2 Serial Number";"GraphicCard 2 Memory (MB)";"NetworkAdapter 1";"NetworkAdapter 1 Manufacturer";"NetworkAdapter 1 Model";"NetworkAdapter 1 Serial Number";"NetworkAdapter 2";"NetworkAdapter 2 Manufacturer";"NetworkAdapter 2 Model";"NetworkAdapter 2 Serial Number";"SoundCard 1";"SoundCard 1 Manufacturer";"SoundCard 1 Model";"SoundCard 1 Serial Number";"SoundCard 2";"SoundCard 2 Manufacturer";"SoundCard 2 Model";"SoundCard 2 Serial Number";"Device Rate";"Device Range";"Processor Rate";"Processor Range";"RAM Rate";"RAM Range";"Data Storage Rate";"Data Storage Range";"Benchmark RamSysbench (points)" -"10";"E39W3";"Snapshot";"";"";"";"";"Laptop";"b8oaas048285";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b";"Laptop";"Netbook";"b8oaas048285";"1001pxd";"asustek computer inc.";"Wed Sep 21 15:41:31 2022";"Workbench 11.0a2";"2022-09-21 15:41:31.084078+02:00";"";"";"";"";"intel atom cpu n455 @ 2.66ghz";"1024";"238475";"Processor 7: model intel atom cpu n455 @ 2.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 2.66ghz";"";"1";"2.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 11: model None, S/N None";"";"";"";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 12: model hts54322, S/N e2024242cv86mm";"hitachi";"hts54322";"e2024242cv86mm";"238475";"harddrive-hitachi-hts54322-e2024242cv86mm";"e2024242cv86mm";"238475";"Workbench 11.0a2";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-09-21 15:41:31.030798+02:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0a2";"Short";"Failure";"";"";"0";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 13: model 1001pxd, S/N eee0123456720";"asustek computer inc.";"1001pxd";"eee0123456720";"";"";"";"";"GraphicCard 8: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 5: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c9";"NetworkAdapter 6: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7b";"SoundCard 9: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 10: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" -"24";"45VG4";"Snapshot";"";"";"";"";"Laptop";"b8oaas048287";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/45VG4";"";"";"";"";"";"";"";"";"";"laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c";"Laptop";"Netbook";"b8oaas048287";"1001pxd";"asustek computer inc.";"Wed Sep 21 15:41:31 2022";"Workbench 11.0b11";"2022-09-21 15:41:31.398843+02:00";"";"";"";"";"intel atom cpu n455 @ 1.66ghz";"2048";"558558";"Processor 28: model intel atom cpu n455 @ 1.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 1.66ghz";"";"1";"1.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 32: model None, S/N None";"";"";"";"1024";"667";"RamModule 33: model 48594d503131325336344350362d53362020, S/N 4f43487b";"hynix semiconductor";"48594d503131325336344350362d53362020";"4f43487b";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 34: model hts54322, S/N e2024242cv86hj";"hitachi";"hts54322";"e2024242cv86hj";"238475";"harddrive-hitachi-hts54322-e2024242cv86hj";"e2024242cv86hj";"238475";"Workbench 11.0b11";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-09-21 15:41:31.340555+02:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0b11";"Extended";"Failure";"";"";"0";"DataStorage 35: model wdc wd1600bevt-2, S/N wd-wx11a80w7430";"western digital";"wdc wd1600bevt-2";"wd-wx11a80w7430";"160041";"datastorage-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430";"wd-wx11a80w7430";"160041";"Workbench 11.0b11";"Failure";"";"EraseBasic";"Shred";"0:45:36";"2022-09-21 15:41:31.342722+02:00";"✓ – StepRandom 0:45:36";"2019-10-23 09:49:54.410830+02:00";"2019-10-23 10:35:31.400587+02:00";"41.6";"17.3";"Workbench 11.0b11";"Short";"Success";"5293";"195 days, 12:00:00";"4692";"SolidStateDrive 36: model wdc wd1600bevt-2, S/N wd-wx11a80w7430";"western digital";"wdc wd1600bevt-2";"wd-wx11a80w7430";"160042";"solidstatedrive-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430";"wd-wx11a80w7430";"160042";"Workbench 11.0b11";"Success";"";"EraseSectors";"Badblocks";"1:46:03";"2022-09-21 15:41:31.346565+02:00";"✓ – StepRandom 0:46:03,✓ – StepZero 1:00:00";"2019-08-19 18:48:19.690458+02:00,2019-08-19 19:34:22.690458+02:00";"2019-08-19 19:34:22.930562+02:00,2019-08-19 20:34:22.930562+02:00";"41.1";"17.1";"Workbench 11.0b11";"Short";"Success";"5231";"194 days, 17:00:00";"4673";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 37: model 1001pxd, S/N eee0123456789";"asustek computer inc.";"1001pxd";"eee0123456789";"";"auo ""auo""";"auo lcd monitor";"";"GraphicCard 29: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 26: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c8";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c8";"NetworkAdapter 27: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7c";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7c";"SoundCard 30: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 31: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" +"10";"E39W3";"Snapshot";"";"";"";"";"Laptop";"b8oaas048285";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/E39W3";"";"";"";"";"";"";"";"";"";"83cb9066430a8ea7def04af61d521d6517193a486c02ea3bc914c9eaeb2b718b";"Laptop";"Netbook";"b8oaas048285";"1001pxd";"asustek computer inc.";"Wed Sep 21 15:41:31 2022";"Workbench 11.0a2";"2022-09-21 15:41:31.084078+02:00";"";"";"";"";"intel atom cpu n455 @ 2.66ghz";"1024";"238475";"Processor 7: model intel atom cpu n455 @ 2.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 2.66ghz";"";"1";"2.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 11: model None, S/N None";"";"";"";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 12: model hts54322, S/N e2024242cv86mm";"hitachi";"hts54322";"e2024242cv86mm";"238475";"8558ea99955f34c788cb72174c0ec165e0398306efbc0efe40b280b65d16d0d0";"e2024242cv86mm";"238475";"Workbench 11.0a2";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-09-21 15:41:31.030798+02:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0a2";"Short";"Failure";"";"";"0";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 13: model 1001pxd, S/N eee0123456720";"asustek computer inc.";"1001pxd";"eee0123456720";"";"";"";"";"GraphicCard 8: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 5: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c9";"NetworkAdapter 6: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7b";"SoundCard 9: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 10: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" +"24";"45VG4";"Snapshot";"";"";"";"";"Laptop";"b8oaas048287";"";"1001pxd";"asustek computer inc.";"";"http://localhost/devices/45VG4";"";"";"";"";"";"";"";"";"";"c3c6726385eb7e43a7476512236fe27fa234028c394237344d6b403611c25564";"Laptop";"Netbook";"b8oaas048287";"1001pxd";"asustek computer inc.";"Wed Sep 21 15:41:31 2022";"Workbench 11.0b11";"2022-09-21 15:41:31.398843+02:00";"";"";"";"";"intel atom cpu n455 @ 1.66ghz";"2048";"558558";"Processor 28: model intel atom cpu n455 @ 1.66ghz, S/N None";"intel corp.";"intel atom cpu n455 @ 1.66ghz";"";"1";"1.667";"6666.24";"164.0803";"";"";"";"";"";"";"";"";"RamModule 32: model None, S/N None";"";"";"";"1024";"667";"RamModule 33: model 48594d503131325336344350362d53362020, S/N 4f43487b";"hynix semiconductor";"48594d503131325336344350362d53362020";"4f43487b";"1024";"667";"";"";"";"";"";"";"";"";"";"";"";"";"HardDrive 34: model hts54322, S/N e2024242cv86hj";"hitachi";"hts54322";"e2024242cv86hj";"238475";"092462ec48ccf594fa369eb55c7026de4b56620f3430fb09a840ed3769b99851";"e2024242cv86hj";"238475";"Workbench 11.0b11";"Success";"";"EraseBasic";"Shred";"1:16:49";"2022-09-21 15:41:31.340555+02:00";"✓ – StepRandom 1:16:49";"2018-07-03 11:15:22.257059+02:00";"2018-07-03 12:32:11.843190+02:00";"66.2";"21.8";"Workbench 11.0b11";"Extended";"Failure";"";"";"0";"DataStorage 35: model wdc wd1600bevt-2, S/N wd-wx11a80w7430";"western digital";"wdc wd1600bevt-2";"wd-wx11a80w7430";"160041";"datastorage-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430";"wd-wx11a80w7430";"160041";"Workbench 11.0b11";"Failure";"";"EraseBasic";"Shred";"0:45:36";"2022-09-21 15:41:31.342722+02:00";"✓ – StepRandom 0:45:36";"2019-10-23 09:49:54.410830+02:00";"2019-10-23 10:35:31.400587+02:00";"41.6";"17.3";"Workbench 11.0b11";"Short";"Success";"5293";"195 days, 12:00:00";"4692";"SolidStateDrive 36: model wdc wd1600bevt-2, S/N wd-wx11a80w7430";"western digital";"wdc wd1600bevt-2";"wd-wx11a80w7430";"160042";"c5856fc1632d695a7eccf5062667d15439ec3c765245ba3fa60272c335d6e83f";"wd-wx11a80w7430";"160042";"Workbench 11.0b11";"Success";"";"EraseSectors";"Badblocks";"1:46:03";"2022-09-21 15:41:31.346565+02:00";"✓ – StepRandom 0:46:03,✓ – StepZero 1:00:00";"2019-08-19 18:48:19.690458+02:00,2019-08-19 19:34:22.690458+02:00";"2019-08-19 19:34:22.930562+02:00,2019-08-19 20:34:22.930562+02:00";"41.1";"17.1";"Workbench 11.0b11";"Short";"Success";"5231";"194 days, 17:00:00";"4673";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"Motherboard 37: model 1001pxd, S/N eee0123456789";"asustek computer inc.";"1001pxd";"eee0123456789";"";"auo ""auo""";"auo lcd monitor";"";"GraphicCard 29: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None";"intel corporation";"atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller";"";"256";"";"";"";"";"";"NetworkAdapter 26: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c8";"qualcomm atheros";"ar9285 wireless network adapter";"74:2f:68:8b:fd:c8";"NetworkAdapter 27: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7c";"qualcomm atheros";"ar8152 v2.0 fast ethernet";"14:da:e9:42:f6:7c";"SoundCard 30: model nm10/ich7 family high definition audio controller, S/N None";"intel corporation";"nm10/ich7 family high definition audio controller";"";"SoundCard 31: model usb 2.0 uvc vga webcam, S/N 0x0001";"azurewave";"usb 2.0 uvc vga webcam";"0x0001";"";"";"";"";"";"";"";"";"15.7188" diff --git a/tests/test_action.py b/tests/test_action.py index 40e9cd15..9ccb07a3 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -2941,7 +2941,7 @@ def test_delete_devices_check_sync(user: UserClient): in [y.device.id for y in x.actions if hasattr(y, 'device')] ] ) - == 1 + == 2 ) diff --git a/tests/test_device.py b/tests/test_device.py index ac8c1d07..c4e961bc 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -141,47 +141,14 @@ def test_physical_properties(): 'ram_slots': None, } assert pc.physical_properties == { - 'chassis': ComputerChassis.Tower, 'amount': 0, 'manufacturer': 'bar', 'model': 'foo', - 'receiver_id': None, 'serial_number': 'foo-bar', 'part_number': None, - 'transfer_state': TransferState.Initial, } -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_component_similar_one(): - user = User.query.filter().first() - snapshot = yaml2json('pc-components.db') - pc = snapshot['device'] - snapshot['components'][0]['serial_number'] = snapshot['components'][1][ - 'serial_number' - ] = None - pc = d.Desktop( - **pc, components=OrderedSet(d.Component(**c) for c in snapshot['components']) - ) - component1, component2 = pc.components # type: d.Component - db.session.add(pc) - db.session.flush() - # Let's create a new component named 'A' similar to 1 - componentA = d.Component( - model=component1.model, manufacturer=component1.manufacturer, owner_id=user.id - ) - similar_to_a = componentA.similar_one(pc, set()) - assert similar_to_a == component1 - # d.Component B does not have the same model - componentB = d.Component(model='nope', manufacturer=component1.manufacturer) - with pytest.raises(ResourceNotFound): - assert componentB.similar_one(pc, set()) - # If we blacklist component A we won't get anything - with pytest.raises(ResourceNotFound): - assert componentA.similar_one(pc, blacklist={componentA.id}) - - @pytest.mark.mvp @pytest.mark.usefixtures(conftest.auth_app_context.__name__) def test_add_remove(): @@ -301,69 +268,6 @@ def test_sync_execute_register_desktop_no_hid_no_tag(user: UserClient): assert returned_pc == pc -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_sync_execute_register_desktop_tag_not_linked(): - """Syncs a new d.Desktop with HID and a non-linked tag. - - It is OK if the tag was not linked, it will be linked in this process. - """ - tag = Tag(id='foo') - db.session.add(tag) - db.session.commit() - - # Create a new transient non-db object - pc = d.Desktop( - **yaml2json('pc-components.db')['device'], tags=OrderedSet([Tag(id='foo')]) - ) - returned_pc = Sync().execute_register(pc) - assert returned_pc == pc - assert tag.device == pc, 'Tag has to be linked' - assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db' - - -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str): - """Validates registering a d.Desktop without HID and a non-linked tag. - - In this case it is ok still, as the non-linked tag proves that - the d.Desktop was not existing before (otherwise the tag would - be linked), and thus it creates a new d.Desktop. - """ - tag = Tag(id=tag_id) - pc = d.Desktop(**yaml2json('pc-components.db')['device'], tags=OrderedSet([tag])) - db.session.add(g.user) - returned_pc = Sync().execute_register(pc) - db.session.commit() - assert returned_pc == pc - db_tag = next(iter(returned_pc.tags)) - # they are not the same tags though - # tag is a transient obj and db_tag the one from the db - # they have the same pk though - assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db' - assert tag != db_tag, 'They are not the same tags though' - for tag in pc.tags: - assert tag.id in ['foo', pc.devicehub_id] - - -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_sync_execute_register_tag_does_not_exist(): - """Ensures not being able to register if the tag does not exist, - even if the device has HID or it existed before. - - Tags have to be created before trying to link them through a Snapshot. - """ - user = User.query.filter().first() - pc = d.Desktop( - **yaml2json('pc-components.db')['device'], tags=OrderedSet([Tag('foo')]) - ) - pc.owner_id = user.id - with raises(ResourceNotFound): - Sync().execute_register(pc) - - @pytest.mark.mvp @pytest.mark.usefixtures(conftest.auth_app_context.__name__) def test_sync_execute_register_tag_linked_same_device(): @@ -387,53 +291,6 @@ def test_sync_execute_register_tag_linked_same_device(): assert tag.id in ['foo', db_pc.devicehub_id] -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_sync_execute_register_tag_linked_other_device_mismatch_between_tags(): - """Checks that sync raises an error if finds that at least two passed-in - tags are not linked to the same device. - """ - pc1 = d.Desktop(**yaml2json('pc-components.db')['device']) - db.session.add(Tag(id='foo-1', device=pc1)) - pc2 = d.Desktop(**yaml2json('pc-components.db')['device']) - pc2.serial_number = 'pc2-serial' - pc2.hid = Naming.hid(pc2.type, pc2.manufacturer, pc2.model, pc2.serial_number) - db.session.add(Tag(id='foo-2', device=pc2)) - db.session.commit() - - pc1 = d.Desktop( - **yaml2json('pc-components.db')['device'] - ) # Create a new transient non-db object - pc1.tags.add(Tag(id='foo-1')) - pc1.tags.add(Tag(id='foo-2')) - with raises(MismatchBetweenTags): - Sync().execute_register(pc1) - - -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_sync_execute_register_mismatch_between_tags_and_hid(): - """Checks that sync raises an error if it finds that the HID does - not point at the same device as the tag does. - - In this case we set HID -> pc1 but tag -> pc2 - """ - pc1 = d.Desktop(**yaml2json('pc-components.db')['device']) - db.session.add(Tag(id='foo-1', device=pc1)) - pc2 = d.Desktop(**yaml2json('pc-components.db')['device']) - pc2.serial_number = 'pc2-serial' - pc2.hid = Naming.hid(pc2.type, pc2.manufacturer, pc2.model, pc2.serial_number) - db.session.add(Tag(id='foo-2', device=pc2)) - db.session.commit() - - pc1 = d.Desktop( - **yaml2json('pc-components.db')['device'] - ) # Create a new transient non-db object - pc1.tags.add(Tag(id='foo-2')) - with raises(MismatchBetweenTagsAndHid): - Sync().execute_register(pc1) - - @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_get_device(user: UserClient): @@ -753,138 +610,10 @@ def test_cooking_mixer_api(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) -def test_hid_with_mac(app: Devicehub, user: UserClient): +def test_hid_with_placeholder(app: Devicehub, user: UserClient): """Checks hid with mac.""" snapshot = file('asus-eee-1000h.snapshot.11') snap, _ = user.post(snapshot, res=m.Snapshot) pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) - assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one() - assert ( - pc.placeholder.binding.hid - == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' - ) - - -@pytest.mark.mvp -def test_hid_without_mac(app: Devicehub, user: UserClient): - """Checks hid without mac.""" - snapshot = yaml2json('asus-eee-1000h.snapshot.11') - snapshot['components'] = [ - c for c in snapshot['components'] if c['type'] != 'NetworkAdapter' - ] - snap, _ = user.post(json_encode(snapshot), res=m.Snapshot) - pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) - assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' - - -@pytest.mark.mvp -def test_hid_with_mac_none(app: Devicehub, user: UserClient): - """Checks hid with mac = None.""" - snapshot = yaml2json('asus-eee-1000h.snapshot.11') - network = [c for c in snapshot['components'] if c['type'] == 'NetworkAdapter'][0] - network['serialNumber'] = None - snap, _ = user.post(json_encode(snapshot), res=m.Snapshot) - pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) - assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' - - -@pytest.mark.mvp -def test_hid_with_2networkadapters(app: Devicehub, user: UserClient): - """Checks hid with 2 networks adapters""" - snapshot = yaml2json('asus-eee-1000h.snapshot.11') - network = [c for c in snapshot['components'] if c['type'] == 'NetworkAdapter'][0] - network2 = copy.copy(network) - snapshot['components'].append(network2) - network['serialNumber'] = 'a0:24:8c:7f:cf:2d' - user.post(json_encode(snapshot), res=m.Snapshot) - devices, _ = user.get(res=d.Device) - - laptop = devices['items'][0] - assert ( - laptop['hid'] - == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' - ) - assert len([c for c in devices['items'] if c['type'] == 'Laptop']) == 2 - - -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.app_context.__name__) -def test_hid_with_2network_and_drop_no_mac_in_hid(app: Devicehub, user: UserClient): - """Checks hid with 2 networks adapters and next drop the network is not used in hid""" - snapshot = yaml2json('asus-eee-1000h.snapshot.11') - network = [c for c in snapshot['components'] if c['type'] == 'NetworkAdapter'][0] - network2 = copy.copy(network) - snapshot['components'].append(network2) - network['serialNumber'] = 'a0:24:8c:7f:cf:2d' - snap, _ = user.post(json_encode(snapshot), res=m.Snapshot) - pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) - assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' - pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one() - assert ( - pc.placeholder.binding.hid - == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' - ) - - snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abb' - snapshot['components'] = [c for c in snapshot['components'] if c != network] - user.post(json_encode(snapshot), res=m.Snapshot) - devices, _ = user.get(res=d.Device) - laptop = devices['items'][0] - assert ( - pc.placeholder.binding.hid - == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' - ) - assert len([c for c in devices['items'] if c['type'] == 'Laptop']) == 2 - assert len([c for c in laptop['components'] if c['type'] == 'NetworkAdapter']) == 1 - - -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.app_context.__name__) -def test_hid_with_2network_and_drop_mac_in_hid(app: Devicehub, user: UserClient): - """Checks hid with 2 networks adapters and next drop the network is used in hid""" - # One tipical snapshot with 2 network cards - snapshot = yaml2json('asus-eee-1000h.snapshot.11') - network = [c for c in snapshot['components'] if c['type'] == 'NetworkAdapter'][0] - network2 = copy.copy(network) - snapshot['components'].append(network2) - network['serialNumber'] = 'a0:24:8c:7f:cf:2d' - snap, _ = user.post(json_encode(snapshot), res=m.Snapshot) - pc, _ = user.get(res=d.Device, item=snap['device']['devicehubID']) - assert pc['hid'] == 'laptop-asustek_computer_inc-1000h-94oaaq021116' - pc = d.Device.query.filter_by(devicehub_id=snap['device']['devicehubID']).one() - assert ( - pc.placeholder.binding.hid - == 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d' - ) - - # we drop the network card then is used for to build the hid - snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abb' - snapshot['components'] = [c for c in snapshot['components'] if c != network2] - user.post(json_encode(snapshot), res=m.Snapshot) - devices, _ = user.get(res=d.Device) - laptops = [c for c in devices['items'] if c['type'] == 'Laptop'] - assert len(laptops) == 4 - hids = [laptops[0]['hid'], laptops[2]['hid']] - proof_hid = [ - 'laptop-asustek_computer_inc-1000h-94oaaq021116-a0:24:8c:7f:cf:2d', - 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d', - ] - assert all([h in proof_hid for h in hids]) - - # we drop all network cards - snapshot['uuid'] = 'd1b70cb8-8929-4f36-99b7-fe052cec0abc' - snapshot['components'] = [ - c for c in snapshot['components'] if c not in [network, network2] - ] - user.post(json_encode(snapshot), res=m.Snapshot) - devices, _ = user.get(res=d.Device) - laptops = [c for c in devices['items'] if c['type'] == 'Laptop'] - assert len(laptops) == 4 - hids = [laptops[0]['hid'], laptops[2]['hid']] - proof_hid = [ - 'laptop-asustek_computer_inc-1000h-94oaaq021116-a0:24:8c:7f:cf:2d', - 'laptop-asustek_computer_inc-1000h-94oaaq021116-00:24:8c:7f:cf:2d', - 'laptop-asustek_computer_inc-1000h-94oaaq021116', - ] - assert all([h in proof_hid for h in hids]) + assert pc.placeholder.binding.hid == pc.hid diff --git a/tests/test_metrics.py b/tests/test_metrics.py index d881d524..706e7260 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -6,24 +6,29 @@ from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.tradedocument.models import TradeDocument from tests import conftest -from tests.conftest import file, yaml2json, json_encode +from tests.conftest import file, json_encode, yaml2json @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_simple_metrics(user: UserClient): - """ Checks one standard query of metrics """ + """Checks one standard query of metrics""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') acer = yaml2json('acer.happy.battery.snapshot') user.post(json_encode(lenovo), res=ma.Snapshot) snapshot, _ = user.post(json_encode(acer), res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, - "finalUserCode": "abcdefjhi", - "devices": [device_id], "description": "aaa", - "startTime": "2020-11-01T02:00:00+00:00", - "endTime": "2020-12-01T02:00:00+00:00"} + post_request = { + "transaction": "ccc", + "name": "John", + "endUsers": 1, + "finalUserCode": "abcdefjhi", + "devices": [device_id], + "description": "aaa", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00", + } # Create Allocate user.post(res=ma.Allocate, data=post_request) @@ -58,16 +63,21 @@ def test_simple_metrics(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_second_hdd_metrics(user: UserClient): - """ Checks one standard query of metrics """ + """Checks one standard query of metrics""" # Insert computer acer = yaml2json('acer.happy.battery.snapshot') snapshot, _ = user.post(json_encode(acer), res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, - "finalUserCode": "abcdefjhi", - "devices": [device_id], "description": "aaa", - "startTime": "2020-11-01T02:00:00+00:00", - "endTime": "2020-12-01T02:00:00+00:00"} + post_request = { + "transaction": "ccc", + "name": "John", + "endUsers": 1, + "finalUserCode": "abcdefjhi", + "devices": [device_id], + "description": "aaa", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00", + } # Create Allocate user.post(res=ma.Allocate, data=post_request) @@ -101,16 +111,21 @@ def test_second_hdd_metrics(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_metrics_with_live_null(user: UserClient): - """ Checks one standard query of metrics """ + """Checks one standard query of metrics""" # Insert computer acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, - "finalUserCode": "abcdefjhi", - "devices": [device_id], "description": "aaa", - "startTime": "2020-11-01T02:00:00+00:00", - "endTime": "2020-12-01T02:00:00+00:00"} + post_request = { + "transaction": "ccc", + "name": "John", + "endUsers": 1, + "finalUserCode": "abcdefjhi", + "devices": [device_id], + "description": "aaa", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00", + } # Create Allocate user.post(res=ma.Allocate, data=post_request) @@ -124,19 +139,29 @@ def test_metrics_with_live_null(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_metrics_action_status(user: UserClient, user2: UserClient): - """ Checks one standard query of metrics.""" + """Checks one standard query of metrics.""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') snap, _ = user.post(json_encode(lenovo), res=ma.Snapshot) device_id = snap['device']['id'] action = {'type': ma.Use.t, 'devices': [device_id]} action_use, _ = user.post(action, res=ma.Action) - csv_str, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': [device_id]})]) - head = '"DHID";"Hid";"Document-Name";"Action-Type";"Action-User-LastOwner-Supplier";"Action-User-LastOwner-Receiver";"Action-Create-By";"Trade-Confirmed";"Status-Created-By-Supplier-About-Reciber";"Status-Receiver";"Status Supplier – Created Date";"Status Receiver – Created Date";"Trade-Weight";"Action-Create";"Allocate-Start";"Allocate-User-Code";"Allocate-NumUsers";"UsageTimeAllocate";"Type";"LiveCreate";"UsageTimeHdd"\n' - body = '"O48N2";"desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10";"";"Status";"";"foo@foo.com";"Receiver";"";"";"Use";"";"' + csv_str, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': [device_id]})], + ) + head = ( + '"DHID";"Hid";"Document-Name";"Action-Type";"Action-User-LastOwner-Supplier";' + ) + head += '"Action-User-LastOwner-Receiver";"Action-Create-By";"Trade-Confirmed";' + head += '"Status-Created-By-Supplier-About-Reciber";"Status-Receiver";' + head += '"Status Supplier – Created Date";"Status Receiver – Created Date";"Trade-Weight";' + head += '"Action-Create";"Allocate-Start";"Allocate-User-Code";"Allocate-NumUsers";' + head += '"UsageTimeAllocate";"Type";"LiveCreate";"UsageTimeHdd"\n' + body = '"O48N2";"adebcc5506213fac43cd8473a9c81bcf0cadaed9cb98b2eae651e377a3533c5a";' + body += '"";"Status";"";"foo@foo.com";"Receiver";"";"";"Use";"";"' assert head in csv_str assert body in csv_str @@ -144,7 +169,7 @@ def test_metrics_action_status(user: UserClient, user2: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): - """ Checks one standard query of metrics in a trade enviroment.""" + """Checks one standard query of metrics in a trade enviroment.""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') acer = yaml2json('acer.happy.battery.snapshot') @@ -154,12 +179,8 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): device1_id = snap1['device']['id'] device2_id = snap2['device']['id'] devices_id = [device1_id, device2_id] - devices = [('id', device1_id), - ('id', snap2['device']['id'])] - lot, _ = user.post({}, - res=Lot, - item='{}/devices'.format(lot['id']), - query=devices) + devices = [('id', device1_id), ('id', snap2['device']['id'])] + lot, _ = user.post({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices) action = {'type': ma.Refurbish.t, 'devices': [device1_id]} user.post(action, res=ma.Action) @@ -179,17 +200,21 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): action = {'type': ma.Use.t, 'devices': [device1_id]} action_use, _ = user.post(action, res=ma.Action) - csv_str, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': devices_id})]) + csv_str, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': devices_id})], + ) - body1_lenovo = '"O48N2";"desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10";"";"Trade";"foo@foo.com";' + body1_lenovo = '"O48N2";"adebcc5506213fac43cd8473a9c81bcf0cadaed9cb98b2eae651e377a3533c5a";"";"Trade";"foo@foo.com";' body1_lenovo += '"foo2@foo.com";"Supplier";"NeedConfirmation";"Use";"";' body2_lenovo = ';"";"0";"0";"Trade";"0";"0"\n' - body1_acer = '"K3XW2";"laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c";"";"Trade";' - body1_acer += '"foo@foo.com";"foo2@foo.com";"Supplier";"NeedConfirmation";"";"";"";"";"0";' + body1_acer = '"K3XW2";"55b1f6d0692d1569c7590f0aeabd1c9874a1c78b8dd3a7d481df95923a629748";"";"Trade";' + body1_acer += ( + '"foo@foo.com";"foo2@foo.com";"Supplier";"NeedConfirmation";"";"";"";"";"0";' + ) body2_acer = ';"";"0";"0";"Trade";"0";"4692.0"\n' assert body1_lenovo in csv_str @@ -200,12 +225,14 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): # User2 mark this device as Refurbish action = {'type': ma.Use.t, 'devices': [device1_id]} action_use2, _ = user2.post(action, res=ma.Action) - csv_str, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': devices_id})]) + csv_str, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': devices_id})], + ) - body1_lenovo = '"O48N2";"desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10";"";"Trade";"foo@foo.com";' + body1_lenovo = '"O48N2";"adebcc5506213fac43cd8473a9c81bcf0cadaed9cb98b2eae651e377a3533c5a";"";"Trade";"foo@foo.com";' body1_lenovo += '"foo2@foo.com";"Supplier";"NeedConfirmation";"Use";"Use";' body2_lenovo = ';"";"0";"0";"Trade";"0";"0"\n' body2_acer = ';"";"0";"0";"Trade";"0";"4692.0"\n' @@ -215,20 +242,16 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): assert body2_acer in csv_str - @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_metrics_action_status_for_containers(user: UserClient, user2: UserClient): - """ Checks one standard query of metrics for a container.""" + """Checks one standard query of metrics for a container.""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') snap, _ = user.post(json_encode(lenovo), res=ma.Snapshot) lot, _ = user.post({'name': 'MyLot'}, res=Lot) devices = [('id', snap['device']['id'])] - lot, _ = user.post({}, - res=Lot, - item='{}/devices'.format(lot['id']), - query=devices) + lot, _ = user.post({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices) request_post = { 'type': 'Trade', 'devices': [snap['device']['id']], @@ -247,7 +270,7 @@ def test_metrics_action_status_for_containers(user: UserClient, user2: UserClien 'hash': 'bbbbbbbb', 'url': 'http://www.ereuse.org/', 'weight': 150, - 'lot': lot['id'] + 'lot': lot['id'], } tradedocument, _ = user.post(res=TradeDocument, data=request_post) action = {'type': ma.Recycling.t, 'devices': [], 'documents': [tradedocument['id']]} @@ -257,10 +280,12 @@ def test_metrics_action_status_for_containers(user: UserClient, user2: UserClien assert str(trade.actions[-1].id) == action['id'] # get metrics from botom in lot menu - csv_str, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer']}), ('lot', lot['id'])]) + csv_str, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']}), ('lot', lot['id'])], + ) body1 = ';"bbbbbbbb";"test.pdf";"Trade-Container";"foo@foo.com";"foo2@foo.com";"Supplier";"False";"Recycling";"";' body2 = ';"";"150.0";' @@ -272,10 +297,12 @@ def test_metrics_action_status_for_containers(user: UserClient, user2: UserClien assert body3 in csv_str.split('\n')[-2] # get metrics from botom in devices menu - csv_str2, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': [snap['device']['id']]})]) + csv_str2, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': [snap['device']['id']]})], + ) assert len(csv_str2.split('\n')) == 4 assert body1 in csv_str2.split('\n')[-2] @@ -286,17 +313,14 @@ def test_metrics_action_status_for_containers(user: UserClient, user2: UserClien @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_visual_metrics_for_old_owners(user: UserClient, user2: UserClient): - """ Checks if one old owner can see the metrics in a trade enviroment.""" + """Checks if one old owner can see the metrics in a trade enviroment.""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') snap1, _ = user.post(json_encode(lenovo), res=ma.Snapshot) lot, _ = user.post({'name': 'MyLot'}, res=Lot) device_id = snap1['device']['id'] devices = [('id', device_id)] - lot, _ = user.post({}, - res=Lot, - item='{}/devices'.format(lot['id']), - query=devices) + lot, _ = user.post({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices) request_post = { 'type': 'Trade', 'devices': [device_id], @@ -309,24 +333,23 @@ def test_visual_metrics_for_old_owners(user: UserClient, user2: UserClient): } trade, _ = user.post(res=ma.Action, data=request_post) - request_confirm = { - 'type': 'Confirm', - 'action': trade['id'], - 'devices': [device_id] - } + request_confirm = {'type': 'Confirm', 'action': trade['id'], 'devices': [device_id]} user2.post(res=ma.Action, data=request_confirm) - action = {'type': ma.Refurbish.t, 'devices': [device_id]} action_use, _ = user.post(action, res=ma.Action) - csv_supplier, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': [device_id]})]) - csv_receiver, _ = user2.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': [device_id]})]) + csv_supplier, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': [device_id]})], + ) + csv_receiver, _ = user2.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': [device_id]})], + ) body = ';"";"0";"0";"Trade";"0";"0"\n' assert body in csv_receiver @@ -343,10 +366,7 @@ def test_bug_trade_confirmed(user: UserClient, user2: UserClient): lot, _ = user.post({'name': 'MyLot'}, res=Lot) device_id = snap1['device']['id'] devices = [('id', device_id)] - lot, _ = user.post({}, - res=Lot, - item='{}/devices'.format(lot['id']), - query=devices) + lot, _ = user.post({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices) request_post = { 'type': 'Trade', 'devices': [device_id], @@ -359,22 +379,24 @@ def test_bug_trade_confirmed(user: UserClient, user2: UserClient): } trade, _ = user.post(res=ma.Action, data=request_post) - csv_not_confirmed, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': [device_id]})]) - request_confirm = { - 'type': 'Confirm', - 'action': trade['id'], - 'devices': [device_id] - } + csv_not_confirmed, _ = user.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': [device_id]})], + ) + request_confirm = {'type': 'Confirm', 'action': trade['id'], 'devices': [device_id]} user2.post(res=ma.Action, data=request_confirm) - csv_confirmed, _ = user2.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer'], 'ids': [device_id]})]) + csv_confirmed, _ = user2.get( + res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer'], 'ids': [device_id]})], + ) - body_not_confirmed = '"Trade";"foo2@foo.com";"foo@foo.com";"Receiver";"NeedConfirmation";' + body_not_confirmed = ( + '"Trade";"foo2@foo.com";"foo@foo.com";"Receiver";"NeedConfirmation";' + ) body_confirmed = '"Trade";"foo2@foo.com";"foo@foo.com";"Receiver";"TradeConfirmed";' assert body_not_confirmed in csv_not_confirmed diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index b970aa1a..101451c0 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -714,7 +714,7 @@ def test_add_laptop(user3: UserClientFlask): assert typ == 'Laptop' assert dev.placeholder.id_device_supplier == "b2" assert ( - dev.chid == '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + dev.chid == '274f05421e4d394c5b3cd10266fed6f0500029b104b5db3521689bda589e3150' ) assert phid == '1' assert dhid == 'O48N2' @@ -754,9 +754,10 @@ def test_add_with_ammount_laptops(user3: UserClientFlask): for dev in Device.query.all(): assert dev.type == 'Laptop' assert dev.placeholder.id_device_supplier is None + assert dev.hid == 'laptop-samsung-lc27t55-' assert ( dev.chid - == 'ab606f8b822dcd9276a6c492161fe592047ea98816387d149b2ccfbb5a7ebd30' + == 'ff8e7794d33ed22046b8d94b8bba4d8d1507f0fee535150835cac28faabbcda1' ) assert dev.placeholder.phid in [str(x) for x in range(1, num + 1)] assert Device.query.count() == num @@ -1702,7 +1703,6 @@ def test_export_lots(user3: UserClientFlask): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_export_snapshot_json(user3: UserClientFlask): - # ?? file_name = 'real-eee-1001pxd.snapshot.13.json' snap = create_device(user3, file_name) @@ -1712,7 +1712,10 @@ def test_export_snapshot_json(user3: UserClientFlask): uri = "/inventory/export/snapshot/?id={}".format(snap.uuid) body, status = user3.get(uri) assert status == '200 OK' - assert body == snapshot + body = json.loads(body) + snapshot = json.loads(snapshot) + assert body['device'] == snapshot['device'] + assert body['components'] == snapshot['components'] @pytest.mark.mvp @@ -1733,7 +1736,7 @@ def test_add_placeholder_excel(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + chid = 'f28ae12ffd513f5ed8fb6714a344a2326c48a7196fb140435065ab96ffda1a71' assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' @@ -1760,7 +1763,7 @@ def test_add_placeholder_csv(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + chid = 'f28ae12ffd513f5ed8fb6714a344a2326c48a7196fb140435065ab96ffda1a71' assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' @@ -1787,7 +1790,7 @@ def test_add_placeholder_ods(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + chid = 'f28ae12ffd513f5ed8fb6714a344a2326c48a7196fb140435065ab96ffda1a71' assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' @@ -1816,7 +1819,7 @@ def test_add_placeholder_office_open_xml(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + chid = 'f28ae12ffd513f5ed8fb6714a344a2326c48a7196fb140435065ab96ffda1a71' assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' @@ -1855,7 +1858,7 @@ def test_edit_laptop(user3: UserClientFlask): assert typ == 'Laptop' assert dev.placeholder.id_device_supplier == "b2" - chid = '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + chid = '274f05421e4d394c5b3cd10266fed6f0500029b104b5db3521689bda589e3150' assert dev.chid == chid assert dev.serial_number == 'aaaab' assert dev.model == 'lc27t55' @@ -2086,7 +2089,7 @@ def test_add_placeholder_excel_from_lot(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") assert Device.query.count() == 3 dev = Device.query.first() - chid = 'fa7eb51fad01a46b7bbe92fee9d4067e698f6cee9896beece3ace48e15c67652' + chid = 'f28ae12ffd513f5ed8fb6714a344a2326c48a7196fb140435065ab96ffda1a71' assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.info == 'Good conditions' @@ -2126,7 +2129,7 @@ def test_add_new_placeholder_from_lot(user3: UserClientFlask): } user3.post(uri, data=data) dev = Device.query.one() - chid = '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + chid = '274f05421e4d394c5b3cd10266fed6f0500029b104b5db3521689bda589e3150' assert dev.chid == chid assert dev.placeholder.phid == '1' assert len(lot.devices) == 1 @@ -2152,7 +2155,7 @@ def test_manual_binding(user3: UserClientFlask): } user3.post(uri, data=data) dev = Device.query.one() - chid = '69c57a32166b146c27a37ea74632f167d9a83fcbb23f11f93cc55cb9e6878e2b' + chid = '274f05421e4d394c5b3cd10266fed6f0500029b104b5db3521689bda589e3150' assert dev.chid == chid assert dev.placeholder.phid == '1' assert dev.placeholder.is_abstract is False @@ -2166,7 +2169,7 @@ def test_manual_binding(user3: UserClientFlask): assert dev_wb.binding.is_abstract is True assert ( dev_wb.chid - == '49b3920735c11693c43cef6199af95798ac00dbd61cc3224eae5e9f04d3313fb' + == '83cb9066430a8ea7def04af61d521d6517193a486c02ea3bc914c9eaeb2b718b' ) assert dev_wb.binding.phid == '11' old_placeholder = dev_wb.binding @@ -2665,7 +2668,7 @@ def test_system_uuid_motherboard(user3: UserClientFlask): } user3.post(uri, data=data, content_type="multipart/form-data") snapshot2 = Snapshot.query.filter_by(uuid=snapshot_json['uuid']).first() - assert snapshot2.device != snapshot.device + assert snapshot2.device == snapshot.device for c in snapshot.device.components: if c.type == 'Motherboard': - assert c.serial_number == 'eee0123456720' + assert c.serial_number == 'abee0123456720' diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index 2ee04e76..9b4eca8e 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -368,7 +368,7 @@ def test_snapshot_post_without_hid(user: UserClient): assert response_snapshot['uuid'] == '9a3e7485-fdd0-47ce-bcc7-65c55226b598' assert response_snapshot['elapsed'] == 4 assert response_snapshot['author']['id'] == user.user['id'] - assert response_snapshot['severity'] == 'Warning' + assert response_snapshot['severity'] == 'Info' assert response_status.status_code == 201 @@ -391,7 +391,7 @@ def test_snapshot_tag_inner_tag_mismatch_between_tags_and_hid( pc2 = yaml2json('1-device-with-components.snapshot') user.post(json_encode(pc2), res=Snapshot) # PC2 uploads well pc2['device']['tags'] = [{'type': 'Tag', 'id': tag_id}] # Set tag from pc1 to pc2 - user.post(json_encode(pc2), res=Snapshot, status=MismatchBetweenTagsAndHid) + user.post(json_encode(pc2), res=Snapshot, status=400) @pytest.mark.mvp @@ -411,7 +411,7 @@ def test_snapshot_different_properties_same_tags(user: UserClient, tag_id: str): pc2['device']['tags'] = pc1['device']['tags'] # pc2 model is unknown but pc1 model is set = different property del pc2['device']['model'] - user.post(json_encode(pc2), res=Snapshot, status=MismatchBetweenProperties) + user.post(json_encode(pc2), res=Snapshot, status=201) @pytest.mark.mvp @@ -684,7 +684,8 @@ def test_erase_changing_hdd_between_pcs(user: UserClient): tag2 = Tag(id='dev2', device=dev2) db.session.commit() - assert dev2.components[1].actions[2].parent == dev1 + assert dev2.components[2].parent == dev2 + assert dev2.components[2].actions[-1].device == dev1 doc1, response = user.get( res=documents.DocumentDef.t, item='erasures/{}'.format(dev1.id), accept=ANY ) @@ -1004,7 +1005,8 @@ def test_snapshot_wb_lite(user: UserClient): assert dev.dhid in body['public_url'] assert ssd.serial_number == 's35anx0j401001' assert res.status == '201 CREATED' - assert '00:28:f8:a6:d5:7e' in dev.hid + chid = '7619bf5dfa630c8bd6d431c56777f6334d5c1e2e55d90c0dc4d1e99f80f031c1' + assert dev.chid == chid assert dev.actions[0].power_on_hours == 6032 errors = SnapshotsLog.query.filter().all() @@ -1028,7 +1030,7 @@ def test_snapshot_wb_lite_qemu(user: UserClient): assert dev.manufacturer == 'qemu' assert dev.model == 'standard' assert dev.serial_number is None - assert dev.hid is None + assert dev.hid == 'computer-qemu-standard-' assert dev.actions[0].power_on_hours == 1 assert dev.components[-1].size == 40960 assert dev.components[-1].serial_number == 'qm00001' @@ -1078,7 +1080,7 @@ def test_snapshot_wb_lite_old_snapshots(user: UserClient): try: assert body11['device'].get('hid') == dev.hid if body11['device'].get('hid'): - assert body11['device']['id'] == dev.id + assert body11['device']['id'] != dev.id assert body11['device'].get('serialNumber') == dev.serial_number assert body11['device'].get('model') == dev.model assert body11['device'].get('manufacturer') == dev.manufacturer @@ -1405,7 +1407,7 @@ def test_bug_4028_components(user: UserClient): assert '' not in [c.phid() for c in components1] assert '' not in [c.phid() for c in components2] assert len(components1) == len(components2) - assert m.Placeholder.query.count() == 16 + assert m.Placeholder.query.count() == 15 assert m.Placeholder.query.count() * 2 == m.Device.query.count() for c in m.Placeholder.query.filter(): assert c.binding diff --git a/tests/test_system_uuid.py b/tests/test_system_uuid.py index 71eae0e7..08a162c7 100644 --- a/tests/test_system_uuid.py +++ b/tests/test_system_uuid.py @@ -29,7 +29,7 @@ def test_wb11_form(user3: UserClientFlask): db_snapthot = Snapshot.query.one() device = db_snapthot.device - assert device.hid == 'laptop-toshiba-satellite_l655-2b335208q-00:26:6c:ae:ee:78' + assert device.hid == 'laptop-toshiba-satellite_l655-2b335208q' assert str(device.system_uuid) == 'f0dc6a7f-c23f-e011-b5d0-00266caeee78' @@ -42,7 +42,7 @@ def test_wb11_api(user: UserClient): db_snapthot = Snapshot.query.one() device = db_snapthot.device - assert device.hid == 'laptop-toshiba-satellite_l655-2b335208q-00:26:6c:ae:ee:78' + assert device.hid == 'laptop-toshiba-satellite_l655-2b335208q' assert str(device.system_uuid) == 'f0dc6a7f-c23f-e011-b5d0-00266caeee78' @@ -65,7 +65,7 @@ def test_wbLite_form(user3: UserClientFlask): db_snapthot = Snapshot.query.one() device = db_snapthot.device - assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -78,7 +78,7 @@ def test_wbLite_api(user: UserClient): db_snapthot = Snapshot.query.one() device = db_snapthot.device - assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -93,7 +93,7 @@ def test_wb11_to_wb11_with_uuid_api(user: UserClient): db_snapthot = Snapshot.query.one() device = db_snapthot.device assert Computer.query.count() == 2 - assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert device.system_uuid is None # insert the same computer with wb11 with hid and with uuid, (new version) @@ -109,11 +109,8 @@ def test_wb11_to_wb11_with_uuid_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) - assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' + assert device.system_uuid is None @pytest.mark.mvp @@ -130,10 +127,7 @@ def test_wb11_with_uuid_to_wb11_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' # insert the same computer with wb11 with hid and with uuid, (new version) @@ -144,10 +138,7 @@ def test_wb11_with_uuid_to_wb11_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -165,10 +156,7 @@ def test_wb11_with_uuid_to_wb11_without_hid_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' # insert the same computer with wb11 with hid and with uuid, (new version) @@ -203,7 +191,7 @@ def test_wb11_to_wb11_with_uuid_form(user3: UserClientFlask): db_snapthot = Snapshot.query.one() device = db_snapthot.device assert Computer.query.count() == 2 - assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert device.system_uuid is None # insert the same computer with wb11 with hid and with uuid, (new version) @@ -222,11 +210,8 @@ def test_wb11_to_wb11_with_uuid_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) - assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' + assert device.system_uuid is None @pytest.mark.mvp @@ -254,10 +239,7 @@ def test_wb11_with_uuid_to_wb11_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' # insert the same computer with wb11 with hid and with uuid, (new version) @@ -275,10 +257,7 @@ def test_wb11_with_uuid_to_wb11_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -307,10 +286,7 @@ def test_wb11_with_uuid_to_wb11_without_hid_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' # insert the same computer with wb11 with hid and with uuid, (new version) @@ -340,10 +316,7 @@ def test_wb11_to_wblite_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert device.system_uuid is None snapshot_lite = conftest.file_json('system_uuid2.json') @@ -351,11 +324,9 @@ def test_wb11_to_wblite_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) - assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' + # assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' + assert device.system_uuid is None @pytest.mark.mvp @@ -367,10 +338,7 @@ def test_wblite_to_wb11_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' snapshot_11 = conftest.file_json('system_uuid3.json') @@ -378,10 +346,7 @@ def test_wblite_to_wb11_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -405,10 +370,7 @@ def test_wb11_to_wblite_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert device.system_uuid is None file_name = 'system_uuid2.json' @@ -424,11 +386,9 @@ def test_wb11_to_wblite_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) - assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' + # assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' + assert device.system_uuid is None @pytest.mark.mvp @@ -451,10 +411,7 @@ def test_wblite_to_wb11_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid == 'laptop-acer-aohappy-lusea0d010038879a01601' assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' file_name = 'system_uuid3.json' @@ -470,10 +427,7 @@ def test_wblite_to_wb11_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -486,10 +440,7 @@ def test_wblite_to_wblite_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' snapshot_lite = conftest.file_json('system_uuid2.json') @@ -498,10 +449,7 @@ def test_wblite_to_wblite_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -525,10 +473,7 @@ def test_wblite_to_wblite_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' file_name = 'system_uuid2.json' @@ -545,10 +490,7 @@ def test_wblite_to_wblite_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -562,10 +504,7 @@ def test_wb11_to_wb11_duplicity_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert device.system_uuid is None snapshot_11 = conftest.file_json('system_uuid3.json') @@ -573,7 +512,7 @@ def test_wb11_to_wb11_duplicity_api(user: UserClient): components = [x for x in snapshot_11['components'] if x['type'] != 'NetworkAdapter'] snapshot_11['components'] = components user.post(snapshot_11, res=Snapshot) - assert Computer.query.count() == 4 + assert Computer.query.count() == 2 for c in Computer.query.all(): assert 'laptop-acer-aohappy-lusea0d010038879a01601' in c.hid assert c.system_uuid is None @@ -599,10 +538,7 @@ def test_wb11_to_wb11_duplicity_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert device.system_uuid is None snapshot_11 = conftest.file_json('system_uuid3.json') @@ -619,7 +555,7 @@ def test_wb11_to_wb11_duplicity_form(user3: UserClientFlask): } user3.post(uri, data=data, content_type="multipart/form-data") - assert Computer.query.count() == 4 + assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: assert 'laptop-acer-aohappy-lusea0d010038879a01601' in device.hid @@ -636,10 +572,7 @@ def test_wb11_smbios_2_5_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert device.system_uuid is None @@ -663,10 +596,7 @@ def test_wb11_smbios_2_5_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert device.system_uuid is None @@ -681,10 +611,7 @@ def test_wblite_smbios_2_5_api(user: UserClient): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' @@ -709,8 +636,5 @@ def test_wblite_smbios_2_5_form(user3: UserClientFlask): assert Computer.query.count() == 2 for device in Computer.query.all(): if device.binding: - assert ( - device.hid - == 'laptop-acer-aohappy-lusea0d010038879a01601-88:ae:1d:a6:f3:d0' - ) + assert device.hid assert str(device.system_uuid) == '9ce64e36-829c-b19c-2111-88ae1da6f3d0' diff --git a/tests/test_tag.py b/tests/test_tag.py index 94c0f23c..cbdd7e5f 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -348,39 +348,6 @@ def test_tag_manual_link_search(app: Devicehub, user: UserClient): assert i['items'] -@pytest.mark.mvp -@pytest.mark.usefixtures(conftest.app_context.__name__) -def test_tag_secondary_workbench_link_find(user: UserClient): - """Creates and consumes tags with a secondary id, linking them - through Workbench to a device - and getting them through search.""" - t = Tag('foo', secondary='bar', owner_id=user.user['id']) - db.session.add(t) - db.session.flush() - assert Tag.from_an_id('bar').one() == Tag.from_an_id('foo').one() - with pytest.raises(ResourceNotFound): - Tag.from_an_id('nope').one() - - s = yaml2json('basic.snapshot') - s['device']['tags'] = [{'id': 'foo', 'secondary': 'bar', 'type': 'Tag'}] - snapshot, _ = user.post(json_encode(s), res=Snapshot) - dev = Device.query.filter_by(id=snapshot['device']['id']).one() - device, _ = user.get(res=Device, item=dev.devicehub_id) - desktop = dev.binding.device - assert [] == [x['id'] for x in device['tags']] - assert 'foo' in [x.id for x in desktop.tags] - assert 'bar' in [x.secondary for x in desktop.tags] - - r, _ = user.get( - res=Device, query=[('search', 'foo'), ('filter', {'type': ['Computer']})] - ) - assert len(r['items']) == 1 - r, _ = user.get( - res=Device, query=[('search', 'bar'), ('filter', {'type': ['Computer']})] - ) - assert len(r['items']) == 1 - - @pytest.mark.mvp def test_tag_create_tags_cli_csv(app: Devicehub, user: UserClient): """Checks creating tags with the CLI endpoint using a CSV.""" diff --git a/tests/test_workbench.py b/tests/test_workbench.py index 43c293ea..5f4221e5 100644 --- a/tests/test_workbench.py +++ b/tests/test_workbench.py @@ -15,8 +15,8 @@ from ereuse_devicehub.resources.action.models import ( from ereuse_devicehub.resources.device.exceptions import NeedsId from ereuse_devicehub.resources.device.models import Device from ereuse_devicehub.resources.tag.model import Tag -from tests.conftest import file, file_workbench, json_encode, yaml2json from tests import conftest +from tests.conftest import file, file_workbench, json_encode, yaml2json @pytest.mark.mvp @@ -60,7 +60,7 @@ def test_workbench_server_condensed(user: UserClient): device, _ = user.get(res=Device, item=db_dev.devicehub_id) assert device['dataStorageSize'] == 1100 assert device['chassis'] == 'Tower' - assert device['hid'] == 'desktop-d1mr-d1ml-d1s-na1-s' + assert device['hid'] == 'desktop-d1mr-d1ml-d1s' assert device['graphicCardModel'] == device['components'][0]['model'] == 'gc1-1ml' assert device['networkSpeeds'] == [1000, 58] assert device['processorModel'] == device['components'][3]['model'] == 'p1-1ml' @@ -147,10 +147,7 @@ def test_real_hp_11(user: UserClient): s = file('real-hp.snapshot.11') snapshot, _ = user.post(res=em.Snapshot, data=s) pc = snapshot['device'] - assert ( - pc['hid'] - == 'desktop-hewlett-packard-hp_compaq_8100_elite_sff-czc0408yjg-6c:62:6d:81:22:9f' - ) + assert pc['hid'] == 'desktop-hewlett-packard-hp_compaq_8100_elite_sff-czc0408yjg' assert pc['chassis'] == 'Tower' assert set(e['type'] for e in snapshot['actions']) == { 'BenchmarkDataStorage', @@ -192,10 +189,7 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient): assert pc['model'] == '1001pxd' assert pc['serialNumber'] == 'b8oaas048286' assert pc['manufacturer'] == 'asustek computer inc.' - assert ( - pc['hid'] - == 'laptop-asustek_computer_inc-1001pxd-b8oaas048286-14:da:e9:42:f6:7c' - ) + assert pc['hid'] == 'laptop-asustek_computer_inc.-1001pxd-b8oaas048286' assert len(pc['tags']) == 0 assert pc['networkSpeeds'] == [ 100, @@ -209,14 +203,14 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient): wifi = components[0] assert ( wifi['hid'] == 'networkadapter-qualcomm_atheros-' - 'ar9285_wireless_network_adapter-74_2f_68_8b_fd_c8' + 'ar9285_wireless_network_adapter-74:2f:68:8b:fd:c8' ) assert wifi['serialNumber'] == '74:2f:68:8b:fd:c8' assert wifi['wireless'] eth = components[1] assert ( eth['hid'] == 'networkadapter-qualcomm_atheros-' - 'ar8152_v2_0_fast_ethernet-14_da_e9_42_f6_7c' + 'ar8152_v2.0_fast_ethernet-14:da:e9:42:f6:7c' ) assert eth['speed'] == 100 assert not eth['wireless'] @@ -225,7 +219,7 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient): assert cpu['cores'] == 1 assert cpu['threads'] == 1 assert cpu['speed'] == 1.667 - assert 'hid' not in cpu + assert 'hid' in cpu assert pc['processorModel'] == cpu['model'] == 'intel atom cpu n455 @ 1.66ghz' db_cpu = Device.query.filter_by(id=cpu['id']).one() cpu, _ = user.get(res=Device, item=db_cpu.devicehub_id) @@ -287,7 +281,7 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient): assert erase['severity'] == 'Info' assert hdd['privacy']['type'] == 'EraseBasic' mother = components[8] - assert mother['hid'] == 'motherboard-asustek_computer_inc-1001pxd-eee0123456789' + assert mother['hid'] == 'motherboard-asustek_computer_inc.-1001pxd-eee0123456789' @pytest.mark.mvp From 31b62a2d81aef5ab751384e9a2ec7be212cf61e0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 20 Dec 2022 10:17:42 +0100 Subject: [PATCH 23/39] check if is active module hid --- ereuse_devicehub/resources/device/models.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index e715342e..222f0d54 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -9,7 +9,8 @@ from typing import Dict, List, Set from boltons import urlutils from citext import CIText -from ereuse_utils.naming import HID_CONVERSION_DOC, Naming +from ereuse_utils.naming import HID_CONVERSION_DOC +from flask import current_app as app from flask import g, request from more_itertools import unique_everseen from sqlalchemy import BigInteger, Boolean, Column @@ -770,14 +771,15 @@ class Device(Thing): ).first() def set_hid(self): - try: - from modules.device.utils import set_hid + if 'property_hid' not in app.blueprints.keys(): + try: + from modules.device.utils import set_hid - self.hid = set_hid(self) - self.set_chid() - return - except Exception: - pass + self.hid = set_hid(self) + self.set_chid() + return + except Exception: + pass self.hid = "{}-{}-{}-{}".format( self._clean_string(self.type), From 2bb6b13e0765aac0a5d238f65203e416288ee648 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 20 Dec 2022 11:06:41 +0100 Subject: [PATCH 24/39] fix --- ereuse_devicehub/resources/device/models.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 222f0d54..39677597 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -753,12 +753,13 @@ class Device(Thing): return "" def get_from_db(self): - try: - from modules.device.utils import get_from_db + if 'property_hid' in app.blueprints.keys(): + try: + from modules.device.utils import get_from_db - return get_from_db(self) - except Exception: - pass + return get_from_db(self) + except Exception: + pass if not self.hid: return @@ -771,7 +772,7 @@ class Device(Thing): ).first() def set_hid(self): - if 'property_hid' not in app.blueprints.keys(): + if 'property_hid' in app.blueprints.keys(): try: from modules.device.utils import set_hid From 205e111e9d9b82caeb3b2e18816aeb03095f6880 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 20 Dec 2022 11:39:31 +0100 Subject: [PATCH 25/39] fix tests rate --- tests/test_rate_workbench_v1.py | 118 ++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 37 deletions(-) diff --git a/tests/test_rate_workbench_v1.py b/tests/test_rate_workbench_v1.py index 7269b72a..b52b2995 100644 --- a/tests/test_rate_workbench_v1.py +++ b/tests/test_rate_workbench_v1.py @@ -17,18 +17,36 @@ Excluded cases in tests """ import math + import pytest -from ereuse_devicehub.resources.action.models import BenchmarkDataStorage, BenchmarkProcessor, \ - VisualTest -from ereuse_devicehub.resources.action.rate.v1_0 import DataStorageRate, ProcessorRate, \ - RamRate, RateAlgorithm -from ereuse_devicehub.resources.device.models import Desktop, HardDrive, Processor, RamModule -from ereuse_devicehub.resources.enums import AppearanceRange, ComputerChassis, FunctionalityRange +from ereuse_devicehub.resources.action.models import ( + BenchmarkDataStorage, + BenchmarkProcessor, + VisualTest, +) +from ereuse_devicehub.resources.action.rate.v1_0 import ( + DataStorageRate, + ProcessorRate, + RamRate, + RateAlgorithm, +) +from ereuse_devicehub.resources.device.models import ( + Desktop, + HardDrive, + Processor, + RamModule, +) +from ereuse_devicehub.resources.enums import ( + AppearanceRange, + ComputerChassis, + FunctionalityRange, +) from tests import conftest @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_data_storage_rate(): """Test to check if compute data storage rate have same value than previous score version. @@ -65,6 +83,7 @@ def test_rate_data_storage_rate(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_data_storage_size_is_null(): """Test where input DataStorage.size = NULL, BenchmarkDataStorage.read_speed = 0, BenchmarkDataStorage.write_speed = 0 is like no DataStorage has been detected; @@ -78,6 +97,7 @@ def test_rate_data_storage_size_is_null(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_no_data_storage(): """Test without data storage devices.""" @@ -88,6 +108,7 @@ def test_rate_no_data_storage(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_ram_rate(): """Test to check if compute ram rate have same value than previous score version only with 1 RamModule. @@ -97,10 +118,13 @@ def test_rate_ram_rate(): ram_rate = RamRate().compute([ram1]) - assert math.isclose(ram_rate, 2.02, rel_tol=0.002), 'RamRate returns incorrect value(rate)' + assert math.isclose( + ram_rate, 2.02, rel_tol=0.002 + ), 'RamRate returns incorrect value(rate)' @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_ram_rate_2modules(): """Test to check if compute ram rate have same value than previous score version with 2 RamModule. @@ -111,10 +135,13 @@ def test_rate_ram_rate_2modules(): ram_rate = RamRate().compute([ram1, ram2]) - assert math.isclose(ram_rate, 3.79, rel_tol=0.001), 'RamRate returns incorrect value(rate)' + assert math.isclose( + ram_rate, 3.79, rel_tol=0.001 + ), 'RamRate returns incorrect value(rate)' @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_ram_rate_4modules(): """Test to check if compute ram rate have same value than previous score version with 2 RamModule. @@ -127,10 +154,13 @@ def test_rate_ram_rate_4modules(): ram_rate = RamRate().compute([ram1, ram2, ram3, ram4]) - assert math.isclose(ram_rate, 1.993, rel_tol=0.001), 'RamRate returns incorrect value(rate)' + assert math.isclose( + ram_rate, 1.993, rel_tol=0.001 + ), 'RamRate returns incorrect value(rate)' @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_ram_module_size_is_0(): """Test where input data RamModule.size = 0; is like no RamModule has been detected. @@ -143,6 +173,7 @@ def test_rate_ram_module_size_is_0(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_ram_speed_is_null(): """Test where RamModule.speed is NULL (not detected) but has size.""" @@ -150,16 +181,21 @@ def test_rate_ram_speed_is_null(): ram_rate = RamRate().compute([ram0]) - assert math.isclose(ram_rate, 1.85, rel_tol=0.002), 'RamRate returns incorrect value(rate)' + assert math.isclose( + ram_rate, 1.85, rel_tol=0.002 + ), 'RamRate returns incorrect value(rate)' ram0 = RamModule(size=1024, speed=None) ram_rate = RamRate().compute([ram0]) - assert math.isclose(ram_rate, 1.25, rel_tol=0.004), 'RamRate returns incorrect value(rate)' + assert math.isclose( + ram_rate, 1.25, rel_tol=0.004 + ), 'RamRate returns incorrect value(rate)' @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_no_ram_module(): """Test without RamModule.""" ram0 = RamModule() @@ -169,6 +205,7 @@ def test_rate_no_ram_module(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_processor_rate(): """Test to check if compute processor rate have same value than previous score version only with 1 core. @@ -184,6 +221,7 @@ def test_rate_processor_rate(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_processor_rate_2cores(): """Test to check if compute processor rate have same value than previous score version with 2 cores. @@ -206,6 +244,7 @@ def test_rate_processor_rate_2cores(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_processor_with_null_cores(): """Test with processor device have null number of cores.""" cpu = Processor(cores=None, speed=3.3) @@ -217,6 +256,7 @@ def test_rate_processor_with_null_cores(): @pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) def test_rate_processor_with_null_speed(): """Test with processor device have null speed value.""" cpu = Processor(cores=1, speed=None) @@ -262,12 +302,14 @@ def test_rate_computer_1193(): data_storage, RamModule(size=4096, speed=1600), RamModule(size=2048, speed=1067), - cpu + cpu, } # Add test visual with functionality and appearance range - VisualTest(appearance_range=AppearanceRange.A, - functionality_range=FunctionalityRange.A, - device=pc_test) + VisualTest( + appearance_range=AppearanceRange.A, + functionality_range=FunctionalityRange.A, + device=pc_test, + ) # Compute all components rates and general rating rate_pc = RateAlgorithm().compute(pc_test) @@ -311,15 +353,13 @@ def test_rate_computer_1201(): data_storage.actions_one.add(BenchmarkDataStorage(read_speed=158, write_speed=34.7)) cpu = Processor(cores=2, speed=3.3) cpu.actions_one.add(BenchmarkProcessor(rate=26339.48)) - pc_test.components |= { - data_storage, - RamModule(size=2048, speed=1333), - cpu - } + pc_test.components |= {data_storage, RamModule(size=2048, speed=1333), cpu} # Add test visual with functionality and appearance range - VisualTest(appearance_range=AppearanceRange.B, - functionality_range=FunctionalityRange.A, - device=pc_test) + VisualTest( + appearance_range=AppearanceRange.B, + functionality_range=FunctionalityRange.A, + device=pc_test, + ) # Compute all components rates and general rating rate_pc = RateAlgorithm().compute(pc_test) @@ -365,7 +405,9 @@ def test_rate_computer_multiple_ram_module(): pc_test = Desktop(chassis=ComputerChassis.Tower) data_storage = HardDrive(size=76319) - data_storage.actions_one.add(BenchmarkDataStorage(read_speed=72.2, write_speed=24.3)) + data_storage.actions_one.add( + BenchmarkDataStorage(read_speed=72.2, write_speed=24.3) + ) cpu = Processor(cores=1, speed=1.6) cpu.actions_one.add(BenchmarkProcessor(rate=3192.34)) pc_test.components |= { @@ -374,12 +416,14 @@ def test_rate_computer_multiple_ram_module(): RamModule(size=512, speed=800), RamModule(size=512, speed=667), RamModule(size=512, speed=533), - cpu + cpu, } # Add test visual with functionality and appearance range - VisualTest(appearance_range=AppearanceRange.C, - functionality_range=FunctionalityRange.A, - device=pc_test) + VisualTest( + appearance_range=AppearanceRange.C, + functionality_range=FunctionalityRange.A, + device=pc_test, + ) # Compute all components rates and general rating rate_pc = RateAlgorithm().compute(pc_test) @@ -421,18 +465,18 @@ def test_rate_computer_one_ram_module(): pc_test = Desktop(chassis=ComputerChassis.Tower) data_storage = HardDrive(size=152587) - data_storage.actions_one.add(BenchmarkDataStorage(read_speed=78.1, write_speed=24.4)) + data_storage.actions_one.add( + BenchmarkDataStorage(read_speed=78.1, write_speed=24.4) + ) cpu = Processor(cores=2, speed=2.5) cpu.actions_one.add(BenchmarkProcessor(rate=9974.3)) - pc_test.components |= { - data_storage, - RamModule(size=0, speed=None), - cpu - } + pc_test.components |= {data_storage, RamModule(size=0, speed=None), cpu} # Add test visual with functionality and appearance range - VisualTest(appearance_range=AppearanceRange.B, - functionality_range=FunctionalityRange.A, - device=pc_test) + VisualTest( + appearance_range=AppearanceRange.B, + functionality_range=FunctionalityRange.A, + device=pc_test, + ) # Compute all components rates and general rating rate_pc = RateAlgorithm().compute(pc_test) From 5d88d4e51651e96ae96b6a4a84722710bcd8c6d3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 20 Dec 2022 13:37:17 +0100 Subject: [PATCH 26/39] remove script --- scripts/create_new_hid.py | 54 --------------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 scripts/create_new_hid.py diff --git a/scripts/create_new_hid.py b/scripts/create_new_hid.py deleted file mode 100644 index 3e9ff4ff..00000000 --- a/scripts/create_new_hid.py +++ /dev/null @@ -1,54 +0,0 @@ -import json -import sys - -from ereuse_devicehub.db import db -from ereuse_devicehub.devicehub import Devicehub -from ereuse_devicehub.resources.action.models import Snapshot - - -def open_snapshot(): - path = sys.argv[2] - f = open(path) - txt = f.read() - return json.loads(txt) - - -def get_family(snapshot): - debug = snapshot.get('debug', {}) - lshw = debug.get('lshw', {}) - return lshw.get('configuration', {}).get('family', '') - - -def get_device(uuid): - snapshot = Snapshot.query.filter_by(uuid=uuid).first() - if snapshot: - return snapshot.device - - -def main(): - schema = sys.argv[1] - app = Devicehub(inventory=schema) - app.app_context().push() - snapshot = open_snapshot() - uuid = snapshot.get('uuid') - if not uuid: - return - family = get_family(snapshot) - device = get_device(uuid) - if not device: - return - device.family = family - device.set_hid() - for c in device.components: - c.set_hid() - - if device.binding: - device.binding.device.family = family - device.binding.device.set_hid() - for c in device.binding.device.components: - c.set_hid() - db.session.commit() - - -if __name__ == '__main__': - main() From 62de2126c79e287d2e271670101b98671adebaec Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 22 Dec 2022 12:01:31 +0100 Subject: [PATCH 27/39] base of form for update type of updated --- ereuse_devicehub/inventory/forms.py | 78 +++++++++++++++++++ ereuse_devicehub/inventory/views.py | 8 ++ ereuse_devicehub/resources/action/models.py | 13 ++++ ereuse_devicehub/resources/device/models.py | 8 ++ .../templates/inventory/snapshot_detail.html | 37 ++++++++- 5 files changed, 143 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 7f51bebf..655bffec 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1692,3 +1692,81 @@ class BindingForm(FlaskForm): return False return True + + +class UserTrustsForm(FlaskForm): + snapshot_type = SelectField( + '', + [validators.DataRequired()], + choices=[("new_device", "New Device"), ("update", "Update")], + default="new_device", + render_kw={'class': "form-select"}, + ) + + def __init__(self, snapshot_uuid, *args, **kwargs): + self.snapshot = Snapshot.query.filter_by(uuid=snapshot_uuid).first() + self.device = self.snapshot.device if self.snapshot.device else None + self.snapshot_type.kwargs['default'] = self.snapshot.get_new_device() + super().__init__(*args, **kwargs) + + def validate(self, extra_validators=None): + is_valid = super().validate(extra_validators) + + if not is_valid: + txt = "" + self.snapthot_type.errors = [txt] + return False + + return True + + def unic(self): + try: + return self._unic + except Exception: + self._unic = ( + Device.query.filter_by( + hid=self.device.hid, owner=g.user, placeholder=None + ).count() + < 2 + ) + + return self._unic + + def show(self): + if not self.snapshot or not self.device: + return False + + if not hasattr(self.device, 'system_uuid'): + return False + + if not self.device.system_uuid: + return False + + if self.snapshot.get_new_device() == 'update': + # To do Split + return True + + if not self.unic(): + # To do merge + return True + + return False + + def save(self, commit=True): + # import pdb; pdb.set_trace() + if not self.show(): + return + + if self.snapshot_type.data == self.snapshot.get_new_device(): + return + + if self.snapshot_type.data == 'update' and not self.unic(): + self.device.merge() + + if self.snapshot_type.data == 'new_device' and self.unic(): + self.device.split() + + if commit: + db.session.commit() + + return self.snapshot diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index ed3939be..15988ddb 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -33,6 +33,7 @@ from ereuse_devicehub.inventory.forms import ( TransferForm, UploadPlaceholderForm, UploadSnapshotForm, + UserTrustsForm, ) from ereuse_devicehub.labels.forms import PrintLabelsForm from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog @@ -1228,9 +1229,12 @@ class SnapshotListView(GenericMixin): class SnapshotDetailView(GenericMixin): template_name = 'inventory/snapshot_detail.html' + methods = ['GET', 'POST'] + form_class = UserTrustsForm def dispatch_request(self, snapshot_uuid): self.snapshot_uuid = snapshot_uuid + form = self.form_class(snapshot_uuid) self.get_context() self.context['page_title'] = "Snapshot Detail" self.context['snapshots_log'] = self.get_snapshots_log() @@ -1238,6 +1242,10 @@ class SnapshotDetailView(GenericMixin): self.context['snapshot_sid'] = '' if self.context['snapshots_log'].count(): self.context['snapshot_sid'] = self.context['snapshots_log'][0].sid + self.context['form'] = form + + if form.validate_on_submit(): + form.save() return flask.render_template(self.template_name, **self.context) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 6060e037..7454cac4 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -701,6 +701,19 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice): return hdds + def get_new_device(self): + + if not self.device: + return '' + + snapshots = [] + for s in self.device.actions: + if s == self: + break + if s.type == self.type: + snapshots.append(s) + return snapshots and 'update' or 'new_device' + def __str__(self) -> str: return '{}. {} version {}.'.format(self.severity, self.software, self.version) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 39677597..54d1fa98 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -875,6 +875,14 @@ class Device(Thing): } return types.get(self.type, '') + def split(self): + self.user_trusts = False + return + + def merge(self): + self.user_trusts = True + return + def __lt__(self, other): return self.id < other.id diff --git a/ereuse_devicehub/templates/inventory/snapshot_detail.html b/ereuse_devicehub/templates/inventory/snapshot_detail.html index 4ea87572..b084f76b 100644 --- a/ereuse_devicehub/templates/inventory/snapshot_detail.html +++ b/ereuse_devicehub/templates/inventory/snapshot_detail.html @@ -20,9 +20,44 @@

{{ snapshot_sid }} | {{ snapshot_uuid }}

+ {% if form.show() %} + + {% endif %}
-
+ {% if form.show() %} +
+
Change Snapshot Type Upload
+
+
+
+ {{ form.csrf_token }} + {% for f in form %} + {% if f != form.csrf_token %} +

+ {{ f }} +

+ {% endif %} + {% endfor %} +

+ +

+
+
+
+
+ {% endif %} +
Traceability log Details
{% for log in snapshots_log %} From bf5c3d6abc4332bc887b1235659c001db0500838 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 22 Dec 2022 18:04:34 +0100 Subject: [PATCH 28/39] add snapshot.active in model and migration file --- .../93daff872771_add_hash_hid_to_device.py | 14 +++++++++++++- ereuse_devicehub/resources/action/models.py | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py index ea1d2037..e274496e 100644 --- a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py +++ b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py @@ -36,7 +36,11 @@ def upgrade_data(): continue dev_id = d.id chid = hashlib.sha3_256(d.hid.encode('utf-8')).hexdigest() - sql = f"update {get_inv()}.device set chid={chid} where id={dev_id};" + sql = f"update {get_inv()}.device set chid='{chid}' where id={dev_id};" + con.execute(sql) + + sql = f"update {get_inv()}.snapshot set active=true;" + con.execute(sql) def upgrade(): @@ -52,11 +56,19 @@ def upgrade(): schema=f'{get_inv()}', ) + op.add_column( + 'snapshot', + sa.Column('active', sa.Boolean(), default=True, nullable=True), + schema=f'{get_inv()}', + ) + upgrade_data() op.alter_column('computer', 'user_trusts', nullable=False, schema=f'{get_inv()}') + op.alter_column('snapshot', 'active', nullable=False, schema=f'{get_inv()}') def downgrade(): op.drop_column('computer', 'user_trusts', schema=f'{get_inv()}') op.drop_column('device', 'chid', schema=f'{get_inv()}') + op.drop_column('snapshot', 'active', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 7454cac4..5f141570 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -678,6 +678,7 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice): sid = Column(CIText(), nullable=True) settings_version = Column(CIText(), nullable=True) is_server_erase = Column(Boolean(), nullable=True) + active = Column(Boolean(), nullable=True) def get_last_lifetimes(self): """We get the lifetime and serial_number of the first disk""" From 14ce3892acf58088e87a4631591b91b2a69a076b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 22 Dec 2022 18:39:59 +0100 Subject: [PATCH 29/39] add new filter in actions for show only active snapshots --- ereuse_devicehub/resources/device/models.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 54d1fa98..735b68a0 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -264,16 +264,18 @@ class Device(Thing): """ actions_multiple = copy.copy(self.actions_multiple) actions_one = copy.copy(self.actions_one) + actions = [] for ac in actions_multiple: ac.real_created = ac.actions_device[0].created + actions.append(ac) for ac in actions_one: ac.real_created = ac.created + if ac.type != 'Snapshot' or ac.active: + actions.append(ac) - return sorted( - chain(actions_multiple, actions_one), key=lambda x: x.real_created - ) + return sorted(actions, key=lambda x: x.real_created) @property def problems(self): From 50856671ed6a384f01c0a64a53f3d4d7777c2c95 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 23 Dec 2022 18:33:49 +0100 Subject: [PATCH 30/39] reliable and unreliable device. Active and deactive devices and snapshots --- ereuse_devicehub/inventory/forms.py | 20 ++++-- ereuse_devicehub/parser/models.py | 12 +++- ereuse_devicehub/resources/action/models.py | 2 +- ereuse_devicehub/resources/device/models.py | 69 ++++++++++++++++++++- ereuse_devicehub/resources/device/sync.py | 2 +- 5 files changed, 92 insertions(+), 13 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 655bffec..39321d8f 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -203,7 +203,9 @@ class FilterForm(FlaskForm): if filter_type: self.devices = self.devices.filter(Device.type.in_(filter_type)) - return self.devices.order_by(Device.updated.desc()) + return self.devices.filter(Device.active == True).order_by( + Device.updated.desc() + ) class LotForm(FlaskForm): @@ -1704,8 +1706,11 @@ class UserTrustsForm(FlaskForm): ) def __init__(self, snapshot_uuid, *args, **kwargs): - self.snapshot = Snapshot.query.filter_by(uuid=snapshot_uuid).first() - self.device = self.snapshot.device if self.snapshot.device else None + self.snapshot = Snapshot.query.filter_by(uuid=snapshot_uuid).one() + self.device = None + if self.snapshot.device: + self.device = self.snapshot.device + self.snapshot_type.kwargs['default'] = self.snapshot.get_new_device() super().__init__(*args, **kwargs) @@ -1725,7 +1730,7 @@ class UserTrustsForm(FlaskForm): except Exception: self._unic = ( Device.query.filter_by( - hid=self.device.hid, owner=g.user, placeholder=None + hid=self.device.hid, owner=g.user, placeholder=None, active=True ).count() < 2 ) @@ -1736,6 +1741,9 @@ class UserTrustsForm(FlaskForm): if not self.snapshot or not self.device: return False + if not self.snapshot.active: + return False + if not hasattr(self.device, 'system_uuid'): return False @@ -1761,10 +1769,10 @@ class UserTrustsForm(FlaskForm): return if self.snapshot_type.data == 'update' and not self.unic(): - self.device.merge() + self.device.reliable() if self.snapshot_type.data == 'new_device' and self.unic(): - self.device.split() + self.device.unreliable() if commit: db.session.commit() diff --git a/ereuse_devicehub/parser/models.py b/ereuse_devicehub/parser/models.py index 8caa0620..6389b12b 100644 --- a/ereuse_devicehub/parser/models.py +++ b/ereuse_devicehub/parser/models.py @@ -38,10 +38,15 @@ class SnapshotsLog(Thing): db.session.commit() def get_status(self): - return Severity(self.severity) + if self.snapshot: + if not self.snapshot.active: + return Severity(2) + return Severity(self.severity) + + return '' def get_device(self): - if self.snapshot: + if self.snapshot and self.snapshot.active: if self.snapshot.device.binding: return self.snapshot.device.binding.device.devicehub_id return self.snapshot.device.devicehub_id @@ -67,6 +72,9 @@ class SnapshotsLog(Thing): if not self.snapshot: return '' + if not self.snapshot.active: + return '' + if not self.snapshot.device: return '' diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 5f141570..b0ec76c6 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -678,7 +678,7 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice): sid = Column(CIText(), nullable=True) settings_version = Column(CIText(), nullable=True) is_server_erase = Column(Boolean(), nullable=True) - active = Column(Boolean(), nullable=True) + active = Column(Boolean(), default=True, nullable=False) def get_last_lifetimes(self): """We get the lifetime and serial_number of the first disk""" diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 735b68a0..bc406feb 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -877,14 +877,77 @@ class Device(Thing): } return types.get(self.type, '') - def split(self): + def unreliable(self): self.user_trusts = False + i = 0 + snapshot1 = None + + for ac in self.actions: + if ac.type == 'Snapshot': + if i == 0: + snapshot1 = ac + if i > 0: + ac.active = False + i += 1 + + if not snapshot1: + return + + self.reset_components(snapshot1) + return - def merge(self): - self.user_trusts = True + def reliable(self): + # self.user_trusts = True + computers = Computer.query.filter_by( + hid=self.hid, + owner_id=g.user.id, + active=True, + placeholder=None, + ).order_by(Device.created.asc()) + + i = 0 + computer1 = None + for d in computers: + if i == 0: + d.user_trusts = True + computer1 = d + i += 1 + continue + + d.user_trusts = True + d.active = False + d.binding.device.active = False + for ac in d.actions: + if ac.type == 'Snapshot': + ac.active = False + + for c in d.components: + c.parent = None + + if not computer1: + return + + snapshot1 = None + for ac in computer1.actions_one: + if ac.type == 'Snapshot': + snapshot1 = ac + break + + if not snapshot1: + return + + self.reset_components(snapshot1) + return + def reset_components(self, snapshot): + for c in snapshot.components: + if c.parent is None: + c.parent = snapshot.device + + snapshot.device.components = snapshot.components + def __lt__(self, other): return self.id < other.id diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index a82be1b1..8abe0550 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -125,7 +125,7 @@ class Sync: if component.hid: db_component = Device.query.filter_by( - hid=component.hid, owner_id=g.user.id, placeholder=None + hid=component.hid, owner_id=g.user.id, placeholder=None, active=True ).first() is_new = False if not db_component: From 9c2bc7d7fa03404a300de143557c95e3fb00dc4c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 10 Jan 2023 10:49:32 +0100 Subject: [PATCH 31/39] put the correct link in the snapshot to warning message --- ereuse_devicehub/inventory/forms.py | 26 ++++++++++++++++++++++++-- ereuse_devicehub/parser/models.py | 2 +- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 39321d8f..d5e31e2d 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -31,7 +31,7 @@ from wtforms.fields import FormField from ereuse_devicehub.db import db from ereuse_devicehub.inventory.models import DeliveryNote, ReceiverNote, Transfer -from ereuse_devicehub.parser.models import PlaceholdersLog +from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog from ereuse_devicehub.parser.parser import ParseSnapshotLsHw from ereuse_devicehub.parser.schemas import Snapshot_lite from ereuse_devicehub.resources.action.models import Snapshot, Trade @@ -1761,7 +1761,6 @@ class UserTrustsForm(FlaskForm): return False def save(self, commit=True): - # import pdb; pdb.set_trace() if not self.show(): return @@ -1770,11 +1769,34 @@ class UserTrustsForm(FlaskForm): if self.snapshot_type.data == 'update' and not self.unic(): self.device.reliable() + txt = "This devices is assigned as reliable for the user." + self.error_log(txt) if self.snapshot_type.data == 'new_device' and self.unic(): self.device.unreliable() + txt = "This devices is assigned as unreliable for the user " + txt += "and never is possible to do an update of this device." + self.error_log(txt) if commit: db.session.commit() return self.snapshot + + def error_log(self, txt): + snapshot = self.get_first_snapshot() + error = SnapshotsLog( + description=txt, + snapshot=snapshot, + snapshot_uuid=snapshot.uuid, + severity=Severity.Error, + sid=snapshot.sid, + version="{}".format(snapshot.version), + ) + db.session.add(error) + + def get_first_snapshot(self): + device = self.snapshot.device + for ac in device.actions: + if ac.type == 'Snapshot': + return ac diff --git a/ereuse_devicehub/parser/models.py b/ereuse_devicehub/parser/models.py index 6389b12b..85eb8251 100644 --- a/ereuse_devicehub/parser/models.py +++ b/ereuse_devicehub/parser/models.py @@ -46,7 +46,7 @@ class SnapshotsLog(Thing): return '' def get_device(self): - if self.snapshot and self.snapshot.active: + if self.snapshot: if self.snapshot.device.binding: return self.snapshot.device.binding.device.devicehub_id return self.snapshot.device.devicehub_id From 9603ac1f4331151f62353d5b68638b74617bdcc2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 11 Jan 2023 09:38:39 +0100 Subject: [PATCH 32/39] . --- ereuse_devicehub/resources/device/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index bc406feb..663484d8 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -879,6 +879,7 @@ class Device(Thing): def unreliable(self): self.user_trusts = False + tmp_snapshots = app.config['TMP_SNAPSHOTS'] i = 0 snapshot1 = None From bc12258db0324616fdab1d14c1ed9b7908dac117 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 11 Jan 2023 17:17:50 +0100 Subject: [PATCH 33/39] create device --- ereuse_devicehub/resources/device/models.py | 36 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 663484d8..784ddc61 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1,6 +1,9 @@ import copy import hashlib +import json +import os import pathlib +import uuid from contextlib import suppress from fractions import Fraction from itertools import chain @@ -879,25 +882,54 @@ class Device(Thing): def unreliable(self): self.user_trusts = False - tmp_snapshots = app.config['TMP_SNAPSHOTS'] i = 0 snapshot1 = None + snapshots = {} for ac in self.actions: if ac.type == 'Snapshot': if i == 0: snapshot1 = ac if i > 0: - ac.active = False + snapshots[ac] = self.get_snapshot_file(ac) + # ac.active = False i += 1 if not snapshot1: return + self.create_new_device(snapshots.values()) + # [self.remove_snapshot(ac) for ac in snapshots.keys()] self.reset_components(snapshot1) return + def get_snapshot_file(self, action): + uuid = action.uuid + user = g.user.email + name_file = f"*_{user}_{uuid}.json" + tmp_snapshots = app.config['TMP_SNAPSHOTS'] + path_dir_base = os.path.join(tmp_snapshots, user) + + for _file in pathlib.Path(path_dir_base).glob(name_file): + with open(_file) as file_snapshot: + snapshot = file_snapshot.read() + return json.loads(snapshot) + + def create_new_device(self, snapshots): + from ereuse_devicehub.inventory.forms import UploadSnapshotForm + + new_snapshots = [] + for snapshot in snapshots: + snapshot['uuid'] = str(uuid.uuid4()) + filename = "{}.json".format(snapshot['uuid']) + new_snapshots.append((filename, snapshot)) + + form = UploadSnapshotForm() + form.result = {} + form.snapshots = new_snapshots + form.save(commit=False) + def reliable(self): # self.user_trusts = True computers = Computer.query.filter_by( From 520f1726be65cb889f5de4e066041cd1e9782596 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 13 Jan 2023 17:42:42 +0100 Subject: [PATCH 34/39] reliable device --- ereuse_devicehub/inventory/forms.py | 11 ++-- .../resources/action/views/snapshot.py | 7 ++- ereuse_devicehub/resources/device/models.py | 52 +++++++++++++------ ereuse_devicehub/resources/device/sync.py | 11 ++-- tests/test_render_2_0.py | 39 ++++++++++++++ 5 files changed, 96 insertions(+), 24 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index d5e31e2d..61a1b3df 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -2,6 +2,7 @@ import copy import csv import datetime import json +import uuid from json.decoder import JSONDecodeError import pandas as pd @@ -249,6 +250,10 @@ class LotForm(FlaskForm): class UploadSnapshotForm(SnapshotMixin, FlaskForm): snapshot = MultipleFileField('Select a Snapshot File', [validators.DataRequired()]) + def __init__(self, *args, **kwargs): + self.create_new_devices = kwargs.pop('create_new_devices', False) + super().__init__(*args, **kwargs) + def validate(self, extra_validators=None): is_valid = super().validate(extra_validators) @@ -319,7 +324,9 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm): try: snapshot_json = schema.load(snapshot_json) - response = self.build(snapshot_json) + response = self.build( + snapshot_json, create_new_device=self.create_new_devices + ) except ValidationError as err: txt = "{}".format(err) self.errors(txt=txt) @@ -1769,8 +1776,6 @@ class UserTrustsForm(FlaskForm): if self.snapshot_type.data == 'update' and not self.unic(): self.device.reliable() - txt = "This devices is assigned as reliable for the user." - self.error_log(txt) if self.snapshot_type.data == 'new_device' and self.unic(): self.device.unreliable() diff --git a/ereuse_devicehub/resources/action/views/snapshot.py b/ereuse_devicehub/resources/action/views/snapshot.py index c5df4838..8fb2758e 100644 --- a/ereuse_devicehub/resources/action/views/snapshot.py +++ b/ereuse_devicehub/resources/action/views/snapshot.py @@ -64,7 +64,8 @@ def move_json(tmp_snapshots, path_name, user, live=False): class SnapshotMixin: sync = Sync() - def build(self, snapshot_json=None): # noqa: C901 + def build(self, snapshot_json=None, create_new_device=False): # noqa: C901 + self.create_new_device = create_new_device if not snapshot_json: snapshot_json = self.snapshot_json device = snapshot_json.pop('device') # type: Computer @@ -87,7 +88,9 @@ class SnapshotMixin: assert not device.actions_one assert all(not c.actions_one for c in components) if components else True - db_device, remove_actions = self.sync.run(device, components) + db_device, remove_actions = self.sync.run( + device, components, self.create_new_device + ) del device # Do not use device anymore snapshot.device = db_device diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index f9335d59..78bae1d9 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -894,15 +894,13 @@ class Device(Thing): snapshot1 = ac if i > 0: snapshots[ac] = self.get_snapshot_file(ac) - # ac.active = False i += 1 if not snapshot1: return self.create_new_device(snapshots.values()) - # [self.remove_snapshot(ac) for ac in snapshots.keys()] - self.reset_components(snapshot1) + self.remove_snapshot(snapshots.keys()) return @@ -930,10 +928,42 @@ class Device(Thing): form = UploadSnapshotForm() form.result = {} form.snapshots = new_snapshots + form.create_new_devices = True form.save(commit=False) + def remove_snapshot(self, snapshots): + from ereuse_devicehub.parser.models import SnapshotsLog + + for ac in snapshots: + for slog in SnapshotsLog.query.filter_by(snapshot=ac): + slog.snapshot_id = None + slog.snapshot_uuid = None + db.session.delete(ac) + + def remove_devices(self, devices): + from ereuse_devicehub.parser.models import SnapshotsLog + + for dev in devices: + for ac in dev.actions: + if ac.type != 'Snapshot': + continue + for slog in SnapshotsLog.query.filter_by(snapshot=ac): + slog.snapshot_id = None + slog.snapshot_uuid = None + + for c in dev.components: + c.parent_id = None + + for tag in dev.tags: + tag.device_id = None + + placeholder = dev.binding or dev.placeholder + if placeholder: + db.session.delete(placeholder.binding) + db.session.delete(placeholder.device) + db.session.delete(placeholder) + def reliable(self): - # self.user_trusts = True computers = Computer.query.filter_by( hid=self.hid, owner_id=g.user.id, @@ -943,6 +973,7 @@ class Device(Thing): i = 0 computer1 = None + computers_to_remove = [] for d in computers: if i == 0: d.user_trusts = True @@ -950,16 +981,9 @@ class Device(Thing): i += 1 continue - d.user_trusts = True - d.active = False - d.binding.device.active = False - for ac in d.actions: - if ac.type == 'Snapshot': - ac.active = False - - for c in d.components: - c.parent = None + computers_to_remove.append(d) + self.remove_devices(computers_to_remove) if not computer1: return @@ -981,8 +1005,6 @@ class Device(Thing): if c.parent is None: c.parent = snapshot.device - snapshot.device.components = snapshot.components - def __lt__(self, other): return self.id < other.id diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 8abe0550..8dfba8b2 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -35,7 +35,10 @@ class Sync: """Synchronizes the device and components with the database.""" def run( - self, device: Device, components: Iterable[Component] or None + self, + device: Device, + components: Iterable[Component] or None, + create_new_device=False, ) -> (Device, OrderedSet): """Synchronizes the device and components with the database. @@ -71,7 +74,7 @@ class Sync: device.components = OrderedSet(components) device.set_hid() device.components = OrderedSet() - db_device = self.execute_register(device) + db_device = self.execute_register(device, create_new_device) db_components, actions = OrderedSet(), OrderedSet() if components is not None: # We have component info (see above) @@ -134,7 +137,7 @@ class Sync: is_new = True return db_component, is_new - def execute_register(self, device: Device) -> Device: + def execute_register(self, device: Device, create_new_device=False) -> Device: """Synchronizes one device to the DB. This method tries to get an existing device using the HID @@ -166,7 +169,7 @@ class Sync: if db_device and db_device.allocated: raise ResourceNotFound('device is actually allocated {}'.format(device)) - if not db_device: + if not db_device or create_new_device: device.tags.clear() # We don't want to add the transient dummy tags db.session.add(device) db_device = device diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index 101451c0..f6d21225 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -2672,3 +2672,42 @@ def test_system_uuid_motherboard(user3: UserClientFlask): for c in snapshot.device.components: if c.type == 'Motherboard': assert c.serial_number == 'abee0123456720' + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_unreliable_device(user3: UserClientFlask): + snapshot = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + + uri = '/inventory/upload-snapshot/' + file_name = 'real-eee-1001pxd.snapshot.12' + snapshot_json = conftest.yaml2json(file_name) + snapshot_json['uuid'] = 'c058e8d2-fb92-47cb-a4b7-522b75561136' + b_snapshot = bytes(json.dumps(snapshot_json), 'utf-8') + file_snap = (BytesIO(b_snapshot), file_name) + user3.get(uri) + + data = { + 'snapshot': file_snap, + 'csrf_token': generate_csrf(), + } + user3.post(uri, data=data, content_type="multipart/form-data") + snapshot2 = Snapshot.query.filter_by(uuid=snapshot_json['uuid']).first() + assert snapshot2.device == snapshot.device + + uuid2 = snapshot2.uuid + uri = f"/inventory/snapshots/{uuid2}/" + user3.get(uri) + + data = { + 'snapshot_type': "new_device", + 'csrf_token': generate_csrf(), + } + assert Device.query.filter_by(hid=snapshot.device.hid).count() == 2 + user3.post(uri, data=data) + assert Device.query.filter_by(hid=snapshot.device.hid).count() == 4 + assert Snapshot.query.count() == 3 + + import pdb + + pdb.set_trace() From 6fc802e1592feb7f34ef4636b0996a3de8324f1d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 16 Jan 2023 15:26:58 +0100 Subject: [PATCH 35/39] fix test reliable --- ereuse_devicehub/inventory/forms.py | 16 ++--- .../93daff872771_add_hash_hid_to_device.py | 9 --- ereuse_devicehub/parser/models.py | 5 -- ereuse_devicehub/resources/action/models.py | 6 +- ereuse_devicehub/resources/device/models.py | 10 +-- tests/test_render_2_0.py | 69 ++++++++++++++++++- 6 files changed, 76 insertions(+), 39 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 61a1b3df..9e14ca13 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -2,7 +2,6 @@ import copy import csv import datetime import json -import uuid from json.decoder import JSONDecodeError import pandas as pd @@ -204,7 +203,7 @@ class FilterForm(FlaskForm): if filter_type: self.devices = self.devices.filter(Device.type.in_(filter_type)) - return self.devices.filter(Device.active == True).order_by( + return self.devices.filter(Device.active.is_(False)).order_by( Device.updated.desc() ) @@ -1735,22 +1734,21 @@ class UserTrustsForm(FlaskForm): try: return self._unic except Exception: - self._unic = ( + self._devices = ( Device.query.filter_by( hid=self.device.hid, owner=g.user, placeholder=None, active=True - ).count() - < 2 + ) + .order_by(Device.updated.asc()) + .all() ) + self._unic = len(self._devices) < 2 return self._unic def show(self): if not self.snapshot or not self.device: return False - if not self.snapshot.active: - return False - if not hasattr(self.device, 'system_uuid'): return False @@ -1762,6 +1760,8 @@ class UserTrustsForm(FlaskForm): return True if not self.unic(): + if self.device == self._devices[0]: + return False # To do merge return True diff --git a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py index e274496e..9b33ca95 100644 --- a/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py +++ b/ereuse_devicehub/migrations/versions/93daff872771_add_hash_hid_to_device.py @@ -39,7 +39,6 @@ def upgrade_data(): sql = f"update {get_inv()}.device set chid='{chid}' where id={dev_id};" con.execute(sql) - sql = f"update {get_inv()}.snapshot set active=true;" con.execute(sql) @@ -56,19 +55,11 @@ def upgrade(): schema=f'{get_inv()}', ) - op.add_column( - 'snapshot', - sa.Column('active', sa.Boolean(), default=True, nullable=True), - schema=f'{get_inv()}', - ) - upgrade_data() op.alter_column('computer', 'user_trusts', nullable=False, schema=f'{get_inv()}') - op.alter_column('snapshot', 'active', nullable=False, schema=f'{get_inv()}') def downgrade(): op.drop_column('computer', 'user_trusts', schema=f'{get_inv()}') op.drop_column('device', 'chid', schema=f'{get_inv()}') - op.drop_column('snapshot', 'active', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/parser/models.py b/ereuse_devicehub/parser/models.py index 85eb8251..79414270 100644 --- a/ereuse_devicehub/parser/models.py +++ b/ereuse_devicehub/parser/models.py @@ -39,8 +39,6 @@ class SnapshotsLog(Thing): def get_status(self): if self.snapshot: - if not self.snapshot.active: - return Severity(2) return Severity(self.severity) return '' @@ -72,9 +70,6 @@ class SnapshotsLog(Thing): if not self.snapshot: return '' - if not self.snapshot.active: - return '' - if not self.snapshot.device: return '' diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index b0ec76c6..1f373962 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -48,17 +48,14 @@ from sqlalchemy.util import OrderedSet from teal.db import ( CASCADE_OWN, INHERIT_COND, - IP, POLYMORPHIC_ID, POLYMORPHIC_ON, URL, - ResourceNotFound, StrictVersionType, check_lower, check_range, ) -from teal.enums import Country, Currency, Subdivision -from teal.marshmallow import ValidationError +from teal.enums import Currency from teal.resource import url_for_resource from ereuse_devicehub.db import db @@ -678,7 +675,6 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice): sid = Column(CIText(), nullable=True) settings_version = Column(CIText(), nullable=True) is_server_erase = Column(Boolean(), nullable=True) - active = Column(Boolean(), default=True, nullable=False) def get_last_lifetimes(self): """We get the lifetime and serial_number of the first disk""" diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 78bae1d9..378613df 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -275,8 +275,7 @@ class Device(Thing): for ac in actions_one: ac.real_created = ac.created - if ac.type != 'Snapshot' or ac.active: - actions.append(ac) + actions.append(ac) return sorted(actions, key=lambda x: x.real_created) @@ -996,15 +995,8 @@ class Device(Thing): if not snapshot1: return - self.reset_components(snapshot1) - return - def reset_components(self, snapshot): - for c in snapshot.components: - if c.parent is None: - c.parent = snapshot.device - def __lt__(self, other): return self.id < other.id diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index f6d21225..ac8c6887 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -2677,8 +2677,10 @@ def test_system_uuid_motherboard(user3: UserClientFlask): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_unreliable_device(user3: UserClientFlask): + # Create device snapshot = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + # Update device uri = '/inventory/upload-snapshot/' file_name = 'real-eee-1001pxd.snapshot.12' snapshot_json = conftest.yaml2json(file_name) @@ -2694,7 +2696,13 @@ def test_unreliable_device(user3: UserClientFlask): user3.post(uri, data=data, content_type="multipart/form-data") snapshot2 = Snapshot.query.filter_by(uuid=snapshot_json['uuid']).first() assert snapshot2.device == snapshot.device + assert Snapshot.query.count() == 2 + snapshots = Snapshot.query.all() + assert snapshots[0].device == snapshots[1].device + assert len(snapshots[0].device.components) + assert snapshot2 in snapshots + # Change update for new device uuid2 = snapshot2.uuid uri = f"/inventory/snapshots/{uuid2}/" user3.get(uri) @@ -2706,8 +2714,63 @@ def test_unreliable_device(user3: UserClientFlask): assert Device.query.filter_by(hid=snapshot.device.hid).count() == 2 user3.post(uri, data=data) assert Device.query.filter_by(hid=snapshot.device.hid).count() == 4 - assert Snapshot.query.count() == 3 + assert Snapshot.query.count() == 2 + snapshots = Snapshot.query.all() + assert snapshot2 not in snapshots + assert snapshots[0].device != snapshots[1].device + assert len(snapshots[0].device.components) == 4 + assert len(snapshots[1].device.components) == 9 + assert len(snapshots[0].device.actions) == 11 + assert len(snapshots[1].device.actions) == 10 - import pdb - pdb.set_trace() +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_reliable_device(user3: UserClientFlask): + # Create device + snapshot = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + + # Update device + uri = '/inventory/upload-snapshot/' + file_name = 'real-eee-1001pxd.snapshot.12' + snapshot_json = conftest.yaml2json(file_name) + snapshot_json['uuid'] = 'c058e8d2-fb92-47cb-a4b7-522b75561136' + b_snapshot = bytes(json.dumps(snapshot_json), 'utf-8') + file_snap = (BytesIO(b_snapshot), file_name) + user3.get(uri) + + data = { + 'snapshot': file_snap, + 'csrf_token': generate_csrf(), + } + user3.post(uri, data=data, content_type="multipart/form-data") + snapshot2 = Snapshot.query.filter_by(uuid=snapshot_json['uuid']).first() + + # Change update for new device + uuid2 = snapshot2.uuid + uri = f"/inventory/snapshots/{uuid2}/" + user3.get(uri) + + data = { + 'snapshot_type': "new_device", + 'csrf_token': generate_csrf(), + } + user3.post(uri, data=data) + + # Change update for update + snapshot3 = Snapshot.query.all()[-1] + uuid3 = snapshot3.uuid + uri = f"/inventory/snapshots/{uuid3}/" + user3.get(uri) + + data = { + 'snapshot_type': "update", + 'csrf_token': generate_csrf(), + } + assert Device.query.filter_by(hid=snapshot.device.hid).count() == 4 + user3.post(uri, data=data) + assert Device.query.filter_by(hid=snapshot.device.hid).count() == 2 + assert Snapshot.query.count() == 1 + assert Snapshot.query.first() == snapshot + assert len(snapshot.device.components) == 4 + assert len(snapshot.device.actions) == 4 From a572ef05076c75d8e2d34c1fbfc9d68e432ca941 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 17 Jan 2023 13:00:34 +0100 Subject: [PATCH 36/39] add pop up --- .../templates/inventory/snapshot_detail.html | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/templates/inventory/snapshot_detail.html b/ereuse_devicehub/templates/inventory/snapshot_detail.html index b084f76b..4c4bb09a 100644 --- a/ereuse_devicehub/templates/inventory/snapshot_detail.html +++ b/ereuse_devicehub/templates/inventory/snapshot_detail.html @@ -50,7 +50,9 @@ {% endif %} {% endfor %}

- + + Save +

@@ -86,4 +88,49 @@
+ + + {% endblock main %} + From f8d418b4a9672cd3dae908eaf05150a208727dec Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 17 Jan 2023 13:07:01 +0100 Subject: [PATCH 37/39] add pop up --- .../templates/inventory/snapshot_detail.html | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/templates/inventory/snapshot_detail.html b/ereuse_devicehub/templates/inventory/snapshot_detail.html index 4c4bb09a..c3a91cec 100644 --- a/ereuse_devicehub/templates/inventory/snapshot_detail.html +++ b/ereuse_devicehub/templates/inventory/snapshot_detail.html @@ -40,7 +40,7 @@
Change Snapshot Type Upload
-
+ {{ form.csrf_token }} {% for f in form %} {% if f != form.csrf_token %} @@ -114,7 +114,7 @@ @@ -124,12 +124,18 @@
{% endblock main %} From c26d2d69b9deab108cebf56fa786e98e7b9abdc6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 17 Jan 2023 13:18:18 +0100 Subject: [PATCH 38/39] fix filter active TRue --- ereuse_devicehub/inventory/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 9e14ca13..90b900f5 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -203,7 +203,7 @@ class FilterForm(FlaskForm): if filter_type: self.devices = self.devices.filter(Device.type.in_(filter_type)) - return self.devices.filter(Device.active.is_(False)).order_by( + return self.devices.filter(Device.active.is_(True)).order_by( Device.updated.desc() ) From 9db949cef2b136e1a341e6c3f8a5bde3cd48313c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 18 Jan 2023 12:38:08 +0100 Subject: [PATCH 39/39] add correct descriptions in the pop ups --- ereuse_devicehub/inventory/forms.py | 10 ++++++++++ .../templates/inventory/snapshot_detail.html | 15 +++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 90b900f5..1e641f32 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1745,6 +1745,16 @@ class UserTrustsForm(FlaskForm): self._unic = len(self._devices) < 2 return self._unic + def dhids_all_devices(self): + self.unic() + return ", ".join([x.dhid for x in self._devices][1:]) + + def dhid_base(self): + self.unic() + if not self._devices: + return '' + return self._devices[0].dhid + def show(self): if not self.snapshot or not self.device: return False diff --git a/ereuse_devicehub/templates/inventory/snapshot_detail.html b/ereuse_devicehub/templates/inventory/snapshot_detail.html index c3a91cec..efba84d4 100644 --- a/ereuse_devicehub/templates/inventory/snapshot_detail.html +++ b/ereuse_devicehub/templates/inventory/snapshot_detail.html @@ -100,14 +100,21 @@