From 236fcac0b81b45aa06c783e1920977b0a76c6120 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 16 Nov 2022 11:51:31 +0100 Subject: [PATCH 01/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] . --- 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/84] 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/84] 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/84] 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/84] . --- 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] . --- 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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/84] 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 @@ From 850278c2970c486b7d0e51b5153dab8bf88291dc Mon Sep 17 00:00:00 2001 From: Nadeu Date: Thu, 19 Jan 2023 10:27:01 +0100 Subject: [PATCH 40/84] Update HWMD iso to 2022.12.2-beta --- ereuse_devicehub/workbench/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/workbench/__init__.py b/ereuse_devicehub/workbench/__init__.py index 8f9bf153..70ac8a85 100644 --- a/ereuse_devicehub/workbench/__init__.py +++ b/ereuse_devicehub/workbench/__init__.py @@ -4,7 +4,7 @@ isos = { 'url': 'https://releases.usody.com/demo/', }, "register": { - 'iso': "USODY_2022.12.1-beta.iso", + 'iso': "USODY_2022.12.2-beta.iso", 'url': 'https://releases.usody.com/2022/', }, "erease": { From de9b525737c76eb0802d7fca63ecc0f203c6f382 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 26 Jan 2023 10:46:34 +0100 Subject: [PATCH 41/84] . --- ereuse_devicehub/inventory/forms.py | 4 +++- ereuse_devicehub/resources/device/models.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 1e641f32..1910c3e8 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -297,7 +297,7 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm): return is_lite - def save(self, commit=True): + def save(self, commit=True, user_trusts=True): if any([x == 'Error' for x in self.result.values()]): return schema = SnapshotSchema() @@ -332,6 +332,8 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm): self.result[filename] = 'Error' continue + import pdb; pdb.set_trace() + response.device.user_trusts = user_trusts db.session.add(response) devices.append(response.device.binding.device) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 378613df..da129b55 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -898,7 +898,7 @@ class Device(Thing): if not snapshot1: return - self.create_new_device(snapshots.values()) + self.create_new_device(snapshots.values(), user_trusts=self.user_trusts) self.remove_snapshot(snapshots.keys()) return @@ -915,7 +915,7 @@ class Device(Thing): snapshot = file_snapshot.read() return json.loads(snapshot) - def create_new_device(self, snapshots): + def create_new_device(self, snapshots, user_trusts=True): from ereuse_devicehub.inventory.forms import UploadSnapshotForm new_snapshots = [] @@ -928,7 +928,7 @@ class Device(Thing): form.result = {} form.snapshots = new_snapshots form.create_new_devices = True - form.save(commit=False) + form.save(commit=False, user_trusts=user_trusts) def remove_snapshot(self, snapshots): from ereuse_devicehub.parser.models import SnapshotsLog From 6c9334fa761ddab7083183ce360150c8d636b68e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 26 Jan 2023 11:35:08 +0100 Subject: [PATCH 42/84] fix test 2 --- ereuse_devicehub/inventory/forms.py | 5 +++-- ereuse_devicehub/resources/device/models.py | 18 ++++++++++++++++++ ereuse_devicehub/resources/device/sync.py | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 1910c3e8..451684e1 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -44,6 +44,7 @@ from ereuse_devicehub.resources.action.views.snapshot import ( from ereuse_devicehub.resources.device.models import ( SAI, Cellphone, + Computer, ComputerMonitor, Desktop, Device, @@ -332,8 +333,8 @@ class UploadSnapshotForm(SnapshotMixin, FlaskForm): self.result[filename] = 'Error' continue - import pdb; pdb.set_trace() - response.device.user_trusts = user_trusts + if isinstance(response.device, Computer): + response.device.user_trusts = user_trusts db.session.add(response) devices.append(response.device.binding.device) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index da129b55..8d2baec1 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -756,6 +756,24 @@ class Device(Thing): return "" + def get_exist_untrusted_device(self): + if isinstance(self, Computer): + if not self.system_uuid: + return True + + return ( + Computer.query.filter_by( + hid=self.hid, + user_trusts=False, + owner_id=g.user.id, + active=True, + placeholder=None, + ).first() + or False + ) + + return False + def get_from_db(self): if 'property_hid' in app.blueprints.keys(): try: diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 8dfba8b2..510e425a 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -171,6 +171,8 @@ class Sync: if not db_device or create_new_device: device.tags.clear() # We don't want to add the transient dummy tags + if create_new_device or device.get_exist_untrusted_device(): + device.user_trusts = False db.session.add(device) db_device = device try: From 38b77c111a0b3ba9a12ae30f8bce33ee44b5803a Mon Sep 17 00:00:00 2001 From: Nadeu Date: Fri, 27 Jan 2023 12:04:54 +0100 Subject: [PATCH 43/84] Update 14.1.0 iso --- ereuse_devicehub/workbench/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/workbench/__init__.py b/ereuse_devicehub/workbench/__init__.py index 70ac8a85..11e71c7c 100644 --- a/ereuse_devicehub/workbench/__init__.py +++ b/ereuse_devicehub/workbench/__init__.py @@ -8,7 +8,7 @@ isos = { 'url': 'https://releases.usody.com/2022/', }, "erease": { - 'iso': "USODY_14.0.0.iso", + 'iso': "USODY_14.1.0.iso", 'url': 'https://releases.usody.com/v14/', }, } From 799c003a090aae62f471eec2ac643c46aabbd59e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 1 Feb 2023 17:29:43 +0100 Subject: [PATCH 44/84] fix --- .../resources/device/templates/devices/layout.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/device/templates/devices/layout.html b/ereuse_devicehub/resources/device/templates/devices/layout.html index a9509915..3a31902c 100644 --- a/ereuse_devicehub/resources/device/templates/devices/layout.html +++ b/ereuse_devicehub/resources/device/templates/devices/layout.html @@ -116,8 +116,8 @@ {{ component.created.strftime('%H:%M %d-%m-%Y') }}

- {{ component.manufacturer }}
- {{ component.model }}
+ {{ component.manufacturer or '- not detected -' }}
+ {{ component.model or '- not detected -' }}

{% if component.type in ['RamModule', 'HardDrive', 'SolidStateDrive'] %} From bed2c534b545a90aeb6693bf88120cc670a520fa Mon Sep 17 00:00:00 2001 From: Stephan Fortelny Date: Thu, 2 Feb 2023 08:01:53 +0100 Subject: [PATCH 45/84] Updated links to Terms & Conditions and Privacy Policy now hosted in English on usody.com --- ereuse_devicehub/templates/ereuse_devicehub/base_site.html | 4 ++-- ereuse_devicehub/templates/ereuse_devicehub/user_login.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ereuse_devicehub/templates/ereuse_devicehub/base_site.html b/ereuse_devicehub/templates/ereuse_devicehub/base_site.html index f3865433..6b5b748d 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/base_site.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/base_site.html @@ -309,8 +309,8 @@
Help | - Privacy | - Terms + Privacy | + Terms
DeviceHub {{ version }} diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_login.html b/ereuse_devicehub/templates/ereuse_devicehub/user_login.html index 78776b16..1de011b4 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_login.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_login.html @@ -71,8 +71,8 @@
Help | - Privacy | - Terms + Privacy | + Terms
From 4055365bc94d6a84cfa6b3718d9b533436eb62d4 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 2 Feb 2023 10:58:09 +0100 Subject: [PATCH 46/84] fix dummy --- ereuse_devicehub/dummy/dummy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py index ec276de4..f3533d48 100644 --- a/ereuse_devicehub/dummy/dummy.py +++ b/ereuse_devicehub/dummy/dummy.py @@ -230,7 +230,7 @@ class Dummy: user1.get(res=Device, item=sample_pc_devicehub_id) # Test anonymous = self.app.test_client() html, _ = anonymous.get(res=Device, item=sample_pc_devicehub_id, accept=ANY) - assert 'intel core2 duo cpu' in html + assert 'hewlett-packard' in html # For netbook: to preapre -> torepair -> to dispose -> disposed print('⭐ Done.') From 2553a9cdd0f7e78c5ce69f45c80d9a53fba30cf1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 2 Feb 2023 10:58:37 +0100 Subject: [PATCH 47/84] fix footer --- .../device/templates/devices/layout.html | 81 ++++++++++++++----- .../templates/ereuse_devicehub/base_site.html | 4 +- .../ereuse_devicehub/user_login.html | 4 +- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/ereuse_devicehub/resources/device/templates/devices/layout.html b/ereuse_devicehub/resources/device/templates/devices/layout.html index 3a31902c..f71806c0 100644 --- a/ereuse_devicehub/resources/device/templates/devices/layout.html +++ b/ereuse_devicehub/resources/device/templates/devices/layout.html @@ -1,7 +1,44 @@ -{% extends "ereuse_devicehub/base.html" %} -{% block page_title %}Device {{ device.dhid }}{% endblock %} + + + + + + + + Device {{ device_real.dhid }} - Usody + + + + + + + + + + + + + + + + + + + + + + + + + + + -{% block body %}
@@ -159,23 +196,25 @@
-
-
-
-
- -
- Help | - Privacy | - Terms -
-
- DeviceHub -
-
+
+
+
+
+ +
+ Help | + Privacy | + Terms +
+
+ DeviceHub +
+
+
-
-{% endblock body%} + + + diff --git a/ereuse_devicehub/templates/ereuse_devicehub/base_site.html b/ereuse_devicehub/templates/ereuse_devicehub/base_site.html index 6b5b748d..f6dfb1b3 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/base_site.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/base_site.html @@ -309,8 +309,8 @@
Help | - Privacy | - Terms + Privacy | + Terms
DeviceHub {{ version }} diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_login.html b/ereuse_devicehub/templates/ereuse_devicehub/user_login.html index 1de011b4..b8b6cbc0 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_login.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_login.html @@ -71,8 +71,8 @@
Help | - Privacy | - Terms + Privacy | + Terms
From 77c8e2181fb7cceb08313907b01ddadc17941eed Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 10 Feb 2023 20:09:22 +0100 Subject: [PATCH 48/84] only sync DataStorages --- ereuse_devicehub/resources/device/sync.py | 19 ++++++++++--------- tests/test_action.py | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 510e425a..32c4a2f2 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -16,19 +16,20 @@ 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 -DEVICES_ALLOW_DUPLICITY = [ - 'RamModule', - 'Display', - 'SoundCard', - 'Battery', - 'Camera', - 'GraphicCard', -] +# DEVICES_ALLOW_DUPLICITY = [ +# 'RamModule', +# 'Display', +# 'SoundCard', +# 'Battery', +# 'Camera', +# 'GraphicCard', +# ] class Sync: @@ -119,7 +120,7 @@ class Sync: """ 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: + if not isinstance(component, DataStorage): db.session.add(component) is_new = True return component, is_new diff --git a/tests/test_action.py b/tests/test_action.py index 9ccb07a3..01ca8ca6 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')] ] ) - == 2 + == 0 ) From ead6f3af78103ad799df9132da3becfb53fad16d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 13 Feb 2023 11:57:12 +0100 Subject: [PATCH 49/84] fix tests --- tests/test_render_2_0.py | 6 ++-- tests/test_snapshot.py | 71 ++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index ac8c6887..dc4a7cf2 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -2718,7 +2718,7 @@ def test_unreliable_device(user3: UserClientFlask): 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[0].device.components) == 8 assert len(snapshots[1].device.components) == 9 assert len(snapshots[0].device.actions) == 11 assert len(snapshots[1].device.actions) == 10 @@ -2772,5 +2772,5 @@ def test_reliable_device(user3: UserClientFlask): 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 + assert len(snapshot.device.components) == 8 + assert len(snapshot.device.actions) == 7 diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index 9b4eca8e..6501a01c 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -158,12 +158,6 @@ def test_snapshot_update_timefield_updated(user: UserClient): perform_second_snapshot=False, ) computer2 = yaml2json('2-second-device-with-components-of-first.snapshot') - snapshot_and_check( - user, - computer2, - action_types=('Remove',), - perform_second_snapshot=False, - ) pc1_devicehub_id = snapshot['device']['devicehubID'] pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id) assert pc1['updated'] != snapshot['device']['updated'] @@ -264,30 +258,25 @@ def test_snapshot_component_add_remove(user: UserClient): pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id) pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id) # Check if the update_timestamp is updated - update1_pc2 = pc2['updated'] - update2_pc1 = pc1['updated'] - assert update1_pc1 != update2_pc1 # PC1 - assert tuple(c['serialNumber'] for c in pc1['components']) == ('p1c1s', 'p1c3s') + assert tuple(c['serialNumber'] for c in pc1['components']) == ( + 'p1c1s', + 'p1c2s', + 'p1c3s', + ) assert all(c['parent'] == pc1_id for c in pc1['components']) assert tuple(e['type'] for e in pc1['actions']) == ( 'BenchmarkProcessor', 'Snapshot', - 'Remove', ) # PC2 - assert tuple(c['serialNumber'] for c in pc2['components']) == ('p1c2s', 'p2c1s') + assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s', 'p1c2s') assert all(c['parent'] == pc2_id for c in pc2['components']) assert tuple(e['type'] for e in pc2['actions']) == ('Snapshot',) # p1c2s has two Snapshots, a Remove and an Add - p1c2s_dev = m.Device.query.filter_by(id=pc2['components'][0]['id']).one() + p1c2s_dev = m.Device.query.filter_by(id=pc2['components'][1]['id']).one() p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id) - assert tuple(e['type'] for e in p1c2s['actions']) == ( - 'BenchmarkProcessor', - 'Snapshot', - 'Snapshot', - 'Remove', - ) + assert tuple(e['type'] for e in p1c2s['actions']) == ('Snapshot',) # We register the first device again, but removing motherboard # and moving processor from the second device to the first. @@ -296,42 +285,29 @@ def test_snapshot_component_add_remove(user: UserClient): s3 = yaml2json( '3-first-device-but-removing-motherboard-and-adding-processor-from-2.snapshot' ) - snapshot_and_check(user, s3, ('Remove',), perform_second_snapshot=False) pc1, _ = user.get(res=m.Device, item=pc1_devicehub_id) pc2, _ = user.get(res=m.Device, item=pc2_devicehub_id) # Check if the update_timestamp is updated update2_pc2 = pc2['updated'] update3_pc1 = pc1['updated'] - assert not update3_pc1 in [update1_pc1, update2_pc1] - assert update1_pc2 != update2_pc2 # PC1 - assert {c['serialNumber'] for c in pc1['components']} == {'p1c2s', 'p1c3s'} - assert all(c['parent'] == pc1_id for c in pc1['components']) + assert {c['serialNumber'] for c in pc1['components']} == {'p1c1s', 'p1c3s', 'p1c2s'} + assert all(c['parent'] == pc1['id'] for c in pc1['components']) assert tuple(get_actions_info(pc1['actions'])) == ( # id, type, components, snapshot ('BenchmarkProcessor', []), # first BenchmarkProcessor - ('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s', 'p1c2s']), # first Snapshot1 - ('Remove', ['p1c2s', 'p1c2s']), # Remove Processor in Snapshot2 - ('Snapshot', ['p1c2s', 'p1c3s']), # This Snapshot3 + ('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s']), # first Snapshot1 ) # PC2 - assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s',) - assert all(c['parent'] == pc2_id for c in pc2['components']) - assert tuple(e['type'] for e in pc2['actions']) == ( - 'Snapshot', # Second Snapshot - 'Remove', # the processor we added in 2. - ) + assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s', 'p1c2s') + assert all(c['parent'] == pc2['id'] for c in pc2['components']) + assert tuple(e['type'] for e in pc2['actions']) == ('Snapshot',) # Second Snapshot # p1c2s has Snapshot, Remove and Add p1c2s_dev = m.Device.query.filter_by(id=pc1['components'][0]['id']).one() p1c2s, _ = user.get(res=m.Device, item=p1c2s_dev.devicehub_id) assert tuple(get_actions_info(p1c2s['actions'])) == ( - ('BenchmarkProcessor', []), # first BenchmarkProcessor - ('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s', 'p1c2s']), # First Snapshot to PC1 - ('Snapshot', ['p1c2s', 'p2c1s']), # Second Snapshot to PC2 - ('Remove', ['p1c2s', 'p1c2s']), # ...which caused p1c2s to be removed form PC1 - ('Snapshot', ['p1c2s', 'p1c3s']), # The third Snapshot to PC1 - ('Remove', ['p1c2s']), # ...which caused p1c2 to be removed from PC2 + ('Snapshot', ['p1c1s', 'p1c2s', 'p1c3s']), # First Snapshot to PC1 ) # We register the first device but without the processor, @@ -344,16 +320,15 @@ def test_snapshot_component_add_remove(user: UserClient): # Check if the update_timestamp is updated update3_pc2 = pc2['updated'] update4_pc1 = pc1['updated'] - assert update4_pc1 in [update1_pc1, update2_pc1, update3_pc1] assert update3_pc2 == update2_pc2 # PC 0: p1c3s, p1c4s. PC1: p2c1s - assert {c['serialNumber'] for c in pc1['components']} == {'p1c2s', 'p1c3s'} - assert all(c['parent'] == pc1_id for c in pc1['components']) + assert {c['serialNumber'] for c in pc1['components']} == {'p1c1s', 'p1c2s', 'p1c3s'} + assert all(c['parent'] == pc1['id'] for c in pc1['components']) # This last Action only # PC2 # We haven't changed PC2 - assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s',) - assert all(c['parent'] == pc2_id for c in pc2['components']) + assert tuple(c['serialNumber'] for c in pc2['components']) == ('p2c1s', 'p1c2s') + assert all(c['parent'] == pc2['id'] for c in pc2['components']) @pytest.mark.mvp @@ -454,7 +429,7 @@ def test_ram_remove(user: UserClient): dev1 = m.Device.query.filter_by(id=snap1['device']['id']).one() dev2 = m.Device.query.filter_by(id=snap2['device']['id']).one() - assert len(dev1.components) == 1 + assert len(dev1.components) == 2 assert len(dev2.components) == 3 ssd = [x for x in dev2.components if x.t == 'SolidStateDrive'][0] remove = [x for x in ssd.actions if x.t == 'Remove'][0] @@ -685,7 +660,7 @@ def test_erase_changing_hdd_between_pcs(user: UserClient): db.session.commit() assert dev2.components[2].parent == dev2 - assert dev2.components[2].actions[-1].device == dev1 + assert dev2.components[2].actions[-1].device == dev2.components[2] doc1, response = user.get( res=documents.DocumentDef.t, item='erasures/{}'.format(dev1.id), accept=ANY ) @@ -1343,6 +1318,7 @@ def test_placeholder(user: UserClient): bodyLite, res = user.post(snapshot_lite, uri="/api/inventory/") assert res.status_code == 201 dev = m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one() + dev = dev.placeholder.binding assert dev.placeholder is None assert dev.binding.phid == '12' assert len(dev.binding.device.components) == 11 @@ -1380,6 +1356,7 @@ def test_system_uuid_motherboard(user: UserClient): if c['type'] == 'Motherboard': c['serialNumber'] = 'ABee0123456720' + s['uuid'] = str(uuid.uuid4()) snap2, _ = user.post(s, res=Snapshot, status=422) txt = "We have detected that a there is a device in your inventory" assert txt in snap2['message'][0] @@ -1407,7 +1384,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() == 15 + assert m.Placeholder.query.count() == 19 assert m.Placeholder.query.count() * 2 == m.Device.query.count() for c in m.Placeholder.query.filter(): assert c.binding From 8cd7777fc6709b910df1c31a9c244e939a41ba7f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 13 Feb 2023 20:35:31 +0100 Subject: [PATCH 50/84] add model, form and template of sanitization entity --- ereuse_devicehub/forms.py | 36 +++++++++++- .../versions/4f33137586dd_sanitization.py | 57 +++++++++++++++++++ ereuse_devicehub/resources/user/models.py | 17 ++++++ .../ereuse_devicehub/user_profile.html | 32 ++++++++++- ereuse_devicehub/views.py | 27 ++++++++- 5 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 0f4cefbe..dff3278d 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -1,10 +1,10 @@ from flask import g from flask_wtf import FlaskForm from werkzeug.security import generate_password_hash -from wtforms import BooleanField, EmailField, PasswordField, validators +from wtforms import BooleanField, EmailField, PasswordField, StringField, validators from ereuse_devicehub.db import db -from ereuse_devicehub.resources.user.models import User +from ereuse_devicehub.resources.user.models import SanitizationEntity, User class LoginForm(FlaskForm): @@ -101,3 +101,35 @@ class PasswordForm(FlaskForm): if commit: db.session.commit() return + + +class SanitizationEntityForm(FlaskForm): + + logo = StringField('Logo', render_kw={'class': "form-control"}) + company_name = StringField('Company Name', render_kw={'class': "form-control"}) + location = StringField('Location', render_kw={'class': "form-control"}) + responsable_person = StringField( + 'Responsable person', render_kw={'class': "form-control"} + ) + + def validate(self, extra_validators=None): + is_valid = super().validate(extra_validators) + + if not is_valid: + return False + + return True + + def save(self, commit=True): + sanitation_data = SanitizationEntity( + logo=self.logo.data, + company_name=self.company_name.data, + location=self.location.data, + responsable_person=self.responsable_person.data, + user=g.user, + ) + db.session.add(sanitation_data) + + if commit: + db.session.commit() + return diff --git a/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py b/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py new file mode 100644 index 00000000..9489dd27 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py @@ -0,0 +1,57 @@ +"""sanitization + +Revision ID: 4f33137586dd +Revises: 93daff872771 +Create Date: 2023-02-13 18:01:00.092527 + +""" +import sqlalchemy as sa +from alembic import context, op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '4f33137586dd' +down_revision = '93daff872771' +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.create_table( + 'sanitization_entity', + sa.Column('id', sa.BigInteger(), nullable=False), + sa.Column( + 'updated', + sa.TIMESTAMP(timezone=True), + server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, + ), + sa.Column( + 'created', + sa.TIMESTAMP(timezone=True), + server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, + ), + sa.Column('company_name', sa.String(), nullable=True), + sa.Column('logo', sa.String(), nullable=True), + sa.Column('responsable_person', sa.String(), nullable=True), + sa.Column('location', sa.String(), nullable=True), + sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.ForeignKeyConstraint( + ['user_id'], + ['common.user.id'], + ), + schema=f'{get_inv()}', + ) + + +def downgrade(): + op.drop_table('sanitization_entity', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index 5eadb21d..e00c577c 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -119,3 +119,20 @@ class Session(Thing): def __str__(self) -> str: return '{0.token}'.format(self) + + +class SanitizationEntity(Thing): + id = Column(BigInteger, primary_key=True) + company_name = Column(db.String, nullable=True) + location = Column(db.String, nullable=True) + logo = Column(db.String, nullable=True) + responsable_person = Column(db.String, nullable=True) + user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id)) + user = db.relationship( + User, + backref=db.backref('sanitization_entity', lazy=True, collection_class=set), + collection_class=set, + ) + + def __str__(self) -> str: + return '{0.company_name}'.format(self) diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index fd8b8804..0a0609b7 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -34,7 +34,10 @@
@@ -65,7 +68,34 @@
+
+
+ +
+ {% for f in sanitization_form %} + {% if f == sanitization_form.csrf_token %} + {{ f }} + {% else %} +
+ +
+ {{ f }} + {% if f.errors %} +

+ {% for error in f.errors %} + {{ error }}
+ {% endfor %} +

+ {% endif %} +
+
+ {% endif %} + {% endfor %} +
+ +
+
diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index fd852da0..ef837556 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -9,7 +9,7 @@ from sqlalchemy import or_ from ereuse_devicehub import __version__, messages from ereuse_devicehub.db import db -from ereuse_devicehub.forms import LoginForm, PasswordForm +from ereuse_devicehub.forms import LoginForm, PasswordForm, SanitizationEntityForm from ereuse_devicehub.resources.action.models import Trade from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.user.models import User @@ -100,10 +100,15 @@ class UserProfileView(GenericMixin): def dispatch_request(self): self.get_context() + sanitization_form = SanitizationEntityForm() + if g.user.sanitization_entity: + sanitization = list(g.user.sanitization_entity)[0] + sanitization_form = SanitizationEntityForm(initial=sanitization) self.context.update( { 'current_user': current_user, 'password_form': PasswordForm(), + 'sanitization_form': sanitization_form, } ) @@ -127,7 +132,27 @@ class UserPasswordView(View): return flask.redirect(flask.url_for('core.user-profile')) +class SanitizationEntityView(View): + methods = ['POST'] + decorators = [login_required] + + def dispatch_request(self): + form = SanitizationEntityForm() + db.session.commit() + if form.validate_on_submit(): + form.save(commit=False) + messages.success('Sanitization datas updated successfully!') + else: + messages.error('Error modifying Sanitization datas!') + + db.session.commit() + return flask.redirect(flask.url_for('core.user-profile')) + + core.add_url_rule('/login/', view_func=LoginView.as_view('login')) core.add_url_rule('/logout/', view_func=LogoutView.as_view('logout')) core.add_url_rule('/profile/', view_func=UserProfileView.as_view('user-profile')) core.add_url_rule('/set_password/', view_func=UserPasswordView.as_view('set-password')) +core.add_url_rule( + '/set_sanitization/', view_func=SanitizationEntityView.as_view('set-sanitization') +) From 8207ca9ab2cd256fb56b0f147cad8a9dc9ad5d47 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 14 Feb 2023 12:15:21 +0100 Subject: [PATCH 51/84] save datas and initialized form --- ereuse_devicehub/forms.py | 28 +++++++++++++++++-- .../versions/4f33137586dd_sanitization.py | 4 ++- ereuse_devicehub/resources/user/models.py | 4 ++- .../ereuse_devicehub/user_profile.html | 2 +- ereuse_devicehub/views.py | 2 +- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index dff3278d..087fd165 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -1,7 +1,15 @@ +from boltons.urlutils import URL from flask import g from flask_wtf import FlaskForm from werkzeug.security import generate_password_hash -from wtforms import BooleanField, EmailField, PasswordField, StringField, validators +from wtforms import ( + BooleanField, + EmailField, + PasswordField, + StringField, + URLField, + validators, +) from ereuse_devicehub.db import db from ereuse_devicehub.resources.user.models import SanitizationEntity, User @@ -105,12 +113,25 @@ class PasswordForm(FlaskForm): class SanitizationEntityForm(FlaskForm): - logo = StringField('Logo', render_kw={'class': "form-control"}) + logo = URLField( + 'Logo', + [validators.Optional(), validators.URL()], + render_kw={'class': "form-control"}, + ) company_name = StringField('Company Name', render_kw={'class': "form-control"}) location = StringField('Location', render_kw={'class': "form-control"}) responsable_person = StringField( 'Responsable person', render_kw={'class': "form-control"} ) + supervisor_person = StringField( + 'Supervisor person', render_kw={'class': "form-control"} + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # import pdb; pdb.set_trace() + if isinstance(self.logo.data, URL): + self.logo.data = self.logo.data.to_text() def validate(self, extra_validators=None): is_valid = super().validate(extra_validators) @@ -122,10 +143,11 @@ class SanitizationEntityForm(FlaskForm): def save(self, commit=True): sanitation_data = SanitizationEntity( - logo=self.logo.data, + logo=URL(self.logo.data), company_name=self.company_name.data, location=self.location.data, responsable_person=self.responsable_person.data, + supervisor_person=self.supervisor_person.data, user=g.user, ) db.session.add(sanitation_data) diff --git a/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py b/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py index 9489dd27..fa5e5fd3 100644 --- a/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py +++ b/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py @@ -6,6 +6,7 @@ Create Date: 2023-02-13 18:01:00.092527 """ import sqlalchemy as sa +import teal from alembic import context, op from sqlalchemy.dialects import postgresql @@ -40,8 +41,9 @@ def upgrade(): nullable=False, ), sa.Column('company_name', sa.String(), nullable=True), - sa.Column('logo', sa.String(), nullable=True), + sa.Column('logo', teal.db.URL(), nullable=True), sa.Column('responsable_person', sa.String(), nullable=True), + sa.Column('supervisor_person', sa.String(), nullable=True), sa.Column('location', sa.String(), nullable=True), sa.Column('user_id', postgresql.UUID(as_uuid=True), nullable=False), sa.PrimaryKeyConstraint('id'), diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index e00c577c..14e1c7ad 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -5,7 +5,7 @@ from flask_login import UserMixin from sqlalchemy import BigInteger, Boolean, Column, Sequence from sqlalchemy.dialects.postgresql import UUID from sqlalchemy_utils import EmailType, PasswordType -from teal.db import IntEnum +from teal.db import URL, IntEnum from ereuse_devicehub.db import db from ereuse_devicehub.resources.enums import SessionType @@ -126,7 +126,9 @@ class SanitizationEntity(Thing): company_name = Column(db.String, nullable=True) location = Column(db.String, nullable=True) logo = Column(db.String, nullable=True) + logo = Column(URL(), nullable=True) responsable_person = Column(db.String, nullable=True) + supervisor_person = Column(db.String, nullable=True) user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id)) user = db.relationship( User, diff --git a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html index 0a0609b7..462fc6ec 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/user_profile.html @@ -72,7 +72,7 @@
-
+ {% for f in sanitization_form %} {% if f == sanitization_form.csrf_token %} {{ f }} diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index ef837556..f2cd4bc1 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -103,7 +103,7 @@ class UserProfileView(GenericMixin): sanitization_form = SanitizationEntityForm() if g.user.sanitization_entity: sanitization = list(g.user.sanitization_entity)[0] - sanitization_form = SanitizationEntityForm(initial=sanitization) + sanitization_form = SanitizationEntityForm(obj=sanitization) self.context.update( { 'current_user': current_user, From 12d64aefdc0c5e5d80cdce2f6f42ffd355997517 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 14 Feb 2023 20:03:33 +0100 Subject: [PATCH 52/84] save customer datas in transfers --- ereuse_devicehub/forms.py | 1 - ereuse_devicehub/inventory/forms.py | 55 ++++++++++++++++++- ereuse_devicehub/inventory/models.py | 22 +++++++- ereuse_devicehub/inventory/views.py | 30 ++++++++++ .../versions/4f33137586dd_sanitization.py | 26 +++++++++ .../templates/inventory/device_list.html | 36 ++++++++++++ tests/test_basic.py | 2 + 7 files changed, 169 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 087fd165..895160c5 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -129,7 +129,6 @@ class SanitizationEntityForm(FlaskForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - # import pdb; pdb.set_trace() if isinstance(self.logo.data, URL): self.logo.data = self.logo.data.to_text() diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 451684e1..fc475f6e 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -30,7 +30,12 @@ from wtforms import ( from wtforms.fields import FormField from ereuse_devicehub.db import db -from ereuse_devicehub.inventory.models import DeliveryNote, ReceiverNote, Transfer +from ereuse_devicehub.inventory.models import ( + DeliveryNote, + ReceiverNote, + Transfer, + TransferCustomerDetails, +) from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog from ereuse_devicehub.parser.parser import ParseSnapshotLsHw from ereuse_devicehub.parser.schemas import Snapshot_lite @@ -1518,6 +1523,54 @@ class NotesForm(FlaskForm): return self._obj +class CustomerDetailsForm(FlaskForm): + company_name = StringField( + 'Company name', + [validators.Optional()], + render_kw={'class': "form-control"}, + description="Name of the company", + ) + location = StringField( + 'Location', + [validators.Optional()], + render_kw={'class': "form-control"}, + description="""Location where is the company""", + ) + logo = URLField( + 'Logo', + [validators.Optional()], + render_kw={'class': "form-control"}, + description="Url where is the logo", + ) + + def __init__(self, *args, **kwargs): + lot_id = kwargs.pop('lot_id', None) + self._tmp_lot = Lot.query.filter(Lot.id == lot_id).one() + self._obj = self._tmp_lot.transfer.customer_details + if self._obj: + kwargs['obj'] = self._obj + if not self._obj: + self._obj = TransferCustomerDetails(transfer_id=self._tmp_lot.transfer.id) + + super().__init__(*args, **kwargs) + if isinstance(self.logo.data, URL): + self.logo.data = URL(self.logo.data).to_text() + + def validate(self, extra_validators=None): + is_valid = super().validate(extra_validators) + return is_valid + + def save(self, commit=True): + self.populate_obj(self._obj) + self._obj.logo = URL(self._obj.logo) + db.session.add(self._obj) + + if commit: + db.session.commit() + + return self._obj + + class UploadPlaceholderForm(FlaskForm): type = StringField('Type', [validators.DataRequired()]) placeholder_file = FileField( diff --git a/ereuse_devicehub/inventory/models.py b/ereuse_devicehub/inventory/models.py index 45d25157..f8b4f977 100644 --- a/ereuse_devicehub/inventory/models.py +++ b/ereuse_devicehub/inventory/models.py @@ -5,7 +5,7 @@ from flask import g from sqlalchemy import Column, Integer from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import backref, relationship -from teal.db import CASCADE_OWN +from teal.db import CASCADE_OWN, URL from ereuse_devicehub.db import db from ereuse_devicehub.resources.models import Thing @@ -90,3 +90,23 @@ class ReceiverNote(Thing): backref=backref('receiver_note', lazy=True, uselist=False, cascade=CASCADE_OWN), primaryjoin='ReceiverNote.transfer_id == Transfer.id', ) + + +class TransferCustomerDetails(Thing): + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4) + company_name = Column(CIText(), nullable=True) + location = Column(CIText(), nullable=True) + logo = Column(URL(), nullable=True) + + transfer_id = db.Column( + UUID(as_uuid=True), + db.ForeignKey('transfer.id'), + nullable=False, + ) + transfer = relationship( + 'Transfer', + backref=backref( + 'customer_details', lazy=True, uselist=False, cascade=CASCADE_OWN + ), + primaryjoin='TransferCustomerDetails.transfer_id == Transfer.id', + ) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 15988ddb..1f973841 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -20,6 +20,7 @@ from ereuse_devicehub.inventory.forms import ( AdvancedSearchForm, AllocateForm, BindingForm, + CustomerDetailsForm, DataWipeForm, EditTransferForm, FilterForm, @@ -79,6 +80,7 @@ class DeviceListMixin(GenericMixin): form_transfer = '' form_delivery = '' form_receiver = '' + form_customer_details = '' if lot_id: lot = lots.filter(Lot.id == lot_id).one() @@ -86,6 +88,7 @@ class DeviceListMixin(GenericMixin): form_transfer = EditTransferForm(lot_id=lot.id) form_delivery = NotesForm(lot_id=lot.id, type='Delivery') form_receiver = NotesForm(lot_id=lot.id, type='Receiver') + form_customer_details = CustomerDetailsForm(lot_id=lot.id) form_new_action = NewActionForm(lot=lot_id) self.context.update( @@ -97,6 +100,7 @@ class DeviceListMixin(GenericMixin): 'form_transfer': form_transfer, 'form_delivery': form_delivery, 'form_receiver': form_receiver, + 'form_customer_details': form_customer_details, 'form_filter': form_filter, 'form_print_labels': PrintLabelsForm(), 'lot': lot, @@ -1257,6 +1261,28 @@ class SnapshotDetailView(GenericMixin): ) +class CustomerDetailsView(GenericMixin): + methods = ['POST'] + form_class = CustomerDetailsForm + + def dispatch_request(self, lot_id): + self.get_context() + form = self.form_class(request.form, lot_id=lot_id) + next_url = url_for('inventory.lotdevicelist', lot_id=lot_id) + + if form.validate_on_submit(): + form.save() + messages.success('Customer details updated successfully!') + return flask.redirect(next_url) + + messages.error('Customer details updated error!') + for k, v in form.errors.items(): + value = ';'.join(v) + key = form[k].label.text + messages.error('Error {key}: {value}!'.format(key=key, value=value)) + return flask.redirect(next_url) + + class DeliveryNoteView(GenericMixin): methods = ['POST'] form_class = NotesForm @@ -1448,6 +1474,10 @@ devices.add_url_rule( '/lot//transfer/', view_func=EditTransferView.as_view('edit_transfer'), ) +devices.add_url_rule( + '/lot//customerdetails/', + view_func=CustomerDetailsView.as_view('customer_details'), +) devices.add_url_rule( '/lot//deliverynote/', view_func=DeliveryNoteView.as_view('delivery_note'), diff --git a/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py b/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py index fa5e5fd3..51fe4d61 100644 --- a/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py +++ b/ereuse_devicehub/migrations/versions/4f33137586dd_sanitization.py @@ -5,6 +5,7 @@ Revises: 93daff872771 Create Date: 2023-02-13 18:01:00.092527 """ +import citext import sqlalchemy as sa import teal from alembic import context, op @@ -54,6 +55,31 @@ def upgrade(): schema=f'{get_inv()}', ) + op.create_table( + 'transfer_customer_details', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column( + 'updated', + sa.TIMESTAMP(timezone=True), + server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, + ), + sa.Column( + 'created', + sa.TIMESTAMP(timezone=True), + server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, + ), + sa.Column('company_name', citext.CIText(), nullable=True), + sa.Column('logo', teal.db.URL(), nullable=True), + sa.Column('location', citext.CIText(), nullable=True), + sa.Column('transfer_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.ForeignKeyConstraint(['transfer_id'], [f'{get_inv()}.transfer.id']), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}', + ) + def downgrade(): op.drop_table('sanitization_entity', schema=f'{get_inv()}') + op.drop_table('transfer_customer_details', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index 78c3e39d..f89c93f6 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -93,6 +93,11 @@ Receiver Note + {% endif %} {% endif %} @@ -656,6 +661,37 @@ {% endif %}
+ +
+
Customer Details
+
+ {{ form_customer_details.csrf_token }} + + {% for field in form_customer_details %} + {% if field != form_customer_details.csrf_token %} +
+ {% if field != form_customer_details.type %} + {{ field.label(class_="form-label") }} + {{ field }} + {{ field.description }} + {% if field.errors %} +

+ {% for error in field.errors %} + {{ error }}
+ {% endfor %} +

+ {% endif %} + {% endif %} +
+ {% endif %} + {% endfor %} + +
+ Cancel + +
+
+
{% endif %} diff --git a/tests/test_basic.py b/tests/test_basic.py index 7322e77b..e9927a0e 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -71,6 +71,7 @@ def test_api_docs(client: Client): '/inventory/lot/{lot_id}/transfer/', '/inventory/lot/transfer/{type_id}/', '/inventory/lot/{lot_id}/upload-snapshot/', + '/inventory/lot/{lot_id}/customerdetails/', '/inventory/snapshots/{snapshot_uuid}/', '/inventory/snapshots/', '/inventory/tag/devices/{dhid}/add/', @@ -98,6 +99,7 @@ def test_api_docs(client: Client): '/metrics/', '/profile/', '/set_password/', + '/set_sanitization/', '/tags/', '/tags/{tag_id}/device/{device_id}', '/trade-documents/', From 680a7b89e24f078f073dbe6db673dc9ad8cfc16a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 15 Feb 2023 18:30:45 +0100 Subject: [PATCH 53/84] change base of template --- .../templates/inventory/erasure.html | 501 +++++++++++++++--- 1 file changed, 426 insertions(+), 75 deletions(-) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 57fa5139..0ae4ca27 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -1,80 +1,431 @@ -{% extends "documents/layout.html" %} -{% block body %} -
-

Summary

- - - - - - - - - - - {% for erasure in erasures %} - - - - - - - {% endfor %} - -
S/N Data StorageType of erasureResultDate
- {{ erasure.device.serial_number.upper() }} - - {{ erasure.type }} - - {{ erasure.severity }} - - {{ erasure.date_str }} -
-
-
-

Details

- {% for erasure in erasures %} -
-

{{ erasure.device.__format__('t') }}

-
-
Data storage:
-
{{ erasure.device.__format__('ts') }}
+ + +Data Sanitization Certificate + + + + + + + +
+
+
+
+

2022-12-26 16:51:32 (+0100), USODY DRIVE ERASURE 2022

+
-
-

Glossary

-
-
Erase Basic
-
- A software-based fast non-100%-secured way of erasing data storage, - using shred. -
-
Erase Sectors
-
- A secured-way of erasing data storages, checking sector-by-sector - the erasure, using badblocks. -
-
+
+ +
+
+
-
- Click here to download the PDF. +
+
- + +
+
+

Data Sanitization Certificate

-{% endblock %} +
+ +
+
+ Entity Information +
+
+ Name: +
+
+ ACME +
+
+
+
+ Location: +
+
+ Paseo de Gracia, 2, 08007 Barcelona, España +
+
+
+
+ + +
+
+ Responsible Sanitization Entity +
+
+ Name: +
+
+ Your company +
+
+
+
+ Responsible Person +
+
+ John Data +
+
+
+
+ Location: +
+
+ Madrid, Gran Via 8, 28040 Madrid, España +
+
+
+
+ + +
+
+ Summary +
+
+ N° of devices: +
+
+ 16 +
+
+
+
+ N° of data storage unit(s): +
+
+ 16 +
+
+
+
+ Sanitization result: +
+
+ Failed +
+
+
+
+ + +
+
+ Report Details +
+
+ Report UUID: +
+
+ 8bcef704-ba04-4320-8056-c8a5c401dbe3 +
+
+
+
+ Report Date: +
+
+ 2022-12-26 11:26:24 +
+
+
+
+ Software Version: +
+
+ Usody Drive Erasure 2022.03.0 +
+
+
+
+ + +
+
+

+ I hereby declare that the data erasure process has been carried + out in accordance with the instructions received. +

+
+
+ + +
+
+ Data Responsable +
+
+ Data Supervisor +
+
+
+ +

+ +
+
+
+

Devices Summary

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SN DeviceSN StorageTag CustomerMethodResultDate
S1...S2...ACME1BasicFailed2022-12-20 11:26:24
S1...1927E18B43F4ACME1BasicFailed2022-12-20 11:26:24
+
+
+
+

+
+
+
+

1927E18B43F4

+
+
+
+
+ Result +
+
+ Failed +
+
+
+
+ Storage Drive +
+
+
+
+
+
+ Manufacturer: +
+
+ Crucial +
+
+
+
+ Model: +
+
+ CT240BX500ssd1 +
+
+
+
+ SN: +
+
+ 1927E18B43F4 +
+
+
+
+ Storage Medium: +
+
+ SSD +
+
+
+
+ Connector: +
+
+ SAS +
+
+
+
+ Size: +
+
+ 240GB +
+
+
+
+
+
+ Method +
+
+
+
+
+
+ Name: +
+
+ Baseline +
+
+
+
+ Standard: +
+
+ NIST SP-800-88 +
+
+
+
+ Removal process: +
+
+ Overwriting +
+
+
+
+ Program: +
+
+ Shred +
+
+
+
+ Verification status: +
+
+ No +
+
+
+
+ Detected bad sectors: +
+
+ - +
+
+
+
+ Hidden areas: +
+
+ No +
+
+
+
+ Warnings: +
+
+ No +
+
+
+
+ Overwriting steps +
+
+ 1 (0) +
+
+
+
+ Step: +
+
+ 1 +
+
+
+
+ Date Init: +
+
+ 2022-12-20 11:00:24 +
+
+
+
+ Date End: +
+
+ 2022-12-20 11:26:24 +
+
+
+
+ Duration: +
+
+ 0:26:00 +
+
+
+
+
+ + \ No newline at end of file From 80013bcc901a71d7198466657445d36c339d954e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 17 Feb 2023 10:45:55 +0100 Subject: [PATCH 54/84] . --- .../templates/inventory/erasure.html | 293 ++++++++++-------- 1 file changed, 165 insertions(+), 128 deletions(-) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 0ae4ca27..5999edf6 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -1,25 +1,37 @@ + Data Sanitization Certificate - - - + + -
-
-
-
-

2022-12-26 16:51:32 (+0100), USODY DRIVE ERASURE 2022

-
+ - +
-
+
-
+
+
+

Data Sanitization Certificate

- +
-
+
Entity Information -
-
- Name: -
-
- ACME -
-
-
-
- Location: -
-
- Paseo de Gracia, 2, 08007 Barcelona, España -
-
+
+
+ + + + + + + + + + +
+ Name: + + ACME +
+ Location: + + Paseo de Gracia, 2, 08007 Barcelona, España +
- -
-
+
+
Responsible Sanitization Entity -
-
- Name: -
-
- Your company -
-
-
-
- Responsible Person -
-
- John Data -
-
-
-
- Location: -
-
- Madrid, Gran Via 8, 28040 Madrid, España -
-
+
+
+ + + + + + + + + + + + + + +
+ Name: + + Your company +
+ Responsible Person + + John Data +
+ Location: + + Madrid, Gran Via 8, 28040 Madrid, España +
- -
-
+
+
Summary -
-
- N° of devices: -
-
- 16 -
-
-
-
- N° of data storage unit(s): -
-
- 16 -
-
-
-
- Sanitization result: -
-
- Failed -
-
+
+
+ + + + + + + + + + + + + + +
+ N° of devices: + + 16 +
+ N° of data storage unit(s): + + 16 +
+ Sanitization result: + + Failed +
- -
-
+
+
Report Details -
-
- Report UUID: -
-
- 8bcef704-ba04-4320-8056-c8a5c401dbe3 -
-
-
-
- Report Date: -
-
- 2022-12-26 11:26:24 -
-
-
-
- Software Version: -
-
- Usody Drive Erasure 2022.03.0 -
-
+
+
+ + + + + + + + + + + + + + +
+ Report UUID: + + 8bcef704-ba04-4320-8056-c8a5c401dbe3 +
+ Report Date: + + 2022-12-26 11:26:24 +
+ Software Version: + + Usody Drive Erasure 2022.03.0 +
- -
+

I hereby declare that the data erasure process has been carried @@ -187,20 +220,24 @@

- -
-
- Data Responsable -
-
- Data Supervisor +
+
+ + + + + + +
+ Data Responsable + + Data Supervisor +
-
-

+

-

Devices Summary

From 5bdcf4da7f79996d6f52fbd4770a8fd5f35c626c Mon Sep 17 00:00:00 2001 From: nad Date: Thu, 23 Feb 2023 12:52:27 +0100 Subject: [PATCH 55/84] disable WB_BENCHMARK in wb settings --- ereuse_devicehub/templates/workbench/wbSettings.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/templates/workbench/wbSettings.ini b/ereuse_devicehub/templates/workbench/wbSettings.ini index 213240c1..53bbc34d 100644 --- a/ereuse_devicehub/templates/workbench/wbSettings.ini +++ b/ereuse_devicehub/templates/workbench/wbSettings.ini @@ -7,7 +7,7 @@ DH_HOST = {{ api_host }} DH_DATABASE = {{ schema }} DEVICEHUB_URL = https://${DB_HOST}/${DB_DATABASE}/ -WB_BENCHMARK = True +WB_BENCHMARK = False WB_STRESS_TEST = 0 WB_SMART_TEST = short @@ -21,7 +21,7 @@ DH_HOST = {{ api_host }} DH_DATABASE = {{ schema }} DEVICEHUB_URL = https://${DB_HOST}/${DB_DATABASE}/ -WB_BENCHMARK = True +WB_BENCHMARK = False WB_STRESS_TEST = 0 WB_SMART_TEST = short From c24460009e30f1907d17649d14ebe4bccd370101 Mon Sep 17 00:00:00 2001 From: nad Date: Thu, 23 Feb 2023 12:52:57 +0100 Subject: [PATCH 56/84] update wb iso to 14.2.0 --- ereuse_devicehub/workbench/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/workbench/__init__.py b/ereuse_devicehub/workbench/__init__.py index 11e71c7c..ea44bae3 100644 --- a/ereuse_devicehub/workbench/__init__.py +++ b/ereuse_devicehub/workbench/__init__.py @@ -8,7 +8,7 @@ isos = { 'url': 'https://releases.usody.com/2022/', }, "erease": { - 'iso': "USODY_14.1.0.iso", + 'iso': "USODY_14.2.0.iso", 'url': 'https://releases.usody.com/v14/', }, } From 26f8d191fb68e4a2f595cd0a2bcec56cc8a282bf Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 23 Feb 2023 17:07:00 +0100 Subject: [PATCH 57/84] . --- .../templates/inventory/erasure.html | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 5999edf6..faf4bb7e 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -34,8 +34,13 @@ } header { - position: running(header); + position: running(header); /*height: 100px;*/ + font-size: 12px; + /* color: #000; */ + font-family: Arial; + width: 100%; + /* position: relative;*/ } footer { @@ -150,7 +155,7 @@ - N° of devices: + N° of computers: 16 @@ -245,34 +250,32 @@
- - +
+ - - - - - - - - - - - - - - - - - + {% for erasure in erasures %} + + + + + + {% endfor %}
SN Device SN StorageTag Customer Method Result Date
S1...S2...ACME1BasicFailed2022-12-20 11:26:24
S1...1927E18B43F4ACME1BasicFailed2022-12-20 11:26:24
+ {{ erasure.device.serial_number.upper() }} + + {{ erasure.type }} + + {{ erasure.severity }} + + {{ erasure.date_str }} +
From 26ed0f3577ef232a7582d18eca2ff99003824181 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 24 Feb 2023 17:01:38 +0100 Subject: [PATCH 58/84] details device --- .../templates/inventory/erasure.html | 227 +++--------------- 1 file changed, 39 insertions(+), 188 deletions(-) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index faf4bb7e..67bfa1ad 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -12,6 +12,7 @@ @page { size: A4 portrait; /* can use also 'landscape' for orientation */ margin: 1.0cm 1.5cm 3.5cm 1.5cm; + font-family: "Source Sans Pro", Calibri, Candra, Sans serif; @top { content: element(header); @@ -58,6 +59,10 @@ img {max-height: 150px; width: auto;} .company-logo {float: left;} .customer-logo {float: right;} + .page-break:not(section:first-of-type) { + page-break-before: always + } +} @@ -241,9 +246,7 @@
-

- -
+

Devices Summary

@@ -281,191 +284,39 @@
-

-
-
-
-

1927E18B43F4

-
-
-
-
- Result -
-
- Failed -
-
-
-
- Storage Drive -
-
-
-
-
-
- Manufacturer: -
-
- Crucial -
-
-
-
- Model: -
-
- CT240BX500ssd1 -
-
-
-
- SN: -
-
- 1927E18B43F4 -
-
-
-
- Storage Medium: -
-
- SSD -
-
-
-
- Connector: -
-
- SAS -
-
-
-
- Size: -
-
- 240GB -
-
-
-
-
-
- Method -
-
-
-
-
-
- Name: -
-
- Baseline -
-
-
-
- Standard: -
-
- NIST SP-800-88 -
-
-
-
- Removal process: -
-
- Overwriting -
-
-
-
- Program: -
-
- Shred -
-
-
-
- Verification status: -
-
- No -
-
-
-
- Detected bad sectors: -
-
- - -
-
-
-
- Hidden areas: -
-
- No -
-
-
-
- Warnings: -
-
- No -
-
-
-
- Overwriting steps -
-
- 1 (0) -
-
-
-
- Step: -
-
- 1 -
-
-
-
- Date Init: -
-
- 2022-12-20 11:00:24 -
-
-
-
- Date End: -
-
- 2022-12-20 11:26:24 -
-
-
-
- Duration: -
-
- 0:26:00 -
-
-
-
+{% for erasure in erasures %} +
+

{{ erasure.device.__format__('t') }}

+
+
Data storage:
+
{{ erasure.device.__format__('ts') }}
+ +
Computer where was erase:
+
Title: {{ erasure.parent.__format__('ts') }}
+
DevicehubID: {{ erasure.parent.dhid }}
+
Hid: {{ erasure.parent.hid }}
+
Tags: {{ erasure.parent.tags }}
+ +
Computer where it resides:
+
Title: {{ erasure.device.parent.__format__('ts') }}
+
DevicehubID: {{ erasure.device.parent.dhid }}
+
Hid: {{ erasure.device.parent.hid }}
+
Tags: {{ erasure.device.parent.tags }}
+ +
Erasure:
+
{{ erasure.__format__('ts') }}
+ {% if erasure.steps %} +
Erasure steps:
+
+
    + {% for step in erasure.steps %} +
  1. {{ step.__format__('') }}
  2. + {% endfor %} +
+
+ {% endif %} +
+{% endfor %} \ No newline at end of file From e900f5f298fd01d6db3e28f448e7a8b35d5fd3e2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 28 Feb 2023 16:43:28 +0100 Subject: [PATCH 59/84] erasure on server --- ereuse_devicehub/inventory/views.py | 59 +++++++- ereuse_devicehub/resources/action/models.py | 24 ++++ ereuse_devicehub/resources/enums.py | 6 + .../templates/inventory/erasure.html | 134 ++++++++++++++---- 4 files changed, 192 insertions(+), 31 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 1f973841..26a4d6e1 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1,7 +1,9 @@ import copy import csv +import datetime import logging import os +import uuid from io import StringIO from pathlib import Path @@ -1043,7 +1045,7 @@ class ExportsView(View): return self.response_csv(data, "Erasures.csv") - def build_erasure_certificate(self): + def get_datastorages(self): erasures = [] for device in self.find_devices(): if device.placeholder and device.placeholder.binding: @@ -1054,11 +1056,66 @@ class ExportsView(View): elif isinstance(device, DataStorage): if device.privacy: erasures.append(device.privacy) + return erasures + + def get_custum_details(self): + my_data = None + customer_details = None + if hasattr(g.user, 'sanitization_entity'): + if g.user.sanitization_entity: + my_data = list(g.user.sanitization_entity)[0] + + if len(request.referrer.split('/lot/')) > 1: + try: + lot_id = request.referrer.split('/lot/')[-1].split('/')[0] + lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first() + customer_details = lot.transfer.customer_details + except Exception: + pass + return my_data, customer_details + + def get_server_erasure_hosts(self, erasures): + erasures_host = [] + erasures_on_server = [] + for erase in erasures: + try: + if erase.parent.binding.kangaroo: + erasures_host.append(erase.parent) + erasures_on_server.append(erase) + except Exception: + pass + return erasures_host, erasures_on_server + + def build_erasure_certificate(self): + erasures = self.get_datastorages() + software = 'USODY DRIVE ERASURE' + if erasures and erasures[0].snapshot: + software += ' {}'.format( + erasures[0].snapshot.version, + ) + + my_data, customer_details = self.get_custum_details() + + a, b = self.get_server_erasure_hosts(erasures) + erasures_host, erasures_on_server = a, b + + result = 'Success' + if "Failed" in [e.severity.get_public_name() for e in erasures]: + result = 'Failed' params = { 'title': 'Erasure Certificate', 'erasures': tuple(erasures), 'url_pdf': '', + 'date_report': '{:%c}'.format(datetime.datetime.now()), + 'uuid_report': '{}'.format(uuid.uuid4()), + 'software': software, + 'my_data': my_data, + 'n_computers': len(set([x.parent for x in erasures])), + 'result': result, + 'customer_details': customer_details, + 'erasure_hosts': erasures_host, + 'erasures_normal': list(set(erasures) - set(erasures_on_server)), } return flask.render_template('inventory/erasure.html', **params) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 1f373962..f1bbb5dd 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -481,6 +481,9 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): return self.snapshot.device.phid() return '' + def get_public_name(self): + return "Basic" + def __str__(self) -> str: return '{} on {}.'.format(self.severity, self.date_str) @@ -510,12 +513,33 @@ class EraseSectors(EraseBasic): method = 'Badblocks' + def get_public_name(self): + # import pdb; pdb.set_trace() + steps_random = 0 + steps_zeros = 0 + for s in self.steps: + if s.type == 'StepRandom': + steps_random += 1 + if s.type == 'StepZero': + steps_zeros += 1 + if steps_zeros < 1: + return "Basic" + if 0 < steps_random < 3: + return "Baseline" + if steps_random > 2: + return "Enhanced" + + return "Basic" + class ErasePhysical(EraseBasic): """The act of physically destroying a data storage unit.""" method = Column(DBEnum(PhysicalErasureMethod)) + def get_public_name(self): + return "Physical" + class Step(db.Model): erasure_id = Column( diff --git a/ereuse_devicehub/resources/enums.py b/ereuse_devicehub/resources/enums.py index bbbcdc10..2d527802 100644 --- a/ereuse_devicehub/resources/enums.py +++ b/ereuse_devicehub/resources/enums.py @@ -334,6 +334,12 @@ class Severity(IntEnum): def __format__(self, format_spec): return str(self) + def get_public_name(self): + if self.value == 3: + return "Failed" + + return "Success" + class PhysicalErasureMethod(Enum): """Methods of physically erasing the data-storage, usually diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 67bfa1ad..2ccd2ad1 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -68,16 +68,16 @@
- +
- +
@@ -101,7 +101,7 @@ Name: - ACME + {{ ustomer_details and customer_details.company_name or ''}} @@ -109,7 +109,7 @@ Location: - Paseo de Gracia, 2, 08007 Barcelona, España + {{ customer_details and customer_details.location or '' }} @@ -128,7 +128,7 @@ Name: - Your company + {{ my_data and my_data.company_name or '' }} @@ -136,7 +136,7 @@ Responsible Person - John Data + {{ my_data and my_data.responsable_person or '' }} @@ -144,7 +144,7 @@ Location: - Madrid, Gran Via 8, 28040 Madrid, España + {{ my_data and my_data.location or '' }} @@ -158,20 +158,35 @@
+ {% if erasure_hosts %} + {% for e in erasure_hosts %} + + + + + {% endfor %} + {% else %} + {% endif %} @@ -179,7 +194,7 @@ Sanitization result:
+ N° of sanitization server ({{ loop.index }}/{{ erasure_hosts|length }}): + + {% if e.serial_number %} + {{ e.serial_number.upper() }} + {% endif %} +
N° of computers: - 16 + {{ n_computers }}
N° of data storage unit(s): - 16 + {{ erasures | length }}
- Failed + {{ result }}
@@ -198,7 +213,7 @@ Report UUID: - 8bcef704-ba04-4320-8056-c8a5c401dbe3 + {{ uuid_report }} @@ -206,7 +221,7 @@ Report Date: - 2022-12-26 11:26:24 + {{ date_report }} @@ -214,7 +229,7 @@ Software Version: - Usody Drive Erasure 2022.03.0 + {{ software }} @@ -237,15 +252,67 @@ Data Responsable +
+ {{ my_data and my_data.responsable_person or '' }} Data Supervisor +
+ {{ my_data and my_data.supervisor_person or '' }}
+{% if erasures %} + {% if erasure_hosts %} + {% for server in erasure_hosts %} +
+
+

Server Summary

+
+
+

SN Server {{ server.serial_number and server.serial_number.upper() }}

+
+
+
+
+ + + + + + + + + + + {% for erasure in erasures %} + {% if erasure.parent == server %} + + + + + + + {% endif %} + {% endfor %} + +
SN StorageMethodResultDate
+ {{ erasure.device.serial_number.upper() }} + + {{ erasure.get_public_name() }} + + {{ erasure.severity.get_public_name() }} + + {{ erasure.date_str }} +
+
+
+ {% endfor %} + {% endif %} + {% if erasures_normal %}

Devices Summary

@@ -256,23 +323,23 @@ - - - - + + + + - {% for erasure in erasures %} + {% for erasure in erasures_normal %}
SN StorageMethodResultDateSN StorageMethodResultDate
{{ erasure.device.serial_number.upper() }} - {{ erasure.type }} + {{ erasure.get_public_name() }} - {{ erasure.severity }} + {{ erasure.severity.get_public_name() }} {{ erasure.date_str }} @@ -283,10 +350,11 @@
+ {% endif %}
{% for erasure in erasures %}
-

{{ erasure.device.__format__('t') }}

+

{{ erasure.device.serial_number.upper() }}

Data storage:
{{ erasure.device.__format__('ts') }}
@@ -308,15 +376,21 @@ {% if erasure.steps %}
Erasure steps:
-
    - {% for step in erasure.steps %} -
  1. {{ step.__format__('') }}
  2. - {% endfor %} -
-
- {% endif %} -
+
    + {% for step in erasure.steps %} +
  1. {{ step.__format__('') }}
  2. + {% endfor %} +
+ + {% endif %} +
{% endfor %} +{% endif %} + \ No newline at end of file From 7f6acf2db87c132ccfa0b5653559a9793702b05c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 28 Feb 2023 16:56:00 +0100 Subject: [PATCH 60/84] drop simple-datatables from local --- .../static/css/simple-datatables.css | 182 ------------------ .../static/js/simple-datatables-5.0.3.js | 132 ------------- .../templates/ereuse_devicehub/base.html | 6 +- 3 files changed, 4 insertions(+), 316 deletions(-) delete mode 100644 ereuse_devicehub/static/css/simple-datatables.css delete mode 100644 ereuse_devicehub/static/js/simple-datatables-5.0.3.js diff --git a/ereuse_devicehub/static/css/simple-datatables.css b/ereuse_devicehub/static/css/simple-datatables.css deleted file mode 100644 index ad225bc3..00000000 --- a/ereuse_devicehub/static/css/simple-datatables.css +++ /dev/null @@ -1,182 +0,0 @@ -.dataTable-wrapper.no-header .dataTable-container { - border-top: 1px solid #d9d9d9; -} - -.dataTable-wrapper.no-footer .dataTable-container { - border-bottom: 1px solid #d9d9d9; -} - -.dataTable-top, -.dataTable-bottom { - padding: 8px 10px; -} - -.dataTable-top > nav:first-child, -.dataTable-top > div:first-child, -.dataTable-bottom > nav:first-child, -.dataTable-bottom > div:first-child { - float: left; -} - -.dataTable-top > nav:last-child, -.dataTable-top > div:last-child, -.dataTable-bottom > nav:last-child, -.dataTable-bottom > div:last-child { - float: right; -} - -.dataTable-selector { - padding: 6px; -} - -.dataTable-input { - padding: 6px 12px; -} - -.dataTable-info { - margin: 7px 0; -} - -/* PAGER */ -.dataTable-pagination ul { - margin: 0; - padding-left: 0; -} - -.dataTable-pagination li { - list-style: none; - float: left; -} - -.dataTable-pagination a { - border: 1px solid transparent; - float: left; - margin-left: 2px; - padding: 6px 12px; - position: relative; - text-decoration: none; - color: #333; -} - -.dataTable-pagination a:hover { - background-color: #d9d9d9; -} - -.dataTable-pagination .active a, -.dataTable-pagination .active a:focus, -.dataTable-pagination .active a:hover { - background-color: #d9d9d9; - cursor: default; -} - -.dataTable-pagination .ellipsis a, -.dataTable-pagination .disabled a, -.dataTable-pagination .disabled a:focus, -.dataTable-pagination .disabled a:hover { - cursor: not-allowed; -} - -.dataTable-pagination .disabled a, -.dataTable-pagination .disabled a:focus, -.dataTable-pagination .disabled a:hover { - cursor: not-allowed; - opacity: 0.4; -} - -.dataTable-pagination .pager a { - font-weight: bold; -} - -/* TABLE */ -.dataTable-table { - max-width: 100%; - width: 100%; - border-spacing: 0; - border-collapse: separate; -} - -.dataTable-table > tbody > tr > td, -.dataTable-table > tbody > tr > th, -.dataTable-table > tfoot > tr > td, -.dataTable-table > tfoot > tr > th, -.dataTable-table > thead > tr > td, -.dataTable-table > thead > tr > th { - vertical-align: top; - padding: 8px 10px; -} - -.dataTable-table > thead > tr > th { - vertical-align: bottom; - text-align: left; - border-bottom: 1px solid #d9d9d9; -} - -.dataTable-table > tfoot > tr > th { - vertical-align: bottom; - text-align: left; - border-top: 1px solid #d9d9d9; -} - -.dataTable-table th { - vertical-align: bottom; - text-align: left; -} - -.dataTable-table th a { - text-decoration: none; - color: inherit; -} - -.dataTable-sorter { - display: inline-block; - height: 100%; - position: relative; - width: 100%; -} - -.dataTable-sorter::before, -.dataTable-sorter::after { - content: ""; - height: 0; - width: 0; - position: absolute; - right: 4px; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - opacity: 0.2; -} - -.dataTable-sorter::before { - border-top: 4px solid #000; - bottom: 0px; -} - -.dataTable-sorter::after { - border-bottom: 4px solid #000; - border-top: 4px solid transparent; - top: 0px; -} - -.asc .dataTable-sorter::after, -.desc .dataTable-sorter::before { - opacity: 0.6; -} - -.dataTables-empty { - text-align: center; -} - -.dataTable-top::after, .dataTable-bottom::after { - clear: both; - content: " "; - display: table; -} - -table.dataTable-table:focus tr.dataTable-cursor > td:first-child { - border-left: 3px blue solid; -} - -table.dataTable-table:focus { - outline: solid 1px black; - outline-offset: -1px; -} \ No newline at end of file diff --git a/ereuse_devicehub/static/js/simple-datatables-5.0.3.js b/ereuse_devicehub/static/js/simple-datatables-5.0.3.js deleted file mode 100644 index 0a894d0b..00000000 --- a/ereuse_devicehub/static/js/simple-datatables-5.0.3.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Minified by jsDelivr using Terser v5.15.1. - * Original file: /npm/simple-datatables@5.0.3/dist/umd/simple-datatables.js - * - * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files - */ -!function(t){if(typeof exports==="object"&&typeof module!=="undefined")module.exports=t();else if(typeof define==="function"&&define.amd)define([],t);else{(typeof window!=="undefined"?window:typeof global!=="undefined"?global:typeof self!=="undefined"?self:this).simpleDatatables=t()}}((() =>function t(e,s,i){function a(o,r){if(!s[o]){if(!e[o]){const l=typeof require==="function"&&require;if(!r&&l)return l(o,!0);if(n)return n(o,!0);const h=new Error(`Cannot find module '${o}'`);throw h.code="MODULE_NOT_FOUND",h}const d=s[o]={exports:{}};e[o][0].call(d.exports,((t) =>a(e[o][1][t]||t)),d,d.exports,t,e,s,i)}return s[o].exports}for(var n=typeof require==="function"&&require,o=0;o=e?t:`${Array(e+1-i.length).join(s)}${t}`}; const b={s:m,z(t){const e=-t.utcOffset(); const s=Math.abs(e); const i=Math.floor(s/60); const a=s%60;return`${(e<=0?"+":"-")+m(i,2,"0")}:${m(a,2,"0")}`},m:function t(e,s){if(e.date()1)return t(o[0])}else{const r=e.name;w[r]=e,a=r}return!i&&a&&(v=a),a||!i&&v}; const x=function(t,e){if(y(t))return t.clone();const s=typeof e==="object"?e:{};return s.date=t,s.args=arguments,new M(s)}; const T=b;T.l=C,T.i=y,T.w=function(t,e){return x(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var M=function(){function g(t){this.$L=C(t.locale,null,!0),this.parse(t)}const m=g.prototype;return m.parse=function(t){this.$d=function(t){const e=t.date; const s=t.utc;if(e===null)return new Date(NaN);if(T.u(e))return new Date;if(e instanceof Date)return new Date(e);if(typeof e==="string"&&!/Z$/i.test(e)){const i=e.match(p);if(i){const a=i[2]-1||0; const n=(i[7]||"0").substring(0,3);return s?new Date(Date.UTC(i[1],a,i[3]||1,i[4]||0,i[5]||0,i[6]||0,n)):new Date(i[1],a,i[3]||1,i[4]||0,i[5]||0,i[6]||0,n)}}return new Date(e)}(t),this.$x=t.x||{},this.init()},m.init=function(){const t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return T},m.isValid=function(){return!(this.$d.toString()===u)},m.isSame=function(t,e){const s=x(t);return this.startOf(e)<=s&&s<=this.endOf(e)},m.isAfter=function(t,e){return x(t)e||g[t]||a.replace(":","")))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(s,c,u){let p; const f=T.p(c); const g=x(s); const m=(g.utcOffset()-this.utcOffset())*t; const b=this-g; let v=T.m(this,g);return v=(p={},p[d]=v/12,p[l]=v,p[h]=v/3,p[r]=(b-m)/6048e5,p[o]=(b-m)/864e5,p[n]=b/e,p[a]=b/t,p[i]=b/1e3,p)[f]||b,u?v:T.a(v)},m.daysInMonth=function(){return this.endOf(l).$D},m.$locale=function(){return w[this.$L]},m.locale=function(t,e){if(!t)return this.$L;const s=this.clone(); const i=C(t,e,!0);return i&&(s.$L=i),s},m.clone=function(){return T.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},g}(); const E=M.prototype;return x.prototype=E,[["$ms",s],["$s",i],["$m",a],["$H",n],["$W",o],["$M",l],["$y",d],["$D",c]].forEach(((t) =>{E[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),x.extend=function(t,e){return t.$i||(t(e,M,x),t.$i=!0),x},x.locale=C,x.isDayjs=y,x.unix=function(t){return x(1e3*t)},x.en=w[v],x.Ls=w,x.p={},x}(); const i={exports:{}}.exports=function(){const t={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"}; const e=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|YYYY|YY?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g; const s=/\d\d/; const i=/\d\d?/; const a=/\d*[^-_:/,()\s\d]+/; let n={}; let o=function(t){return(t=+t)+(t>68?1900:2e3)}; const r=function(t){return function(e){this[t]=+e}}; const l=[/[+-]\d\d:?(\d\d)?|Z/,function(t){(this.zone||(this.zone={})).offset=function(t){if(!t)return 0;if(t==="Z")return 0;const e=t.match(/([+-]|\d\d)/g); const s=60*e[1]+(+e[2]||0);return s===0?0:e[0]==="+"?-s:s}(t)}]; const h=function(t){const e=n[t];return e&&(e.indexOf?e:e.s.concat(e.f))}; const d=function(t,e){let s; const i=n.meridiem;if(i){for(let a=1;a<=24;a+=1)if(t.indexOf(i(a,0,e))>-1){s=a>12;break}}else s=t===(e?"pm":"PM");return s}; const c={A:[a,function(t){this.afternoon=d(t,!1)}],a:[a,function(t){this.afternoon=d(t,!0)}],S:[/\d/,function(t){this.milliseconds=100*+t}],SS:[s,function(t){this.milliseconds=10*+t}],SSS:[/\d{3}/,function(t){this.milliseconds=+t}],s:[i,r("seconds")],ss:[i,r("seconds")],m:[i,r("minutes")],mm:[i,r("minutes")],H:[i,r("hours")],h:[i,r("hours")],HH:[i,r("hours")],hh:[i,r("hours")],D:[i,r("day")],DD:[s,r("day")],Do:[a,function(t){const e=n.ordinal; const s=t.match(/\d+/);if(this.day=s[0],e)for(let i=1;i<=31;i+=1)e(i).replace(/\[|\]/g,"")===t&&(this.day=i)}],M:[i,r("month")],MM:[s,r("month")],MMM:[a,function(t){const e=h("months"); const s=(h("monthsShort")||e.map(((t) =>t.slice(0,3)))).indexOf(t)+1;if(s<1)throw new Error;this.month=s%12||s}],MMMM:[a,function(t){const e=h("months").indexOf(t)+1;if(e<1)throw new Error;this.month=e%12||e}],Y:[/[+-]?\d+/,r("year")],YY:[s,function(t){this.year=o(t)}],YYYY:[/\d{4}/,r("year")],Z:l,ZZ:l};function u(s){let i; let a;i=s,a=n&&n.formats;for(var o=(s=i.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,((e,s,i) =>{const n=i&&i.toUpperCase();return s||a[i]||t[i]||a[n].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,((t,e,s) =>e||s.slice(1)))}))).match(e),r=o.length,l=0;l-1)return new Date((e==="X"?1e3:1)*t);const i=u(e)(t); const a=i.year; const n=i.month; const o=i.day; const r=i.hours; const l=i.minutes; const h=i.seconds; const d=i.milliseconds; const c=i.zone; const p=new Date; const f=o||(a||n?1:p.getDate()); const g=a||p.getFullYear(); let m=0;a&&!n||(m=n>0?n-1:p.getMonth());const b=r||0; const v=l||0; const w=h||0; const y=d||0;return c?new Date(Date.UTC(g,m,f,b,v,w,y+60*c.offset*1e3)):s?new Date(Date.UTC(g,m,f,b,v,w,y)):new Date(g,m,f,b,v,w,y)}catch(t){return new Date("")}}(e,r,i),this.init(),c&&!0!==c&&(this.$L=this.locale(c).$L),d&&e!=this.format(r)&&(this.$d=new Date("")),n={}}else if(r instanceof Array)for(let p=r.length,f=1;f<=p;f+=1){o[1]=r[f-1];const g=s.apply(this,o);if(g.isValid()){this.$d=g.$d,this.$L=g.$L,this.init();break}f===p&&(this.$d=new Date(""))}else a.call(this,t)}}}();e.extend(i),s.parseDate=(t,s)=>{let i=!1;if(s)switch(s){case"ISO_8601":i=t;break;case"RFC_2822":i=e(t.slice(5),"DD MMM YYYY HH:mm:ss ZZ").unix();break;case"MYSQL":i=e(t,"YYYY-MM-DD hh:mm:ss").unix();break;case"UNIX":i=e(t).unix();break;default:i=e(t,s,!0).valueOf()}return i}}).call(this)}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{}],2:[function(t,e,s){"use strict"; - -Object.defineProperty(s,"__esModule",{value:!0});const i=t=>Object.prototype.toString.call(t)==="[object Object]"; const a=t=>{let e=!1;try{e=JSON.parse(t)}catch(t){return!1}return!(e===null||!Array.isArray(e)&&!i(e))&&e}; const n=(t,e)=>{const s=document.createElement(t);if(e&&typeof e==="object")for(const t in e)t==="html"?s.innerHTML=e[t]:s.setAttribute(t,e[t]);return s}; const o=t=>{t instanceof NodeList?t.forEach((t=>o(t))):t.innerHTML=""}; const r=(t,e,s)=>n("li",{class:t,html:`${s}`}); const l=(t,e)=>{let s; let i;e===1?(s=0,i=t.length):e===-1&&(s=t.length-1,i=-1);for(let a=!0;a;){a=!1;for(let n=s;n!=i;n+=e)if(t[n+e]&&t[n].value>t[n+e].value){const s=t[n]; const i=t[n+e]; const o=s;t[n]=i,t[n+e]=o,a=!0}}return t};class h{constructor(t){this.dt=t,this.cursor=!1} - -build(t){const e=n("tr");let s=this.dt.headings;return s.length||(s=t.map((()=>""))),s.forEach(((s,i)=>{const a=n("td");t[i]&&t[i].length||(t[i]=""),a.innerHTML=t[i],a.data=t[i],e.appendChild(a)})),e} - -setCursor(t=!1){let e;Array.from(this.dt.dom.rows).forEach((t=>{e=t,t.classList.remove("dataTable-cursor")})),t&&(t.classList.add("dataTable-cursor"),this.cursor=t,this.dt.options.scrollY&&this.cursor.scrollIntoView({block:"nearest"}),this.dt.emit("datatable.cursormove",this.cursor,e))} - -render(t){return t} - -add(t){if(Array.isArray(t)){const e=this.dt;Array.isArray(t[0])?t.forEach((t=>{e.data.push(this.build(t))})):e.data.push(this.build(t)),e.data.length&&(e.hasRows=!0),this.update(),e.columns.rebuild()}} - -remove(t){const e=this.dt;Array.isArray(t)?(t.sort(((t,e)=>e-t)),t.forEach((t=>{e.data.splice(t,1)}))):t=="all"?e.data=[]:e.data.splice(t,1),e.data.length||(e.hasRows=!1),this.update(),e.columns.rebuild()} - -update(){this.dt.data.forEach(((t,e)=>{t.dataIndex=e}))} - -findRowIndex(t,e){return this.dt.data.findIndex((s=>s.children[t].innerText.toLowerCase().includes(String(e).toLowerCase())))} - -findRow(t,e){const s=this.findRowIndex(t,e);if(s<0)return{index:-1,row:null,cols:[]};const i=this.dt.data[s];return{index:s,row:i,cols:[...i.cells].map((t=>t.innerHTML))}} - -updateRow(t,e){const s=this.build(e);this.dt.data.splice(t,1,s),this.update(),this.dt.columns.rebuild()}}class d{constructor(t){this.dt=t} - -swap(t){if(t.length&&t.length===2){const e=[];this.dt.headings.forEach(((t,s)=>{e.push(s)}));const s=t[0]; const i=t[1]; const a=e[i];e[i]=e[s],e[s]=a,this.order(e)}} - -order(t){let e; let s; let i; let a; let n; let o; let r;const l=[[],[],[],[]]; const h=this.dt;t.forEach(((t,i)=>{n=h.headings[t],o=n.getAttribute("data-sortable")!=="false",e=n.cloneNode(!0),e.originalCellIndex=i,e.sortable=o,l[0].push(e),h.hiddenColumns.includes(t)||(s=n.cloneNode(!0),s.originalCellIndex=i,s.sortable=o,l[1].push(s))})),h.data.forEach(((e,s)=>{i=e.cloneNode(!1),a=e.cloneNode(!1),i.dataIndex=a.dataIndex=s,e.searchIndex!==null&&void 0!==e.searchIndex&&(i.searchIndex=a.searchIndex=e.searchIndex),t.forEach((t=>{r=e.cells[t].cloneNode(!0),r.data=e.cells[t].data,i.appendChild(r),h.hiddenColumns.includes(t)||(r=e.cells[t].cloneNode(!0),r.data=e.cells[t].data,a.appendChild(r))})),l[2].push(i),l[3].push(a)})),h.headings=l[0],h.activeHeadings=l[1],h.data=l[2],h.activeRows=l[3],h.update()} - -hide(t){if(t.length){const e=this.dt;t.forEach((t=>{e.hiddenColumns.includes(t)||e.hiddenColumns.push(t)})),this.rebuild()}} - -show(t){if(t.length){let e;const s=this.dt;t.forEach((t=>{e=s.hiddenColumns.indexOf(t),e>-1&&s.hiddenColumns.splice(e,1)})),this.rebuild()}} - -visible(t){let e;const s=this.dt;return t=t||s.headings.map((t=>t.originalCellIndex)),isNaN(t)?Array.isArray(t)&&(e=[],t.forEach((t=>{e.push(!s.hiddenColumns.includes(t))}))):e=!s.hiddenColumns.includes(t),e} - -add(t){let e;const s=document.createElement("th");if(!this.dt.headings.length)return this.dt.insert({headings:[t.heading],data:t.data.map((t=>[t]))}),void this.rebuild();this.dt.hiddenHeader?s.innerHTML="":t.heading.nodeName?s.appendChild(t.heading):s.innerHTML=t.heading,this.dt.headings.push(s),this.dt.data.forEach(((s,i)=>{t.data[i]&&(e=document.createElement("td"),t.data[i].nodeName?e.appendChild(t.data[i]):e.innerHTML=t.data[i],e.data=e.innerHTML,t.render&&(e.innerHTML=t.render.call(this,e.data,e,s)),s.appendChild(e))})),t.type&&s.setAttribute("data-type",t.type),t.format&&s.setAttribute("data-format",t.format),t.hasOwnProperty("sortable")&&(s.sortable=t.sortable,s.setAttribute("data-sortable",!0===t.sortable?"true":"false")),this.rebuild(),this.dt.renderHeader()} - -remove(t){Array.isArray(t)?(t.sort(((t,e)=>e-t)),t.forEach((t=>this.remove(t)))):(this.dt.headings.splice(t,1),this.dt.data.forEach((e=>{e.removeChild(e.cells[t])}))),this.rebuild()} - -filter(t,e,s,i){const a=this.dt;if(a.filterState||(a.filterState={originalData:a.data}),!a.filterState[t]){const e=[...i,()=>!0];a.filterState[t]=function(){let t=0;return()=>e[t++%e.length]}()}const n=a.filterState[t](); const o=Array.from(a.filterState.originalData).filter((e=>{const s=e.cells[t]; const i=s.hasAttribute("data-content")?s.getAttribute("data-content"):s.innerText;return typeof n==="function"?n(i):i===n}));a.data=o,a.data.length?(this.rebuild(),a.update()):(a.clear(),a.hasRows=!1,a.setMessage(a.options.labels.noRows)),s||a.emit("datatable.sort",t,e)} - -sort(e,s,i){const a=this.dt;if(a.hasHeadings&&(e<0||e>a.headings.length))return!1;const n=a.options.filters&&a.options.filters[a.headings[e].textContent];if(n&&n.length!==0)return void this.filter(e,s,i,n);a.sorting=!0,i||a.emit("datatable.sorting",e,s);let o=a.data;const r=[]; const h=[];let d=0; let c=0;const u=a.headings[e]; const p=[];if(u.getAttribute("data-type")==="date"){let e=!1;u.hasAttribute("data-format")&&(e=u.getAttribute("data-format")),p.push(Promise.resolve().then((() =>t("./date-7061ceee.js"))).then((({parseDate:t})=>s=>t(s,e))))}Promise.all(p).then((t=>{const n=t[0];let p; let f;Array.from(o).forEach((t=>{const s=t.cells[e]; const i=s.hasAttribute("data-content")?s.getAttribute("data-content"):s.innerText;let a;a=n?n(i):typeof i==="string"?i.replace(/(\$|,|\s|%)/g,""):i,parseFloat(a)==a?h[c++]={value:Number(a),row:t}:r[d++]={value:typeof i==="string"?i.toLowerCase():i,row:t}})),s||(s=u.classList.contains("asc")?"desc":"asc"),s=="desc"?(p=l(r,-1),f=l(h,-1),u.classList.remove("asc"),u.classList.add("desc"),u.setAttribute("aria-sort","descending")):(p=l(h,1),f=l(r,1),u.classList.remove("desc"),u.classList.add("asc"),u.setAttribute("aria-sort","ascending")),a.lastTh&&u!=a.lastTh&&(a.lastTh.classList.remove("desc"),a.lastTh.classList.remove("asc"),a.lastTh.removeAttribute("aria-sort")),a.lastTh=u,o=p.concat(f),a.data=[];const g=[];o.forEach(((t,e)=>{a.data.push(t.row),t.row.searchIndex!==null&&void 0!==t.row.searchIndex&&g.push(e)})),a.searchData=g,this.rebuild(),a.update(),i||a.emit("datatable.sort",e,s)}))} - -rebuild(){let t; let e; let s; let i;const a=this.dt; const n=[];a.activeRows=[],a.activeHeadings=[],a.headings.forEach(((t,e)=>{t.originalCellIndex=e,t.sortable=t.getAttribute("data-sortable")!=="false",a.hiddenColumns.includes(e)||a.activeHeadings.push(t)})),a.selectedColumns.length&&a.data.forEach((t=>{Array.from(t.cells).forEach(((e,s)=>{a.selectedColumns.includes(s)&&a.columnRenderers.forEach((i=>{i.columns.includes(s)&&(a.data[e.parentNode.dataIndex].cells[e.cellIndex].innerHTML=e.innerHTML=i.renderer.call(this,e.data,e,t))}))}))})),a.data.forEach(((o,r)=>{t=o.cloneNode(!1),e=o.cloneNode(!1),t.dataIndex=e.dataIndex=r,o.searchIndex!==null&&void 0!==o.searchIndex&&(t.searchIndex=e.searchIndex=o.searchIndex),Array.from(o.cells).forEach((n=>{s=n.cloneNode(!0),s.data=n.data,t.appendChild(s),a.hiddenColumns.includes(s.cellIndex)||(i=s.cloneNode(!0),i.data=s.data,e.appendChild(i))})),n.push(t),a.activeRows.push(e)})),a.data=n,a.update()}}const c=function(t){let e=!1; let s=!1;if((t=t||this.options.data).headings){e=n("thead");const s=n("tr");t.headings.forEach((t=>{const e=n("th",{html:t});s.appendChild(e)})),e.appendChild(s)}t.data&&t.data.length&&(s=n("tbody"),t.data.forEach((e=>{if(t.headings&&t.headings.length!==e.length)throw new Error("The number of rows do not match the number of headings.");const i=n("tr");e.forEach((t=>{const e=n("td",{html:t});i.appendChild(e)})),s.appendChild(i)}))),e&&(this.dom.tHead!==null&&this.dom.removeChild(this.dom.tHead),this.dom.appendChild(e)),s&&(this.dom.tBodies.length&&this.dom.removeChild(this.dom.tBodies[0]),this.dom.appendChild(s))}; const u={sortable:!0,searchable:!0,paging:!0,perPage:10,perPageSelect:[5,10,15,20,25],nextPrev:!0,firstLast:!1,prevText:"‹",nextText:"›",firstText:"«",lastText:"»",ellipsisText:"…",ascText:"▴",descText:"▾",truncatePager:!0,pagerDelta:2,scrollY:"",fixedColumns:!0,fixedHeight:!1,header:!0,hiddenHeader:!1,footer:!1,tabIndex:!1,rowNavigation:!1,labels:{placeholder:"Search...",perPage:"{select} entries per page",noRows:"No entries found",noResults:"No results match your search query",info:"Showing {start} to {end} of {rows} entries"},layout:{top:"{select}{search}",bottom:"{info}{pager}"}}; const p={classes:{row:"dataTable-editor-row",form:"dataTable-editor-form",item:"dataTable-editor-item",menu:"dataTable-editor-menu",save:"dataTable-editor-save",block:"dataTable-editor-block",close:"dataTable-editor-close",inner:"dataTable-editor-inner",input:"dataTable-editor-input",label:"dataTable-editor-label",modal:"dataTable-editor-modal",action:"dataTable-editor-action",header:"dataTable-editor-header",wrapper:"dataTable-editor-wrapper",editable:"dataTable-editor-editable",container:"dataTable-editor-container",separator:"dataTable-editor-separator"},labels:{editCell:"Edit Cell",editRow:"Edit Row",removeRow:"Remove Row",reallyRemove:"Are you sure?"},hiddenColumns:!1,contextMenu:!0,clickEvent:"dblclick",excludeColumns:[],menuItems:[{text:t=>t.options.labels.editCell,action:(t,e)=>{const s=t.event.target.closest("td");return t.editCell(s)}},{text:t=>t.options.labels.editRow,action:(t,e)=>{const s=t.event.target.closest("tr");return t.editRow(s)}},{separator:!0},{text:t=>t.options.labels.removeRow,action:(t,e)=>{if(confirm(t.options.labels.reallyRemove)){const e=t.event.target.closest("tr");t.removeRow(e)}}}]};class f{constructor(t,e={}){this.dataTable=t,this.options={...p,...e}} - -init(){this.initialized||(this.dataTable.wrapper.classList.add(this.options.classes.editable),this.options.contextMenu&&(this.container=n("div",{id:this.options.classes.container}),this.wrapper=n("div",{class:this.options.classes.wrapper}),this.menu=n("ul",{class:this.options.classes.menu}),this.options.menuItems&&this.options.menuItems.length&&this.options.menuItems.forEach((t=>{const e=n("li",{class:t.separator?this.options.classes.separator:this.options.classes.item});if(!t.separator){const s=n("a",{class:this.options.classes.action,href:t.url||"#",html:typeof t.text==="function"?t.text(this):t.text});e.appendChild(s),t.action&&typeof t.action==="function"&&s.addEventListener("click",(e=>{e.preventDefault(),t.action(this,e)}))}this.menu.appendChild(e)})),this.wrapper.appendChild(this.menu),this.container.appendChild(this.wrapper),this.update()),this.data={},this.closed=!0,this.editing=!1,this.editingRow=!1,this.editingCell=!1,this.bindEvents(),setTimeout((()=>{this.initialized=!0,this.dataTable.emit("editable.init")}),10))} - -bindEvents(){this.events={context:this.context.bind(this),update:this.update.bind(this),dismiss:this.dismiss.bind(this),keydown:this.keydown.bind(this),click:this.click.bind(this)},this.dataTable.body.addEventListener(this.options.clickEvent,this.events.click),document.addEventListener("click",this.events.dismiss),document.addEventListener("keydown",this.events.keydown),this.options.contextMenu&&(this.dataTable.body.addEventListener("contextmenu",this.events.context),this.events.reset=function(t,e=300){let s;return(...i)=>{clearTimeout(s),s=setTimeout((()=>{t.apply(this,i)}),e)}}(this.events.update,50),window.addEventListener("resize",this.events.reset),window.addEventListener("scroll",this.events.reset))} - -context(t){this.event=t;const e=this.dataTable.body.contains(t.target);if(this.options.contextMenu&&!this.disabled&&e){t.preventDefault();let e=t.pageX; let s=t.pageY;e>this.limits.x&&(e-=this.rect.width),s>this.limits.y&&(s-=this.rect.height),this.wrapper.style.top=`${s}px`,this.wrapper.style.left=`${e}px`,this.openMenu(),this.update()}} - -click(t){if(this.editing&&this.data&&this.editingCell)this.saveCell();else if(!this.editing){const e=t.target.closest("td");e&&(this.editCell(e),t.preventDefault())}} - -keydown(t){this.modal?t.key==="Escape"?this.closeModal():t.key==="Enter"&&this.saveRow():this.editing&&this.data&&(t.key==="Enter"?this.editingCell?this.saveCell():this.editingRow&&this.saveRow():t.key==="Escape"&&this.saveCell(this.data.content))} - -editCell(t){this.options.excludeColumns.includes(t.cellIndex)?this.closeMenu():(t=this.dataTable.body.rows[t.parentNode.dataIndex].cells[t.cellIndex],this.data={cell:t,content:t.dataset.content||t.innerHTML,input:n("input",{type:"text",value:t.dataset.content||t.innerHTML,class:this.options.classes.input})},t.innerHTML="",t.appendChild(this.data.input),setTimeout((()=>{this.data.input.focus(),this.data.input.selectionStart=this.data.input.selectionEnd=this.data.input.value.length,this.editing=!0,this.editingCell=!0,this.closeMenu()}),10))} - -saveCell(t,e){e=e||this.data.cell,t=t||this.data.input.value;const s=this.data.content;this.dataTable.data[e.parentNode.dataIndex].cells[e.cellIndex].innerHTML=e.innerHTML=t.trim(),this.data={},this.editing=this.editingCell=!1,this.dataTable.emit("editable.save.cell",t,s,e)} - -editRow(t){if(!(t=t||this.event.target.closest("tr"))||t.nodeName!=="TR"||this.editing)return;t=this.dataTable.body.rows[t.dataIndex];const e=[`
`,`
`,"

Editing row

",``,"
",`
`,`
`,`
`,``,"
","
","
","
"].join(""); const s=n("div",{class:this.options.classes.modal,html:e}); const i=s.firstElementChild.lastElementChild.firstElementChild;Array.from(t.cells).forEach(((t,e)=>{(!t.hidden||t.hidden&&this.options.hiddenColumns)&&!this.options.excludeColumns.includes(e)&&i.insertBefore(n("div",{class:this.options.classes.row,html:[`
`,``,``,"
"].join("")}),i.lastElementChild)})),this.modal=s,this.openModal();const a=Array.from(i.elements);a.pop(),this.data={row:t,inputs:a},this.editing=!0,this.editingRow=!0,s.addEventListener("click",(t=>{t.target.hasAttribute("data-editor-close")?this.closeModal():t.target.hasAttribute("data-editor-save")&&this.saveRow()})),this.closeMenu()} - -saveRow(t,e){t=t||this.data.inputs.map((t=>t.value.trim())),e=e||this.data.row;const s=Array.from(e.cells).map((t=>t.dataset.content||t.innerHTML));Array.from(e.cells).forEach(((e,s)=>{e.innerHTML=t[s]})),this.closeModal(),this.dataTable.emit("editable.save.row",t,s,e)} - -openModal(){!this.editing&&this.modal&&document.body.appendChild(this.modal)} - -closeModal(){this.editing&&this.modal&&(document.body.removeChild(this.modal),this.modal=this.editing=this.editingRow=!1)} - -removeRow(t){t?(t instanceof Element&&t.nodeName==="TR"&&void 0!==t.dataIndex&&(t=t.dataIndex),this.dataTable.rows.remove(t),this.closeMenu()):(t=this.event.target.closest("tr"))&&void 0!==t.dataIndex&&(this.dataTable.rows.remove(t.dataIndex),this.closeMenu())} - -update(){const t=window.scrollX||window.pageXOffset; const e=window.scrollY||window.pageYOffset;this.rect=this.wrapper.getBoundingClientRect(),this.limits={x:window.innerWidth+t-this.rect.width,y:window.innerHeight+e-this.rect.height}} - -dismiss(t){let e=!0;this.options.contextMenu&&(e=!this.wrapper.contains(t.target),this.editing&&(e=!this.wrapper.contains(t.target)&&t.target!==this.data.input)),e&&(this.editingCell&&this.saveCell(this.data.content),this.closeMenu())} - -openMenu(){this.editing&&this.data&&this.editingCell&&this.saveCell(),this.options.contextMenu&&(document.body.appendChild(this.container),this.closed=!1,this.dataTable.emit("editable.context.open"))} - -closeMenu(){this.options.contextMenu&&!this.closed&&(this.closed=!0,document.body.removeChild(this.container),this.dataTable.emit("editable.context.close"))} - -destroy(){this.dataTable.body.removeEventListener(this.options.clickEvent,this.events.click),this.dataTable.body.removeEventListener("contextmenu",this.events.context),document.removeEventListener("click",this.events.dismiss),document.removeEventListener("keydown",this.events.keydown),window.removeEventListener("resize",this.events.reset),window.removeEventListener("scroll",this.events.reset),document.body.contains(this.container)&&document.body.removeChild(this.container),this.initialized=!1}}s.DataTable=class{constructor(t,e={}){const s=typeof t==="string"?document.querySelector(t):t;if(this.options={...u,...e,layout:{...u.layout,...e.layout},labels:{...u.labels,...e.labels}},this.rows=new h(this),this.columns=new d(this),this.initialized=!1,this.initialLayout=s.innerHTML,this.initialSortable=this.options.sortable,this.options.tabIndex?s.tabIndex=this.options.tabIndex:this.options.rowNavigation&&s.tabIndex===-1&&(s.tabIndex=0),this.options.header||(this.options.sortable=!1),s.tHead===null&&(!this.options.data||this.options.data&&!this.options.data.headings)&&(this.options.sortable=!1),s.tBodies.length&&!s.tBodies[0].rows.length&&this.options.data&&!this.options.data.data)throw new Error("You seem to be using the data option, but you've not defined any rows.");this.dom=s,this.listeners={onResize:t=>this.onResize(t)},this.init()} - -init(t){if(this.initialized||this.dom.classList.contains("dataTable-table"))return!1;Object.assign(this.options,t||{}),this.currentPage=1,this.onFirstPage=!0,this.hiddenColumns=[],this.columnRenderers=[],this.selectedColumns=[],this.render(),setTimeout((()=>{this.emit("datatable.init"),this.initialized=!0}),10)} - -render(){let t="";if(this.options.data&&c.call(this),this.body=this.dom.tBodies[0],this.head=this.dom.tHead,this.foot=this.dom.tFoot,this.body||(this.body=n("tbody"),this.dom.appendChild(this.body)),this.hasRows=this.body.rows.length>0,!this.head){const t=n("thead"); const e=n("tr");this.hasRows&&(Array.from(this.body.rows[0].cells).forEach((()=>{e.appendChild(n("th"))})),t.appendChild(e)),this.head=t,this.dom.insertBefore(this.head,this.body),this.hiddenHeader=this.options.hiddenHeader}if(this.headings=[],this.hasHeadings=this.head.rows.length>0,this.hasHeadings&&(this.header=this.head.rows[0],this.headings=[].slice.call(this.header.cells)),this.options.header||this.head&&this.dom.removeChild(this.dom.tHead),this.options.footer?this.head&&!this.foot&&(this.foot=n("tfoot",{html:this.head.innerHTML}),this.dom.appendChild(this.foot)):this.foot&&this.dom.removeChild(this.dom.tFoot),this.wrapper=n("div",{class:"dataTable-wrapper dataTable-loading"}),t+="
",t+=this.options.layout.top,t+="
",this.options.scrollY.length?t+=`
`:t+="
",t+="
",t+=this.options.layout.bottom,t+="
",t=t.replace("{info}",this.options.paging?"
":""),this.options.paging&&this.options.perPageSelect){let e="
";const s=n("select",{class:"dataTable-selector"});this.options.perPageSelect.forEach((t=>{const e=t===this.options.perPage; const i=new Option(t,t,e,e);s.add(i)})),e=e.replace("{select}",s.outerHTML),t=t.replace("{select}",e)}else t=t.replace("{select}","");if(this.options.searchable){const e=``;t=t.replace("{search}",e)}else t=t.replace("{search}","");this.hasHeadings&&this.renderHeader(),this.dom.classList.add("dataTable-table");const e=n("nav",{class:"dataTable-pagination"}); const s=n("ul",{class:"dataTable-pagination-list"});e.appendChild(s),t=t.replace(/\{pager\}/g,e.outerHTML),this.wrapper.innerHTML=t,this.container=this.wrapper.querySelector(".dataTable-container"),this.pagers=this.wrapper.querySelectorAll(".dataTable-pagination-list"),this.label=this.wrapper.querySelector(".dataTable-info"),this.dom.parentNode.replaceChild(this.wrapper,this.dom),this.container.appendChild(this.dom),this.rect=this.dom.getBoundingClientRect(),this.data=Array.from(this.body.rows),this.activeRows=this.data.slice(),this.activeHeadings=this.headings.slice(),this.update(),this.setColumns(),this.fixHeight(),this.fixColumns(),this.options.header||this.wrapper.classList.add("no-header"),this.options.footer||this.wrapper.classList.add("no-footer"),this.options.sortable&&this.wrapper.classList.add("sortable"),this.options.searchable&&this.wrapper.classList.add("searchable"),this.options.fixedHeight&&this.wrapper.classList.add("fixed-height"),this.options.fixedColumns&&this.wrapper.classList.add("fixed-columns"),this.bindEvents()} - -renderPage(t=!1){if(this.hasHeadings&&(o(this.header),this.activeHeadings.forEach((t=>this.header.appendChild(t)))),this.hasRows&&this.totalPages){this.currentPage>this.totalPages&&(this.currentPage=1);const t=this.currentPage-1; const e=document.createDocumentFragment();this.pages[t].forEach((t=>e.appendChild(this.rows.render(t)))),this.clear(e),this.onFirstPage=this.currentPage===1,this.onLastPage=this.currentPage===this.lastPage}else this.setMessage(this.options.labels.noRows);let e; let s=0; let i=0; let a=0;if(this.totalPages&&(s=this.currentPage-1,i=s*this.options.perPage,a=i+this.pages[s].length,i+=1,e=this.searching?this.searchData.length:this.data.length),this.label&&this.options.labels.info.length){const t=this.options.labels.info.replace("{start}",i).replace("{end}",a).replace("{page}",this.currentPage).replace("{pages}",this.totalPages).replace("{rows}",e);this.label.innerHTML=e?t:""}if(this.currentPage==1&&this.fixHeight(),this.options.rowNavigation&&(!this.rows.cursor||!this.pages[this.currentPage-1].includes(this.rows.cursor))){const e=this.pages[this.currentPage-1];t?this.rows.setCursor(e[e.length-1]):this.rows.setCursor(e[0])}} - -renderPager(){if(o(this.pagers),this.totalPages>1){const t="pager"; const e=document.createDocumentFragment(); const s=this.onFirstPage?1:this.currentPage-1; const i=this.onLastPage?this.totalPages:this.currentPage+1;this.options.firstLast&&e.appendChild(r(t,1,this.options.firstText)),this.options.nextPrev&&!this.onFirstPage&&e.appendChild(r(t,s,this.options.prevText));let a=this.links;this.options.truncatePager&&(a=((t,e,s,i,a)=>{let o;const r=2*(i=i||2);let l=e-i; let h=e+i;const d=[]; const c=[];e<4-i+r?h=3+r:e>s-(3-i+r)&&(l=s-(2+r));for(let e=1;e<=s;e++)if(e==1||e==s||e>=l&&e<=h){const s=t[e-1];s.classList.remove("active"),d.push(s)}return d.forEach((e=>{const s=e.children[0].getAttribute("data-page");if(o){const e=o.children[0].getAttribute("data-page");if(s-e==2)c.push(t[e]);else if(s-e!=1){const t=n("li",{class:"ellipsis",html:`${a}`});c.push(t)}}c.push(e),o=e})),c})(this.links,this.currentPage,this.pages.length,this.options.pagerDelta,this.options.ellipsisText)),this.links[this.currentPage-1].classList.add("active"),a.forEach((t=>{t.classList.remove("active"),e.appendChild(t)})),this.links[this.currentPage-1].classList.add("active"),this.options.nextPrev&&!this.onLastPage&&e.appendChild(r(t,i,this.options.nextText)),this.options.firstLast&&e.appendChild(r(t,this.totalPages,this.options.lastText)),this.pagers.forEach((t=>{t.appendChild(e.cloneNode(!0))}))}} - -renderHeader(){this.labels=[],this.headings&&this.headings.length&&this.headings.forEach(((t,e)=>{if(this.labels[e]=t.textContent,t.firstElementChild&&t.firstElementChild.classList.contains("dataTable-sorter")&&(t.innerHTML=t.firstElementChild.innerHTML),t.sortable=t.getAttribute("data-sortable")!=="false",t.originalCellIndex=e,this.options.sortable&&t.sortable){const e=n("a",{href:"#",class:"dataTable-sorter",html:t.innerHTML});t.innerHTML="",t.setAttribute("data-sortable",""),t.appendChild(e)}})),this.fixColumns()} - -bindEvents(){if(this.options.perPageSelect){const t=this.wrapper.querySelector(".dataTable-selector");t&&t.addEventListener("change",(()=>{this.options.perPage=parseInt(t.value,10),this.update(),this.fixHeight(),this.emit("datatable.perpage",this.options.perPage)}),!1)}this.options.searchable&&(this.input=this.wrapper.querySelector(".dataTable-input"),this.input&&this.input.addEventListener("keyup",(()=>this.search(this.input.value)),!1)),this.wrapper.addEventListener("click",(t=>{const e=t.target.closest("a");e&&e.nodeName.toLowerCase()==="a"&&(e.hasAttribute("data-page")?(this.page(e.getAttribute("data-page")),t.preventDefault()):this.options.sortable&&e.classList.contains("dataTable-sorter")&&e.parentNode.getAttribute("data-sortable")!="false"&&(this.columns.sort(this.headings.indexOf(e.parentNode)),t.preventDefault()))}),!1),this.options.rowNavigation?(this.dom.addEventListener("keydown",(t=>{t.key==="ArrowUp"?this.rows.cursor.previousElementSibling?(this.rows.setCursor(this.rows.cursor.previousElementSibling),t.preventDefault(),t.stopPropagation()):this.onFirstPage||this.page(this.currentPage-1,!0):t.key==="ArrowDown"?this.rows.cursor.nextElementSibling?(this.rows.setCursor(this.rows.cursor.nextElementSibling),t.preventDefault(),t.stopPropagation()):this.onLastPage||this.page(this.currentPage+1):["Enter"," "].includes(t.key)&&this.emit("datatable.selectrow",this.rows.cursor,t)})),this.body.addEventListener("mousedown",(t=>{if(this.body.matches(":focus")){const e=Array.from(this.body.rows).find((e=>e.contains(t.target)));this.emit("datatable.selectrow",e,t)}}))):this.body.addEventListener("mousedown",(t=>{const e=Array.from(this.body.rows).find((e=>e.contains(t.target)));this.emit("datatable.selectrow",e,t)})),window.addEventListener("resize",this.listeners.onResize)} - -onResize(){this.rect=this.container.getBoundingClientRect(),this.rect.width&&this.fixColumns()} - -setColumns(t){t||this.data.forEach((t=>{Array.from(t.cells).forEach((t=>{t.data=t.innerHTML}))})),this.options.columns&&this.headings.length&&this.options.columns.forEach((t=>{Array.isArray(t.select)||(t.select=[t.select]),t.hasOwnProperty("render")&&typeof t.render==="function"&&(this.selectedColumns=this.selectedColumns.concat(t.select),this.columnRenderers.push({columns:t.select,renderer:t.render})),t.select.forEach((e=>{const s=this.headings[e];s&&(t.type&&s.setAttribute("data-type",t.type),t.format&&s.setAttribute("data-format",t.format),t.hasOwnProperty("sortable")&&s.setAttribute("data-sortable",t.sortable),t.hasOwnProperty("hidden")&&!1!==t.hidden&&this.columns.hide([e]),t.hasOwnProperty("sort")&&t.select.length===1&&this.columns.sort(t.select[0],t.sort,!0))}))})),this.hasRows&&(this.data.forEach(((t,e)=>{t.dataIndex=e,Array.from(t.cells).forEach((t=>{t.data=t.innerHTML}))})),this.columns.rebuild()),this.renderHeader()} - -destroy(){this.dom.innerHTML=this.initialLayout,this.dom.classList.remove("dataTable-table"),this.wrapper.parentNode.replaceChild(this.dom,this.wrapper),this.initialized=!1,window.removeEventListener("resize",this.listeners.onResize)} - -update(){this.wrapper.classList.remove("dataTable-empty"),this.paginate(),this.renderPage(),this.links=[];let t=this.pages.length;for(;t--;){const e=t+1;this.links[t]=r(t===0?"active":"",e,e)}this.sorting=!1,this.renderPager(),this.rows.update(),this.emit("datatable.update")} - -paginate(){let t=this.activeRows;return this.searching&&(t=[],this.searchData.forEach((e=>t.push(this.activeRows[e])))),this.options.paging?this.pages=t.map(((e,s)=>s%this.options.perPage==0?t.slice(s,s+this.options.perPage):null)).filter((t=>t)):this.pages=[t],this.totalPages=this.lastPage=this.pages.length,this.totalPages} - -fixColumns(){if((this.options.scrollY.length||this.options.fixedColumns)&&this.activeHeadings&&this.activeHeadings.length){let t; let e=!1;if(this.columnWidths=[],this.dom.tHead){this.options.scrollY.length&&(e=n("thead"),e.appendChild(n("tr")),e.style.height="0px",this.headerTable&&(this.dom.tHead=this.headerTable.tHead)),this.activeHeadings.forEach((t=>{t.style.width=""}));const t=this.activeHeadings.reduce(((t,e)=>t+e.offsetWidth),0);if(this.activeHeadings.forEach(((s,i)=>{const a=s.offsetWidth; const o=a/t*100;if(s.style.width=`${o}%`,this.columnWidths[i]=a,this.options.scrollY.length){const t=n("th");e.firstElementChild.appendChild(t),t.style.width=`${o}%`,t.style.paddingTop="0",t.style.paddingBottom="0",t.style.border="0"}})),this.options.scrollY.length){const t=this.dom.parentElement;if(!this.headerTable){this.headerTable=n("table",{class:"dataTable-table"});const e=n("div",{class:"dataTable-headercontainer"});e.appendChild(this.headerTable),t.parentElement.insertBefore(e,t)}const s=this.dom.tHead;this.dom.replaceChild(e,s),this.headerTable.tHead=s,this.headerTable.parentElement.style.paddingRight=`${this.headerTable.clientWidth-this.dom.clientWidth+parseInt(this.headerTable.parentElement.style.paddingRight||"0",10)}px`,t.scrollHeight>t.clientHeight&&(t.style.overflowY="scroll")}}else{t=[],e=n("thead");const s=n("tr");Array.from(this.dom.tBodies[0].rows[0].cells).forEach((()=>{const e=n("th");s.appendChild(e),t.push(e)})),e.appendChild(s),this.dom.insertBefore(e,this.body);const i=[];t.forEach(((t,e)=>{const s=t.offsetWidth; const a=s/this.rect.width*100;i.push(a),this.columnWidths[e]=s})),this.data.forEach((t=>{Array.from(t.cells).forEach(((t,e)=>{this.columns.visible(t.cellIndex)&&(t.style.width=`${i[e]}%`)}))})),this.dom.removeChild(e)}}} - -fixHeight(){this.options.fixedHeight&&(this.container.style.height=null,this.rect=this.container.getBoundingClientRect(),this.container.style.height=`${this.rect.height}px`)} - -search(t){return!!this.hasRows&&(t=t.toLowerCase(),this.currentPage=1,this.searching=!0,this.searchData=[],t.length?(this.clear(),this.data.forEach(((e,s)=>{const i=this.searchData.includes(e);t.split(" ").reduce(((t,s)=>{let i=!1; let a=null; let n=null;for(let t=0;tthis.pages.length||t<0)&&(this.renderPage(e),this.renderPager(),void this.emit("datatable.page",t)))} - -sortColumn(t,e){this.columns.sort(t,e)} - -insert(t){let e=[];if(i(t)){if(t.headings&&!this.hasHeadings&&!this.hasRows){const e=n("tr");t.headings.forEach((t=>{const s=n("th",{html:t});e.appendChild(s)})),this.head.appendChild(e),this.header=e,this.headings=[].slice.call(e.cells),this.hasHeadings=!0,this.options.sortable=this.initialSortable,this.renderHeader(),this.activeHeadings=this.headings.slice()}t.data&&Array.isArray(t.data)&&(e=t.data)}else Array.isArray(t)&&t.forEach((t=>{const s=[];Object.entries(t).forEach((([t,e])=>{const i=this.labels.indexOf(t);i>-1&&(s[i]=e)})),e.push(s)}));e.length&&(this.rows.add(e),this.hasRows=!0),this.update(),this.setColumns(),this.fixColumns()} - -refresh(){this.options.searchable&&(this.input.value="",this.searching=!1),this.currentPage=1,this.onFirstPage=!0,this.update(),this.emit("datatable.refresh")} - -clear(t){this.body&&o(this.body);let e=this.body;this.body||(e=this.dom),t&&(typeof t==="string"&&(document.createDocumentFragment().innerHTML=t),e.appendChild(t))} - -print(){const t=this.activeHeadings; const e=this.activeRows; const s=n("table"); const i=n("thead"); const a=n("tbody"); const o=n("tr");t.forEach((t=>{o.appendChild(n("th",{html:t.textContent}))})),i.appendChild(o),e.forEach((t=>{const e=n("tr");Array.from(t.cells).forEach((t=>{e.appendChild(n("td",{html:t.textContent}))})),a.appendChild(e)})),s.appendChild(i),s.appendChild(a);const r=window.open();r.document.body.appendChild(s),r.print()} - -setMessage(t){let e=1;this.hasRows?e=this.data[0].cells.length:this.activeHeadings.length&&(e=this.activeHeadings.length),this.wrapper.classList.add("dataTable-empty"),this.label&&(this.label.innerHTML=""),this.totalPages=0,this.renderPager(),this.clear(n("tr",{html:`${t}`}))} - -on(t,e){this.events=this.events||{},this.events[t]=this.events[t]||[],this.events[t].push(e)} - -off(t,e){this.events=this.events||{},t in this.events!=0&&this.events[t].splice(this.events[t].indexOf(e),1)} - -emit(t){if(this.events=this.events||{},t in this.events!=0)for(let e=0;et.trim().replace(/(^"|"$)/g,"")))),t.shift()),t.forEach(((t,i)=>{e.data[i]=[];const a=t.split(s.columnDelimiter);a.length&&a.forEach((t=>{s.removeDoubleQuotes&&(t=t.trim().replace(/(^"|"$)/g,"")),e.data[i].push(t)}))}))),e)return e}return!1},s.convertJSON=function(t={}){let e=!1;if(!i(t))return!1;const s={...t};if(s.data.length||i(s.data)){const t=a(s.data);if(t?(e={headings:[],data:[]},t.forEach(((t,s)=>{e.data[s]=[],Object.entries(t).forEach((([t,i])=>{e.headings.includes(t)||e.headings.push(t),e.data[s].push(i)}))}))):console.warn("That's not valid JSON!"),e)return e}return!1},s.createElement=n,s.exportCSV=function(t,e={}){if(!t.hasHeadings&&!t.hasRows)return!1;const s=t.activeHeadings;let a; let n; let o; let r; let l=[];if(!i(e))return!1;const h={download:!0,skipColumn:[],lineDelimiter:"\n",columnDelimiter:",",...e};if(l[0]=t.header,h.selection)if(isNaN(h.selection)){if(Array.isArray(h.selection))for(a=0;as.init())),s}},{"./date-7061ceee.js":1}]},{},[2])(2))); -// # sourceMappingURL=/sm/ecd7e55334cc99506bcb5e8cc047ef01e68c1dcb40a0d23a5d482f195c93ec51.map \ No newline at end of file diff --git a/ereuse_devicehub/templates/ereuse_devicehub/base.html b/ereuse_devicehub/templates/ereuse_devicehub/base.html index 85063560..6c54dd49 100644 --- a/ereuse_devicehub/templates/ereuse_devicehub/base.html +++ b/ereuse_devicehub/templates/ereuse_devicehub/base.html @@ -19,12 +19,14 @@ - + + + - + From 6b9965f57e2053914326b858a9eca133f9f466a1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 28 Feb 2023 17:25:20 +0100 Subject: [PATCH 61/84] drop pdbs --- ereuse_devicehub/resources/action/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index f1bbb5dd..b723bab8 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -514,7 +514,6 @@ class EraseSectors(EraseBasic): method = 'Badblocks' def get_public_name(self): - # import pdb; pdb.set_trace() steps_random = 0 steps_zeros = 0 for s in self.steps: From be271d59eafab9d1ee027dcc62a94791012bf180 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 28 Feb 2023 17:25:42 +0100 Subject: [PATCH 62/84] fix test render --- ereuse_devicehub/inventory/views.py | 12 ++++++------ tests/test_render_2_0.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 26a4d6e1..835f95e6 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1058,20 +1058,20 @@ class ExportsView(View): erasures.append(device.privacy) return erasures - def get_custum_details(self): + def get_costum_details(self): my_data = None customer_details = None if hasattr(g.user, 'sanitization_entity'): if g.user.sanitization_entity: my_data = list(g.user.sanitization_entity)[0] - if len(request.referrer.split('/lot/')) > 1: - try: + try: + if len(request.referrer.split('/lot/')) > 1: lot_id = request.referrer.split('/lot/')[-1].split('/')[0] lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first() customer_details = lot.transfer.customer_details - except Exception: - pass + except Exception: + pass return my_data, customer_details def get_server_erasure_hosts(self, erasures): @@ -1094,7 +1094,7 @@ class ExportsView(View): erasures[0].snapshot.version, ) - my_data, customer_details = self.get_custum_details() + my_data, customer_details = self.get_costum_details() a, b = self.get_server_erasure_hosts(erasures) erasures_host, erasures_on_server = a, b diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index dc4a7cf2..c84ad143 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -320,7 +320,7 @@ def test_export_certificates(user3: UserClientFlask): body = str(next(body)) assert status == '200 OK' assert "PDF-1.5" in body - assert 'hts54322' in body + assert 'e2024242cv86mm'.upper() in body @pytest.mark.mvp From 5bfd69f785535abfeefd3abfb500d1a01a85be96 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 3 Mar 2023 10:11:18 +0100 Subject: [PATCH 63/84] fix customer name in pdf --- ereuse_devicehub/templates/inventory/erasure.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 2ccd2ad1..bbb870b1 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -101,7 +101,7 @@ Name: - {{ ustomer_details and customer_details.company_name or ''}} + {{ customer_details and customer_details.company_name or ''}} From 1e62af56a63ccbea94d8c5f65f51c32d9d42c558 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 3 Mar 2023 16:00:54 +0100 Subject: [PATCH 64/84] fix parent --- ereuse_devicehub/templates/inventory/erasure.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index bbb870b1..76df0694 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -359,6 +359,7 @@
Data storage:
{{ erasure.device.__format__('ts') }}
+ {% if erasure.parent %}
Computer where was erase:
Title: {{ erasure.parent.__format__('ts') }}
DevicehubID: {{ erasure.parent.dhid }}
@@ -370,6 +371,7 @@
DevicehubID: {{ erasure.device.parent.dhid }}
Hid: {{ erasure.device.parent.hid }}
Tags: {{ erasure.device.parent.tags }}
+ {% endif %}
Erasure:
{{ erasure.__format__('ts') }}
From 0ff2bcae92745f567da98d6cc85cba7f3da3472e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 7 Mar 2023 16:39:52 +0100 Subject: [PATCH 65/84] use populate_obj --- ereuse_devicehub/forms.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 895160c5..495446b8 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -141,15 +141,17 @@ class SanitizationEntityForm(FlaskForm): return True def save(self, commit=True): - sanitation_data = SanitizationEntity( - logo=URL(self.logo.data), - company_name=self.company_name.data, - location=self.location.data, - responsable_person=self.responsable_person.data, - supervisor_person=self.supervisor_person.data, - user=g.user, - ) - db.session.add(sanitation_data) + if isinstance(self.logo.data, str): + self.logo.data = URL(self.logo.data) + + sanitation_data = SanitizationEntity.query.filter_by(user_id=g.user.id).first() + + if not sanitation_data: + sanitation_data = SanitizationEntity(user_id=g.user.id) + self.populate_obj(sanitation_data) + db.session.add(sanitation_data) + else: + self.populate_obj(sanitation_data) if commit: db.session.commit() From 7534df083cf1e8eab498dc674eaf0ba5ca1256e8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 7 Mar 2023 16:40:45 +0100 Subject: [PATCH 66/84] fix definition of model SanitizationEntity --- ereuse_devicehub/resources/user/models.py | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index 14e1c7ad..351907a8 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -1,11 +1,12 @@ from uuid import uuid4 from flask import current_app as app +from flask import g from flask_login import UserMixin from sqlalchemy import BigInteger, Boolean, Column, Sequence from sqlalchemy.dialects.postgresql import UUID from sqlalchemy_utils import EmailType, PasswordType -from teal.db import URL, IntEnum +from teal.db import CASCADE_OWN, URL, IntEnum from ereuse_devicehub.db import db from ereuse_devicehub.resources.enums import SessionType @@ -122,18 +123,24 @@ class Session(Thing): class SanitizationEntity(Thing): - id = Column(BigInteger, primary_key=True) - company_name = Column(db.String, nullable=True) - location = Column(db.String, nullable=True) - logo = Column(db.String, nullable=True) - logo = Column(URL(), nullable=True) - responsable_person = Column(db.String, nullable=True) - supervisor_person = Column(db.String, nullable=True) - user_id = db.Column(db.UUID(as_uuid=True), db.ForeignKey(User.id)) + id = db.Column(BigInteger, primary_key=True) + company_name = db.Column(db.String, nullable=True) + location = db.Column(db.String, nullable=True) + # logo = db.Column(db.String, nullable=True) + logo = db.Column(URL(), nullable=True) + responsable_person = db.Column(db.String, nullable=True) + supervisor_person = db.Column(db.String, nullable=True) + user_id = db.Column( + db.UUID(as_uuid=True), + db.ForeignKey(User.id), + default=lambda: g.user.id, + ) user = db.relationship( User, - backref=db.backref('sanitization_entity', lazy=True, collection_class=set), - collection_class=set, + backref=db.backref( + 'sanitization_entity', lazy=True, uselist=False, cascade=CASCADE_OWN + ), + primaryjoin=user_id == User.id, ) def __str__(self) -> str: From eed1075771dee95a673cda90328ad93318154d9f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 7 Mar 2023 16:41:24 +0100 Subject: [PATCH 67/84] save with commit for default --- ereuse_devicehub/views.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index f2cd4bc1..5d3861d9 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -102,7 +102,7 @@ class UserProfileView(GenericMixin): self.get_context() sanitization_form = SanitizationEntityForm() if g.user.sanitization_entity: - sanitization = list(g.user.sanitization_entity)[0] + sanitization = g.user.sanitization_entity sanitization_form = SanitizationEntityForm(obj=sanitization) self.context.update( { @@ -138,14 +138,13 @@ class SanitizationEntityView(View): def dispatch_request(self): form = SanitizationEntityForm() - db.session.commit() if form.validate_on_submit(): - form.save(commit=False) + form.save() messages.success('Sanitization datas updated successfully!') else: messages.error('Error modifying Sanitization datas!') - db.session.commit() + # db.session.commit() return flask.redirect(flask.url_for('core.user-profile')) From ab6f89c3d2e7231c389954613fac4563d277f902 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 8 Mar 2023 10:58:28 +0100 Subject: [PATCH 68/84] fix sanitization_entity in view --- ereuse_devicehub/inventory/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 835f95e6..4522c5b5 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1062,8 +1062,7 @@ class ExportsView(View): my_data = None customer_details = None if hasattr(g.user, 'sanitization_entity'): - if g.user.sanitization_entity: - my_data = list(g.user.sanitization_entity)[0] + my_data = g.user.sanitization_entity try: if len(request.referrer.split('/lot/')) > 1: From eb945ae348264eaf44f07a1e47c971b0e676c17b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 8 Mar 2023 12:34:52 +0100 Subject: [PATCH 69/84] fix ortigraphy --- ereuse_devicehub/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 5d3861d9..915a4dc4 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -140,9 +140,9 @@ class SanitizationEntityView(View): form = SanitizationEntityForm() if form.validate_on_submit(): form.save() - messages.success('Sanitization datas updated successfully!') + messages.success('Sanitization data updated successfully!') else: - messages.error('Error modifying Sanitization datas!') + messages.error('Error modifying Sanitization data!') # db.session.commit() return flask.redirect(flask.url_for('core.user-profile')) From 54372ad2f90ee674d66b7749cd10525644e4b9ba Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 8 Mar 2023 12:43:37 +0100 Subject: [PATCH 70/84] put comment as placeholder in field of logo --- ereuse_devicehub/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 495446b8..68485f33 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -116,7 +116,10 @@ class SanitizationEntityForm(FlaskForm): logo = URLField( 'Logo', [validators.Optional(), validators.URL()], - render_kw={'class': "form-control"}, + render_kw={ + 'class': "form-control", + "placeholder": "Url where is the logo - acceptd only .png, .jpg, .gif, svg", + }, ) company_name = StringField('Company Name', render_kw={'class': "form-control"}) location = StringField('Location', render_kw={'class': "form-control"}) From 40a151df5a434eb3a409ead174792c593035508a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 8 Mar 2023 17:22:26 +0100 Subject: [PATCH 71/84] fix order of devices --- ereuse_devicehub/inventory/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 4522c5b5..675409b4 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1102,6 +1102,12 @@ class ExportsView(View): if "Failed" in [e.severity.get_public_name() for e in erasures]: result = 'Failed' + erasures = sorted(erasures, key=lambda x: x.end_time) + erasures_on_server = sorted(erasures_on_server, key=lambda x: x.end_time) + erasures_host = sorted(erasures_host, key=lambda x: x.end_time) + erasures_normal = list(set(erasures) - set(erasures_on_server)) + erasures_normal = sorted(erasures_normal, key=lambda x: x.end_time) + params = { 'title': 'Erasure Certificate', 'erasures': tuple(erasures), @@ -1114,7 +1120,7 @@ class ExportsView(View): 'result': result, 'customer_details': customer_details, 'erasure_hosts': erasures_host, - 'erasures_normal': list(set(erasures) - set(erasures_on_server)), + 'erasures_normal': erasures_normal, } return flask.render_template('inventory/erasure.html', **params) From de24cae235a58974c755807125217ad464e6569a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 9 Mar 2023 10:43:35 +0100 Subject: [PATCH 72/84] add placeholder --- ereuse_devicehub/inventory/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index fc475f6e..a4504f17 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1539,7 +1539,10 @@ class CustomerDetailsForm(FlaskForm): logo = URLField( 'Logo', [validators.Optional()], - render_kw={'class': "form-control"}, + render_kw={ + 'class': "form-control", + "placeholder": "Url where is the logo - acceptd only .png, .jpg, .gif, svg", + }, description="Url where is the logo", ) From 6b0110addab6e75f2a3c2878e61c9902f6ccfebb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 9 Mar 2023 12:40:46 +0100 Subject: [PATCH 73/84] fix server report --- ereuse_devicehub/inventory/views.py | 3 ++- ereuse_devicehub/templates/inventory/erasure.html | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 675409b4..081d42c4 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1097,6 +1097,7 @@ class ExportsView(View): a, b = self.get_server_erasure_hosts(erasures) erasures_host, erasures_on_server = a, b + erasures_host = set(erasures_host) result = 'Success' if "Failed" in [e.severity.get_public_name() for e in erasures]: @@ -1104,7 +1105,7 @@ class ExportsView(View): erasures = sorted(erasures, key=lambda x: x.end_time) erasures_on_server = sorted(erasures_on_server, key=lambda x: x.end_time) - erasures_host = sorted(erasures_host, key=lambda x: x.end_time) + # import pdb; pdb.set_trace() erasures_normal = list(set(erasures) - set(erasures_on_server)) erasures_normal = sorted(erasures_normal, key=lambda x: x.end_time) diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 76df0694..c6b40d12 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -366,12 +366,14 @@
Hid: {{ erasure.parent.hid }}
Tags: {{ erasure.parent.tags }}
+ {% if erasure.device.parent %}
Computer where it resides:
Title: {{ erasure.device.parent.__format__('ts') }}
DevicehubID: {{ erasure.device.parent.dhid }}
Hid: {{ erasure.device.parent.hid }}
Tags: {{ erasure.device.parent.tags }}
- {% endif %} + {% endif %} + {% endif %}
Erasure:
{{ erasure.__format__('ts') }}
From 93d6502a66709081d139ea8295f4aa3fa960b32d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 9 Mar 2023 13:09:05 +0100 Subject: [PATCH 74/84] fix server report n_computers --- ereuse_devicehub/inventory/views.py | 4 ++-- ereuse_devicehub/templates/inventory/erasure.html | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 081d42c4..89d0bdac 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1105,9 +1105,9 @@ class ExportsView(View): erasures = sorted(erasures, key=lambda x: x.end_time) erasures_on_server = sorted(erasures_on_server, key=lambda x: x.end_time) - # import pdb; pdb.set_trace() erasures_normal = list(set(erasures) - set(erasures_on_server)) erasures_normal = sorted(erasures_normal, key=lambda x: x.end_time) + n_computers = len({x.parent for x in erasures} - erasures_host) params = { 'title': 'Erasure Certificate', @@ -1117,7 +1117,7 @@ class ExportsView(View): 'uuid_report': '{}'.format(uuid.uuid4()), 'software': software, 'my_data': my_data, - 'n_computers': len(set([x.parent for x in erasures])), + 'n_computers': n_computers, 'result': result, 'customer_details': customer_details, 'erasure_hosts': erasures_host, diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index c6b40d12..7b8ae650 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -159,19 +159,20 @@ {% if erasure_hosts %} - {% for e in erasure_hosts %} - {% endfor %} - {% else %} + {% endif %} + {% if n_computers %}
- N° of sanitization server ({{ loop.index }}/{{ erasure_hosts|length }}): + N° of sanitization server {{ erasure_hosts|length }}: + {% for e in erasure_hosts %} {% if e.serial_number %} - {{ e.serial_number.upper() }} + {{ e.serial_number.upper() }}{% if not loop.last %},{% endif %} {% endif %} + {% endfor %}
N° of computers: @@ -245,7 +246,7 @@ -
+
From 6d722bb19f33c82f5b65923f09be669a5bb5e480 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 9 Mar 2023 18:07:16 +0100 Subject: [PATCH 75/84] feedback when there are one error in sanitization form --- ereuse_devicehub/forms.py | 6 ++++++ ereuse_devicehub/inventory/forms.py | 12 +++++++++++- ereuse_devicehub/views.py | 5 ++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 68485f33..4980b41e 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -141,6 +141,12 @@ class SanitizationEntityForm(FlaskForm): if not is_valid: return False + extensions = ["jpg", "jpeg", "png", "gif", "svg"] + if self.logo.data.lower().split(".")[-1] not in extensions: + txt = "Error in Url field - accepted only .PNG, .JPG and .GIF. extensions" + self.logo.errors = [txt] + return False + return True def save(self, commit=True): diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index a4504f17..dff4e87e 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1561,7 +1561,17 @@ class CustomerDetailsForm(FlaskForm): def validate(self, extra_validators=None): is_valid = super().validate(extra_validators) - return is_valid + + if not is_valid: + return is_valid + + extensions = ["jpg", "jpeg", "png", "gif", "svg"] + if self.logo.data.lower().split(".")[-1] not in extensions: + txt = "Error in Url field - accepted only .PNG, .JPG and .GIF. extensions" + self.logo.errors = [txt] + return False + + return True def save(self, commit=True): self.populate_obj(self._obj) diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 915a4dc4..65cb4d3a 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -143,8 +143,11 @@ class SanitizationEntityView(View): messages.success('Sanitization data updated successfully!') else: messages.error('Error modifying Sanitization data!') + if form.errors: + for k in form.errors.keys(): + txt = "{}: {}".format(k, form.errors[k]) + messages.error(txt) - # db.session.commit() return flask.redirect(flask.url_for('core.user-profile')) From 20ccb385d847827798dc652770606cf6a2151c8b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 9 Mar 2023 18:38:54 +0100 Subject: [PATCH 76/84] add lots in list of erasures actions --- ereuse_devicehub/resources/device/models.py | 6 ++++++ ereuse_devicehub/templates/inventory/erasure_list.html | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 8d2baec1..168c4371 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -676,6 +676,12 @@ class Device(Thing): return args def get_lots_for_template(self): + if self.binding: + return self.binding.device.get_lots_for_template() + + if not self.lots and hasattr(self, 'parent') and self.parent: + return self.parent.get_lots_for_template() + lots = [] for lot in self.lots: if lot.is_incoming: diff --git a/ereuse_devicehub/templates/inventory/erasure_list.html b/ereuse_devicehub/templates/inventory/erasure_list.html index 2f36de71..e2154c3e 100644 --- a/ereuse_devicehub/templates/inventory/erasure_list.html +++ b/ereuse_devicehub/templates/inventory/erasure_list.html @@ -187,9 +187,9 @@ {% endif %} {{ ac.device.serial_number.upper() }} {% endif %} - {% if ac.device.my_partner.lots | length > 0 %} + {% if ac.device.get_lots_for_template() | length > 0 %}
- {% for lot in ac.device.my_partner.get_lots_for_template() %} + {% for lot in ac.device.get_lots_for_template() %} {{ lot }} {% endfor %}
From 1c82fcfa3081909e29f725b98ed5a72829e0ecdb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 10 Mar 2023 18:34:09 +0100 Subject: [PATCH 77/84] add customer details for default if there are more than one incoming lot --- ereuse_devicehub/inventory/views.py | 22 +++++++++++++++++++-- ereuse_devicehub/resources/device/models.py | 12 +++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 89d0bdac..57bab6d7 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1058,9 +1058,10 @@ class ExportsView(View): erasures.append(device.privacy) return erasures - def get_costum_details(self): + def get_costum_details(self, erasures): my_data = None customer_details = None + lot = None if hasattr(g.user, 'sanitization_entity'): my_data = g.user.sanitization_entity @@ -1071,6 +1072,23 @@ class ExportsView(View): customer_details = lot.transfer.customer_details except Exception: pass + + if lot or not erasures: + return my_data, customer_details + + init = erasures[0].device.get_set_lots() + for e in erasures: + init = init.intersection(e.device.get_set_lots()) + + if len(init) != 1: + return my_data, customer_details + + lot = init.pop() + try: + customer_details = lot.transfer.customer_details + except Exception: + pass + return my_data, customer_details def get_server_erasure_hosts(self, erasures): @@ -1093,7 +1111,7 @@ class ExportsView(View): erasures[0].snapshot.version, ) - my_data, customer_details = self.get_costum_details() + my_data, customer_details = self.get_costum_details(erasures) a, b = self.get_server_erasure_hosts(erasures) erasures_host, erasures_on_server = a, b diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 168c4371..1e3d4b12 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1021,6 +1021,18 @@ class Device(Thing): return + def get_set_lots(self): + if self.lots: + return set(self.lots) + + if hasattr(self, "parent") and self.parent and self.parent.lots: + return set(self.parent.lots) + + if self.binding: + return self.binding.device.get_set_lots() + + return set() + def __lt__(self, other): return self.id < other.id From ba02351f59082ce526be430ecf03d41ec31982d7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 10 Mar 2023 20:13:54 +0100 Subject: [PATCH 78/84] fix lots --- ereuse_devicehub/resources/device/models.py | 13 ++--- .../templates/inventory/erasure.html | 52 ++----------------- 2 files changed, 11 insertions(+), 54 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 1e3d4b12..3bb98ffb 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1022,16 +1022,17 @@ class Device(Thing): return def get_set_lots(self): - if self.lots: + if hasattr(self, "orphan") and self.orphan: + if self.binding: + return set(self.binding.device.lots) return set(self.lots) - if hasattr(self, "parent") and self.parent and self.parent.lots: + if hasattr(self, "parent") and self.parent: + if self.parent.binding: + return set(self.parent.binding.device.lots) return set(self.parent.lots) - if self.binding: - return self.binding.device.get_set_lots() - - return set() + return set(self.lots) def __lt__(self, other): return self.id < other.id diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index 7b8ae650..a5eb0039 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -161,7 +161,7 @@ {% if erasure_hosts %}
+ @@ -290,51 +286,12 @@ {% for erasure in erasures %} - {% if erasure.parent == server %} - - - - {% endif %} - {% endfor %} - -
- N° of sanitization server {{ erasure_hosts|length }}: + SNs; of sanitization server {{ erasure_hosts|length }}: {% for e in erasure_hosts %} @@ -267,14 +267,9 @@ {% if erasures %} - {% if erasure_hosts %} - {% for server in erasure_hosts %}
-

Server Summary

-
-
-

SN Server {{ server.serial_number and server.serial_number.upper() }}

+

Summary

@@ -283,6 +278,7 @@
SN StorageSN Host Method Result Date
{{ erasure.device.serial_number.upper() }} - {{ erasure.get_public_name() }} - - {{ erasure.severity.get_public_name() }} - - {{ erasure.date_str }} -
-
-
- {% endfor %} - {% endif %} - {% if erasures_normal %} -
-
-

Devices Summary

-
-
-
-
- - - - - - - - - - - {% for erasure in erasures_normal %} - -
SN StorageMethodResultDate
- {{ erasure.device.serial_number.upper() }} + {{ erasure.parent.serial_number.upper() }} {{ erasure.get_public_name() }} @@ -351,7 +308,6 @@
- {% endif %}
{% for erasure in erasures %}
From cf5150b7c9d93cad2032c7753f8e7a89ba8ceb0f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 10 Mar 2023 21:15:00 +0100 Subject: [PATCH 79/84] fix lots --- ereuse_devicehub/inventory/views.py | 38 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 57bab6d7..91ea99cc 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1062,35 +1062,45 @@ class ExportsView(View): my_data = None customer_details = None lot = None + if hasattr(g.user, 'sanitization_entity'): my_data = g.user.sanitization_entity - try: - if len(request.referrer.split('/lot/')) > 1: - lot_id = request.referrer.split('/lot/')[-1].split('/')[0] - lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first() - customer_details = lot.transfer.customer_details - except Exception: - pass + customer_details = self.get_customer_details_from_request() - if lot or not erasures: + if not erasures or customer_details: return my_data, customer_details init = erasures[0].device.get_set_lots() for e in erasures: init = init.intersection(e.device.get_set_lots()) - if len(init) != 1: + if not len(init): return my_data, customer_details - lot = init.pop() - try: - customer_details = lot.transfer.customer_details - except Exception: - pass + lots = sorted(list(init), key=lambda x: x.created) + lots.reverse() + for lot in lots: + try: + customer_details = lot.transfer.customer_details + if customer_details: + return my_data, customer_details + except Exception: + continue return my_data, customer_details + def get_customer_details_from_request(self): + if len(request.referrer.split('/lot/')) < 2: + return + + try: + lot_id = request.referrer.split('/lot/')[-1].split('/')[0] + lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first() + return lot.transfer.customer_details + except Exception: + pass + def get_server_erasure_hosts(self, erasures): erasures_host = [] erasures_on_server = [] From 498d2ec92ff66bc5ac5c608a5f5e39891a937974 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 10 Mar 2023 21:56:17 +0100 Subject: [PATCH 80/84] fix test --- ereuse_devicehub/inventory/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 91ea99cc..5ebabaa5 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1091,10 +1091,10 @@ class ExportsView(View): return my_data, customer_details def get_customer_details_from_request(self): - if len(request.referrer.split('/lot/')) < 2: - return - try: + if len(request.referrer.split('/lot/')) < 2: + return + lot_id = request.referrer.split('/lot/')[-1].split('/')[0] lot = Lot.query.filter_by(owner=g.user).filter_by(id=lot_id).first() return lot.transfer.customer_details From d0688cc75172306f0e0f036a6b43a04c68482db3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 13 Mar 2023 12:24:57 +0100 Subject: [PATCH 81/84] fix with last lot incoming --- ereuse_devicehub/inventory/views.py | 22 ++++++++----------- ereuse_devicehub/resources/device/models.py | 20 +++++++++++------ .../templates/inventory/erasure.html | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 5ebabaa5..b03cd345 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1071,22 +1071,18 @@ class ExportsView(View): if not erasures or customer_details: return my_data, customer_details - init = erasures[0].device.get_set_lots() - for e in erasures: - init = init.intersection(e.device.get_set_lots()) + lots = {erasures[0].device.get_last_incoming_lot()} + for e in erasures[1:]: + lots.add(e.device.get_last_incoming_lot()) - if not len(init): + if len(lots) != 1: return my_data, customer_details - lots = sorted(list(init), key=lambda x: x.created) - lots.reverse() - for lot in lots: - try: - customer_details = lot.transfer.customer_details - if customer_details: - return my_data, customer_details - except Exception: - continue + lot = lots.pop() + try: + customer_details = lot.transfer.customer_details + except Exception: + pass return my_data, customer_details diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 3bb98ffb..a0ba0f20 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1021,18 +1021,24 @@ class Device(Thing): return - def get_set_lots(self): + def get_last_incoming_lot(self): + lots = list(self.lots) if hasattr(self, "orphan") and self.orphan: + lots = list(self.lots) if self.binding: - return set(self.binding.device.lots) - return set(self.lots) + lots = list(self.binding.device.lots) - if hasattr(self, "parent") and self.parent: + elif hasattr(self, "parent") and self.parent: + lots = list(self.parent.lots) if self.parent.binding: - return set(self.parent.binding.device.lots) - return set(self.parent.lots) + lots = list(self.parent.binding.device.lots) - return set(self.lots) + lots = sorted(lots, key=lambda x: x.created) + lots.reverse() + for lot in lots: + if lot.is_incoming: + return lot + return None def __lt__(self, other): return self.id < other.id diff --git a/ereuse_devicehub/templates/inventory/erasure.html b/ereuse_devicehub/templates/inventory/erasure.html index a5eb0039..06ad6943 100644 --- a/ereuse_devicehub/templates/inventory/erasure.html +++ b/ereuse_devicehub/templates/inventory/erasure.html @@ -161,7 +161,7 @@ {% if erasure_hosts %}
- SNs; of sanitization server {{ erasure_hosts|length }}: + SNs of sanitization server: {% for e in erasure_hosts %} From b140dc5f899be61bca36b56914d0f72320d88a17 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 13 Mar 2023 17:04:57 +0100 Subject: [PATCH 82/84] fix without logo --- ereuse_devicehub/forms.py | 3 +++ ereuse_devicehub/inventory/forms.py | 3 +++ ereuse_devicehub/views.py | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/forms.py b/ereuse_devicehub/forms.py index 4980b41e..ef383588 100644 --- a/ereuse_devicehub/forms.py +++ b/ereuse_devicehub/forms.py @@ -141,6 +141,9 @@ class SanitizationEntityForm(FlaskForm): if not is_valid: return False + if not self.logo.data: + return True + extensions = ["jpg", "jpeg", "png", "gif", "svg"] if self.logo.data.lower().split(".")[-1] not in extensions: txt = "Error in Url field - accepted only .PNG, .JPG and .GIF. extensions" diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index dff4e87e..ffb8d13c 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -1565,6 +1565,9 @@ class CustomerDetailsForm(FlaskForm): if not is_valid: return is_valid + if not self.logo.data: + return True + extensions = ["jpg", "jpeg", "png", "gif", "svg"] if self.logo.data.lower().split(".")[-1] not in extensions: txt = "Error in Url field - accepted only .PNG, .JPG and .GIF. extensions" diff --git a/ereuse_devicehub/views.py b/ereuse_devicehub/views.py index 65cb4d3a..8f9a5e1d 100644 --- a/ereuse_devicehub/views.py +++ b/ereuse_devicehub/views.py @@ -145,7 +145,8 @@ class SanitizationEntityView(View): messages.error('Error modifying Sanitization data!') if form.errors: for k in form.errors.keys(): - txt = "{}: {}".format(k, form.errors[k]) + errors = ", ".join(form.errors[k]) + txt = "{}: {}".format(k, errors) messages.error(txt) return flask.redirect(flask.url_for('core.user-profile')) From 21d251e6c03008b878af45dc549d445ba86b576a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 13 Mar 2023 17:52:00 +0100 Subject: [PATCH 83/84] add reopen transfer --- ereuse_devicehub/inventory/views.py | 19 +++++++++++++++ .../templates/inventory/device_list.html | 23 +++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index b03cd345..2526a850 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -841,6 +841,21 @@ class NewTransferView(GenericMixin): return flask.render_template(self.template_name, **self.context) +class OpenTransferView(GenericMixin): + methods = ['GET'] + + def dispatch_request(self, lot_id=None): + lot = Lot.query.filter_by(id=lot_id).one() + next_url = url_for('inventory.lotdevicelist', lot_id=str(lot_id)) + + if hasattr(lot, 'transfer'): + lot.transfer.date = None + db.session.commit() + messages.success('Transfer was reopen successfully!') + + return flask.redirect(next_url) + + class EditTransferView(GenericMixin): methods = ['POST'] form_class = EditTransferForm @@ -1601,3 +1616,7 @@ devices.add_url_rule( '/device/erasure//', view_func=ErasureListView.as_view('device_erasure_list_orphans'), ) +devices.add_url_rule( + '/lot//opentransfer/', + view_func=OpenTransferView.as_view('open_transfer'), +) diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index f89c93f6..7f5ac904 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -516,13 +516,13 @@ {% if lot and not lot.is_temporary %}
- +
Documents
@@ -565,6 +565,15 @@
+ {% if form_transfer.date.data %} + + {% endif %}
Transfer
{{ form_transfer.csrf_token }} From e7833c17275f4cf0b797b21d3045d0db4ab500d2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 13 Mar 2023 17:59:08 +0100 Subject: [PATCH 84/84] fix test --- tests/test_basic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_basic.py b/tests/test_basic.py index e9927a0e..4b734079 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -68,6 +68,7 @@ def test_api_docs(client: Client): '/inventory/lot/{lot_id}/receivernote/', '/inventory/lot/{lot_id}/trade-document/add/', '/inventory/lot/{lot_id}/transfer/{type_id}/', + '/inventory/lot/{lot_id}/opentransfer/', '/inventory/lot/{lot_id}/transfer/', '/inventory/lot/transfer/{type_id}/', '/inventory/lot/{lot_id}/upload-snapshot/',