diff --git a/CHANGELOG.md b/CHANGELOG.md index 01024d2d..3be890ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ml). ## master - [1.0.7-beta] + [1.0.8-beta] ## testing - [1.0.8-beta] + [1.0.9-beta] +- [addend] #159 external document as proof of erase of disk + + +## [1.0.8-beta] +- [bugfix] #161 fixing DataStorage with bigInteger ## [1.0.7-beta] - [addend] #158 support for encrypted snapshots data diff --git a/ereuse_devicehub/__init__.py b/ereuse_devicehub/__init__.py index 811df9bd..d44f1a11 100644 --- a/ereuse_devicehub/__init__.py +++ b/ereuse_devicehub/__init__.py @@ -1 +1 @@ -__version__ = "1.0.8-beta" +__version__ = "1.0.9-beta" diff --git a/ereuse_devicehub/migrations/versions/0103a9c96b2d_testdatastorage_bigintegers.py b/ereuse_devicehub/migrations/versions/0103a9c96b2d_testdatastorage_bigintegers.py new file mode 100644 index 00000000..e4f8d866 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/0103a9c96b2d_testdatastorage_bigintegers.py @@ -0,0 +1,38 @@ +"""TestDataStorage_bigIntegers + +Revision ID: 0103a9c96b2d +Revises: 3a3601ac8224 +Create Date: 2021-07-21 08:56:48.342503 + +""" +from alembic import op, context +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0103a9c96b2d' +down_revision = '3a3601ac8224' +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.alter_column('test_data_storage', 'reallocated_sector_count', type_=sa.BigInteger(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'power_cycle_count', type_=sa.Integer(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'reported_uncorrectable_errors', type_=sa.BigInteger(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'current_pending_sector_count', type_=sa.BigInteger(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'offline_uncorrectable', type_=sa.BigInteger(), schema=f'{get_inv()}') + + +def downgrade(): + op.alter_column('test_data_storage', 'reallocated_sector_count', type_=sa.SmallInteger(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'power_cycle_count', type_=sa.SmallInteger(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'reported_uncorrectable_errors', type_=sa.Integer(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'current_pending_sector_count', type_=sa.Integer(), schema=f'{get_inv()}') + op.alter_column('test_data_storage', 'offline_uncorrectable', type_=sa.Integer(), schema=f'{get_inv()}') diff --git a/ereuse_devicehub/migrations/versions/7ecb8ff7abad_documents.py b/ereuse_devicehub/migrations/versions/7ecb8ff7abad_documents.py new file mode 100644 index 00000000..83daaf61 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/7ecb8ff7abad_documents.py @@ -0,0 +1,85 @@ +"""documents + +Revision ID: 7ecb8ff7abad +Revises: 3a3601ac8224 +Create Date: 2021-07-19 14:46:42.375331 + +""" +from alembic import op +import sqlalchemy as sa +import sqlalchemy_utils +import citext +import teal + +from alembic import op +from alembic import context +from sqlalchemy.dialects import postgresql + + +# revision identifiers, used by Alembic. +revision = '7ecb8ff7abad' +down_revision = '0103a9c96b2d' +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(): + # Document table + op.create_table('document', + sa.Column('id', sa.BigInteger(), nullable=False), + sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, + comment='The last time Document recorded a change for \n this thing.\n '), + sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, comment='When Document created this.'), + sa.Column('document_type', sa.Unicode(), nullable=False), + sa.Column('date', sa.TIMESTAMP(timezone=True), nullable=True), + sa.Column('id_document', sa.Unicode(), nullable=True), + sa.Column('owner_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('file_name', sa.Unicode(), nullable=False), + sa.Column('file_hash', sa.Unicode(), nullable=False), + sa.Column('url', sa.Unicode(), nullable=True), + + sa.ForeignKeyConstraint(['owner_id'], ['common.user.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + op.create_index('generic_document_id', 'document', ['id'], unique=False, postgresql_using='hash', schema=f'{get_inv()}') + op.create_index(op.f('ix_document_created'), 'document', ['created'], unique=False, schema=f'{get_inv()}') + op.create_index(op.f('ix_document_updated'), 'document', ['updated'], unique=False, schema=f'{get_inv()}') + op.create_index('document_type_index', 'document', ['document_type'], unique=False, postgresql_using='hash', schema=f'{get_inv()}') + + + # DataWipeDocument table + op.create_table('data_wipe_document', + sa.Column('id', sa.BigInteger(), nullable=False), + sa.Column('software', sa.Unicode(), nullable=True), + sa.Column('success', sa.Boolean(), nullable=False), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.document.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + + + # DataWipe table + op.create_table('data_wipe', + sa.Column('document_id', sa.BigInteger(), nullable=False), + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.ForeignKeyConstraint(['document_id'], [f'{get_inv()}.document.id'], ), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + + +def downgrade(): + op.drop_table('data_wipe', schema=f'{get_inv()}') + op.drop_table('data_wipe_document', schema=f'{get_inv()}') + op.drop_table('document', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 5e581cd5..bdc55014 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -199,6 +199,11 @@ class ToPrepareDef(ActionDef): SCHEMA = schemas.ToPrepare +class DataWipeDef(ActionDef): + VIEW = None + SCHEMA = schemas.DataWipe + + class AllocateDef(ActionDef): VIEW = AllocateView SCHEMA = schemas.Allocate diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index d8bcb3ce..fdbdf1fa 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -754,12 +754,12 @@ class TestDataStorage(TestMixin, Test): status = Column(Unicode(), check_lower('status'), nullable=False) lifetime = Column(Interval) assessment = Column(Boolean) - reallocated_sector_count = Column(SmallInteger) - power_cycle_count = Column(SmallInteger) - _reported_uncorrectable_errors = Column('reported_uncorrectable_errors', Integer) + reallocated_sector_count = Column(BigInteger) + power_cycle_count = Column(Integer) + _reported_uncorrectable_errors = Column('reported_uncorrectable_errors', BigInteger) command_timeout = Column(BigInteger) - current_pending_sector_count = Column(Integer) - offline_uncorrectable = Column(Integer) + current_pending_sector_count = Column(BigInteger) + offline_uncorrectable = Column(BigInteger) remaining_lifetime_percentage = Column(SmallInteger) elapsed = Column(Interval, nullable=False) @@ -1327,6 +1327,20 @@ class ToPrepare(ActionWithMultipleDevices): pass +class DataWipe(JoinedTableMixin, ActionWithMultipleDevices): + """The device has been selected for insert one proof of erease disk. + """ + document_comment = """The user that gets the device due this deal.""" + document_id = db.Column(BigInteger, + db.ForeignKey('data_wipe_document.id'), + nullable=False) + document = db.relationship('DataWipeDocument', + backref=backref('actions', + lazy=True, + cascade=CASCADE_OWN), + primaryjoin='DataWipe.document_id == DataWipeDocument.id') + + class Prepare(ActionWithMultipleDevices): """Work has been performed to the device to a defined point of acceptance. diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 087af53d..3232f11b 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -17,6 +17,7 @@ from ereuse_devicehub.resources.action import models as m from ereuse_devicehub.resources.agent import schemas as s_agent from ereuse_devicehub.resources.device import schemas as s_device from ereuse_devicehub.resources.tradedocument import schemas as s_document +from ereuse_devicehub.resources.documents import schemas as s_generic_document from ereuse_devicehub.resources.enums import AppearanceRange, BiosAccessRange, FunctionalityRange, \ PhysicalErasureMethod, R_POSITIVE, RatingRange, \ Severity, SnapshotSoftware, TestDataStorageLength @@ -430,6 +431,11 @@ class Prepare(ActionWithMultipleDevices): __doc__ = m.Prepare.__doc__ +class DataWipe(ActionWithMultipleDevices): + __doc__ = m.DataWipe.__doc__ + document = NestedOn(s_generic_document.DataWipeDocument, only_query='id') + + class Live(ActionWithOneDevice): __doc__ = m.Live.__doc__ """ diff --git a/ereuse_devicehub/resources/action/views/documents.py b/ereuse_devicehub/resources/action/views/documents.py new file mode 100644 index 00000000..e1f685b5 --- /dev/null +++ b/ereuse_devicehub/resources/action/views/documents.py @@ -0,0 +1,52 @@ +import copy + +from ereuse_devicehub.db import db +from ereuse_devicehub.resources.action.models import DataWipe +from ereuse_devicehub.resources.documents.models import DataWipeDocument +from ereuse_devicehub.resources.device.models import DataStorage +from ereuse_devicehub.resources.documents.schemas import DataWipeDocument as sh_document +from ereuse_devicehub.resources.hash_reports import ReportHash + + +class ErasedView(): + """Handler for manager the action register for add to a device one proof of erase + """ + + def __init__(self, data, schema): + self.schema = schema + self.insert_document(copy.copy(data)) + self.insert_action(copy.copy(data)) + + def post(self): + db.session().final_flush() + from flask import jsonify + ret = jsonify(self.erased) + ret.status_code = 201 + db.session.commit() + return ret + + def insert_document(self, data): + schema = sh_document() + [data.pop(x, None) for x in ['severity', 'devices', 'name', 'description']] + doc_data = schema.load(data) + self.document = DataWipeDocument(**doc_data) + db.session.add(self.document) + + db_hash = ReportHash(hash3=self.document.file_hash) + db.session.add(db_hash) + + def insert_action(self, data): + [data.pop(x, None) for x in ['url', 'documentId', 'filename', 'hash', 'software', 'success']] + self.data = self.schema.load(data) + + for dev in self.data['devices']: + if not hasattr(dev, 'components'): + continue + + for component in dev.components: + if isinstance(component, DataStorage): + self.data['devices'].add(component) + + self.data['document'] = self.document + self.erased = DataWipe(**self.data) + db.session.add(self.erased) diff --git a/ereuse_devicehub/resources/action/views/views.py b/ereuse_devicehub/resources/action/views/views.py index e51a8e7a..415effb8 100644 --- a/ereuse_devicehub/resources/action/views/views.py +++ b/ereuse_devicehub/resources/action/views/views.py @@ -18,6 +18,7 @@ from ereuse_devicehub.resources.action.models import (Action, Snapshot, VisualTe Trade, Confirm, ConfirmRevoke, Revoke) from ereuse_devicehub.resources.action.views import trade as trade_view from ereuse_devicehub.resources.action.views.snapshot import SnapshotView, save_json, move_json +from ereuse_devicehub.resources.action.views.documents import ErasedView from ereuse_devicehub.resources.device.models import Device, Computer, DataStorage from ereuse_devicehub.resources.enums import Severity @@ -250,6 +251,10 @@ class ActionView(View): confirm_revoke = trade_view.ConfirmRevokeDocumentView(json, resource_def, self.schema) return confirm_revoke.post() + if json['type'] == 'DataWipe': + erased = ErasedView(json, resource_def.schema) + return erased.post() + a = resource_def.schema.load(json) Model = db.Model._decl_class_registry.data[json['type']]() action = Model(**a) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index ea585785..a0917bef 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -696,6 +696,25 @@ class Computer(Device): if privacy ) + @property + def external_document_erasure(self): + """Returns the external ``DataStorage`` proof of erasure. + """ + from ereuse_devicehub.resources.action.models import DataWipe + urls = set() + try: + ev = self.last_action_of(DataWipe) + urls.add(ev.document.url.to_text()) + except LookupError: + pass + + for comp in self.components: + if isinstance(comp, DataStorage): + doc = comp.external_document_erasure + if doc: + urls.add(doc) + return urls + def add_mac_to_hid(self, components_snap=None): """Returns the Naming.hid with the first mac of network adapter, following an alphabetical order. @@ -879,6 +898,17 @@ class DataStorage(JoinedComponentTableMixin, Component): v += ' – {} GB'.format(self.size // 1000 if self.size else '?') return v + @property + def external_document_erasure(self): + """Returns the external ``DataStorage`` proof of erasure. + """ + from ereuse_devicehub.resources.action.models import DataWipe + try: + ev = self.last_action_of(DataWipe) + return ev.document.url.to_text() + except LookupError: + return None + class HardDrive(DataStorage): pass diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index 875906d7..1e8d1aa7 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -52,7 +52,8 @@ class DeviceRow(OrderedDict): self['Tag 2 Type'] = self['Tag 2 ID'] = self['Tag 2 Organization'] = '' self['Tag 3 Type'] = self['Tag 3 ID'] = self['Tag 3 Organization'] = '' for i, tag in zip(range(1, 3), device.tags): - self['Tag {} Type'.format(i)] = 'unamed' if tag.provider else 'named' + self['Tag {} Type'.format( + i)] = 'unamed' if tag.provider else 'named' self['Tag {} ID'.format(i)] = tag.id self['Tag {} Organization'.format(i)] = tag.org.name @@ -70,11 +71,13 @@ class DeviceRow(OrderedDict): self['Updated in (web)'] = '' try: - self['Physical state'] = device.last_action_of(*states.Physical.actions()).t + self['Physical state'] = device.last_action_of( + *states.Physical.actions()).t except LookupError: self['Physical state'] = '' try: - self['Trading state'] = device.last_action_of(*states.Trading.actions()).t + self['Trading state'] = device.last_action_of( + *states.Trading.actions()).t except LookupError: self['Trading state'] = '' if isinstance(device, d.Computer): @@ -108,7 +111,7 @@ class DeviceRow(OrderedDict): self['RAM Range'] = '' self['Data Storage Rate'] = '' self['Data Storage Range'] = '' - + self['Price'] = none2str(device.price) benchram = get_action(device, 'BenchmarkRamSysbench') @@ -120,7 +123,7 @@ class DeviceRow(OrderedDict): def components(self): """Function to get all components information of a device.""" assert isinstance(self.device, d.Computer) - for ctype in self.ORDER_COMPONENTS: # ctype: str + for ctype in self.ORDER_COMPONENTS: # ctype: str cmax = self.NUMS.get(ctype, 4) i = 1 l_ctype = [ctype] @@ -148,9 +151,11 @@ class DeviceRow(OrderedDict): self['{} {} Model'.format(ctype, i)] = '' self['{} {} Serial Number'.format(ctype, i)] = '' else: - self['{} {} Manufacturer'.format(ctype, i)] = none2str(component.manufacturer) + self['{} {} Manufacturer'.format(ctype, i)] = none2str( + component.manufacturer) self['{} {} Model'.format(ctype, i)] = none2str(component.model) - self['{} {} Serial Number'.format(ctype, i)] = none2str(component.serial_number) + self['{} {} Serial Number'.format(ctype, i)] = none2str( + component.serial_number) if ctype == d.Processor.t: self.get_processor(ctype, i, component) @@ -170,10 +175,12 @@ class DeviceRow(OrderedDict): self['{} {} Number of cores'.format(ctype, i)] = '' self['{} {} Speed (GHz)'.format(ctype, i)] = '' self['Benchmark {} {} (points)'.format(ctype, i)] = '' - self['Benchmark ProcessorSysbench {} {} (points)'.format(ctype, i)] = '' + self['Benchmark ProcessorSysbench {} {} (points)'.format( + ctype, i)] = '' return - self['{} {} Number of cores'.format(ctype, i)] = none2str(component.cores) + self['{} {} Number of cores'.format( + ctype, i)] = none2str(component.cores) self['{} {} Speed (GHz)'.format(ctype, i)] = none2str(component.speed) benchmark = get_action(component, 'BenchmarkProcessor') @@ -184,9 +191,11 @@ class DeviceRow(OrderedDict): sysbench = get_action(component, 'BenchmarkProcessorSysbench') if not sysbench: - self['Benchmark ProcessorSysbench {} {} (points)'.format(ctype, i)] = '' + self['Benchmark ProcessorSysbench {} {} (points)'.format( + ctype, i)] = '' return - self['Benchmark ProcessorSysbench {} {} (points)'.format(ctype, i)] = sysbench.rate + self['Benchmark ProcessorSysbench {} {} (points)'.format( + ctype, i)] = sysbench.rate def get_ram(self, ctype, i, component): """Particular fields for component Ram Module.""" @@ -202,6 +211,7 @@ class DeviceRow(OrderedDict): """Particular fields for component DataStorage. A DataStorage can be HardDrive or SolidStateDrive. """ + if component is None: self['{} {} Size (MB)'.format(ctype, i)] = '' self['Erasure {} {}'.format(ctype, i)] = '' @@ -209,6 +219,7 @@ class DeviceRow(OrderedDict): self['Erasure {} {} Size (MB)'.format(ctype, i)] = '' self['Erasure {} {} Software'.format(ctype, i)] = '' self['Erasure {} {} Result'.format(ctype, i)] = '' + self['Erasure {} {} Certificate URL'.format(ctype, i)] = '' self['Erasure {} {} Type'.format(ctype, i)] = '' self['Erasure {} {} Method'.format(ctype, i)] = '' self['Erasure {} {} Elapsed (hours)'.format(ctype, i)] = '' @@ -222,7 +233,8 @@ class DeviceRow(OrderedDict): self['Test {} {} Type'.format(ctype, i)] = '' self['Test {} {} Result'.format(ctype, i)] = '' self['Test {} {} Power on (hours used)'.format(ctype, i)] = '' - self['Test {} {} Lifetime remaining (percentage)'.format(ctype, i)] = '' + self['Test {} {} Lifetime remaining (percentage)'.format( + ctype, i)] = '' return snapshot = get_action(component, 'Snapshot') @@ -233,15 +245,38 @@ class DeviceRow(OrderedDict): self['{} {} Size (MB)'.format(ctype, i)] = none2str(component.size) - erasures = [a for a in component.actions if a.type in ['EraseBasic', 'EraseSectors']] + erasures = [a for a in component.actions if a.type in [ + 'EraseBasic', 'EraseSectors', 'DataWipe']] erasure = erasures[-1] if erasures else None if not erasure: self['Erasure {} {}'.format(ctype, i)] = none2str(component.hid) 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) + self['Erasure {} {} Serial Number'.format( + ctype, i)] = serial_number + self['Erasure {} {} Size (MB)'.format( + ctype, i)] = none2str(component.size) self['Erasure {} {} Software'.format(ctype, i)] = '' self['Erasure {} {} Result'.format(ctype, i)] = '' + self['Erasure {} {} Certificate URL'.format(ctype, i)] = '' + self['Erasure {} {} Type'.format(ctype, i)] = '' + self['Erasure {} {} Method'.format(ctype, i)] = '' + self['Erasure {} {} Elapsed (hours)'.format(ctype, i)] = '' + self['Erasure {} {} Date'.format(ctype, i)] = '' + self['Erasure {} {} Steps'.format(ctype, i)] = '' + self['Erasure {} {} Steps Start Time'.format(ctype, i)] = '' + self['Erasure {} {} Steps End Time'.format(ctype, i)] = '' + elif hasattr(erasure, 'type') and erasure.type == 'DataWipe': + self['Erasure {} {}'.format(ctype, i)] = none2str(component.hid) + 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) + self['Erasure {} {} Software'.format( + ctype, i)] = erasure.document.software + self['Erasure {} {} Result'.format(ctype, i)] = get_result(erasure) + self['Erasure {} {} Certificate URL'.format( + ctype, i)] = erasure.document.url.to_text() self['Erasure {} {} Type'.format(ctype, i)] = '' self['Erasure {} {} Method'.format(ctype, i)] = '' self['Erasure {} {} Elapsed (hours)'.format(ctype, i)] = '' @@ -252,22 +287,31 @@ class DeviceRow(OrderedDict): else: self['Erasure {} {}'.format(ctype, i)] = none2str(component.hid) 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) + self['Erasure {} {} Serial Number'.format( + ctype, i)] = serial_number + self['Erasure {} {} Size (MB)'.format( + ctype, i)] = none2str(component.size) self['Erasure {} {} Software'.format(ctype, i)] = software - result = get_result(erasure.severity) + result = get_result(erasure) self['Erasure {} {} Result'.format(ctype, i)] = result + self['Erasure {} {} Certificate URL'.format(ctype, i)] = '' self['Erasure {} {} Type'.format(ctype, i)] = erasure.type self['Erasure {} {} Method'.format(ctype, i)] = erasure.method - self['Erasure {} {} Elapsed (hours)'.format(ctype, i)] = format(erasure.elapsed) - self['Erasure {} {} Date'.format(ctype, i)] = format(erasure.created) + self['Erasure {} {} Elapsed (hours)'.format( + ctype, i)] = format(erasure.elapsed) + self['Erasure {} {} Date'.format( + ctype, i)] = format(erasure.created) steps = ','.join((format(x) for x in erasure.steps)) self['Erasure {} {} Steps'.format(ctype, i)] = steps - steps_start_time = ','.join((format(x.start_time) for x in erasure.steps)) - self['Erasure {} {} Steps Start Time'.format(ctype, i)] = steps_start_time - steps_end_time = ','.join((format(x.end_time) for x in erasure.steps)) - self['Erasure {} {} Steps End Time'.format(ctype, i)] = steps_end_time + steps_start_time = ','.join( + (format(x.start_time) for x in erasure.steps)) + self['Erasure {} {} Steps Start Time'.format( + ctype, i)] = steps_start_time + steps_end_time = ','.join((format(x.end_time) + for x in erasure.steps)) + self['Erasure {} {} Steps End Time'.format( + ctype, i)] = steps_end_time benchmark = get_action(component, 'BenchmarkDataStorage') if not benchmark: @@ -285,12 +329,14 @@ class DeviceRow(OrderedDict): self['Test {} {} Type'.format(ctype, i)] = '' self['Test {} {} Result'.format(ctype, i)] = '' self['Test {} {} Power on (hours used)'.format(ctype, i)] = '' - self['Test {} {} Lifetime remaining (percentage)'.format(ctype, i)] = '' + self['Test {} {} Lifetime remaining (percentage)'.format( + ctype, i)] = '' return self['Test {} {} Software'.format(ctype, i)] = software self['Test {} {} Type'.format(ctype, i)] = test_storage.length.value - self['Test {} {} Result'.format(ctype, i)] = get_result(test_storage.severity) + self['Test {} {} Result'.format(ctype, i)] = get_result( + test_storage) self['Test {} {} Power on (hours used)'.format(ctype, i)] = none2str( test_storage.power_cycle_count) self['Test {} {} Lifetime remaining (percentage)'.format(ctype, i)] = none2str( @@ -319,7 +365,8 @@ class StockRow(OrderedDict): self['Manufacturer'] = none2str(device.manufacturer) self['Registered in'] = format(device.created, '%c') try: - self['Physical state'] = device.last_action_of(*states.Physical.actions()).t + self['Physical state'] = device.last_action_of( + *states.Physical.actions()).t except LookupError: self['Physical state'] = '' try: @@ -343,15 +390,21 @@ class StockRow(OrderedDict): self['Data Storage Range'] = rate.data_storage_range -def get_result(severity): +def get_result(erasure): """ For the csv is necessary simplify the message of results """ + if hasattr(erasure, 'type') and erasure.type == 'DataWipe': + if erasure.document.success: + return 'Success' + return 'Failure' + + type_of_results = { Severity.Error: 'Failure', Severity.Warning: 'Success with Warnings', Severity.Notice: 'Success', Severity.Info: 'Success' } - return type_of_results[severity] + return type_of_results[erasure.severity] def none2str(string): diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index 26e94292..98cdf956 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -90,6 +90,7 @@ class DocumentView(DeviceView): res = flask.make_response(template) return res + @staticmethod def erasure(query: db.Query): def erasures(): @@ -274,7 +275,13 @@ class StampsView(View): ok = '100% coincidence. The attached file contains data 100% existing in \ to our backend' result = ('Bad', bad) - if file_check.mimetype in ['text/csv', 'application/pdf']: + mime = ['text/csv', 'application/pdf', 'text/plain','text/markdown', + 'image/jpeg', 'image/png', 'text/html', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/msword'] + if file_check.mimetype in mime: if verify_hash(file_check): result = ('Ok', ok) @@ -291,7 +298,6 @@ class InternalStatsView(DeviceView): evs.Action.type.in_(('Snapshot', 'Live', 'Allocate', 'Deallocate'))) return self.generate_post_csv(query) - def generate_post_csv(self, query): d = {} for ac in query: diff --git a/ereuse_devicehub/resources/documents/models.py b/ereuse_devicehub/resources/documents/models.py new file mode 100644 index 00000000..a2b98511 --- /dev/null +++ b/ereuse_devicehub/resources/documents/models.py @@ -0,0 +1,57 @@ +from citext import CIText +from flask import g +from sqlalchemy import BigInteger, Column, Sequence, Unicode, Boolean, ForeignKey +from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.dialects.postgresql import UUID +from teal.db import URL +from ereuse_devicehub.db import db +from ereuse_devicehub.resources.user.models import User +from ereuse_devicehub.resources.models import Thing, STR_SM_SIZE + + +class Document(Thing): + """This represent a generic document.""" + + id = Column(BigInteger, Sequence('device_seq'), primary_key=True) + id.comment = """The identifier of the device for this database. Used only + internally for software; users should not use this. + """ + document_type = Column(Unicode(STR_SM_SIZE), nullable=False) + date = Column(db.DateTime, nullable=True) + date.comment = """The date of document, some documents need to have one date + """ + id_document = Column(CIText(), nullable=True) + id_document.comment = """The id of one document like invoice so they can be linked.""" + owner_id = db.Column(UUID(as_uuid=True), + db.ForeignKey(User.id), + nullable=False, + default=lambda: g.user.id) + owner = db.relationship(User, primaryjoin=owner_id == User.id) + file_name = Column(db.CIText(), nullable=False) + file_name.comment = """This is the name of the file when user up the document.""" + file_hash = Column(db.CIText(), nullable=False) + file_hash.comment = """This is the hash of the file produced from frontend.""" + url = db.Column(URL(), nullable=True) + url.comment = """This is the url where resides the document.""" + + def __str__(self) -> str: + return '{0.file_name}'.format(self) + + +class JoinedTableMixin: + # noinspection PyMethodParameters + @declared_attr + def id(cls): + return Column(BigInteger, ForeignKey(Document.id), primary_key=True) + + +class DataWipeDocument(JoinedTableMixin, Document): + """This represent a generic document.""" + + software = Column(CIText(), nullable=True) + software.comment = """Which software is used""" + success = Column(Boolean, default=False) + success.comment = """If the erase was success""" + + def __str__(self) -> str: + return '{0.file_name}'.format(self) diff --git a/ereuse_devicehub/resources/documents/schemas.py b/ereuse_devicehub/resources/documents/schemas.py new file mode 100644 index 00000000..6500777a --- /dev/null +++ b/ereuse_devicehub/resources/documents/schemas.py @@ -0,0 +1,32 @@ +from marshmallow.fields import DateTime, Integer, validate, Boolean +from marshmallow import post_load +from teal.marshmallow import SanitizedStr, URL +from ereuse_devicehub.resources.schemas import Thing +from ereuse_devicehub.resources.documents import models as m + + +class DataWipeDocument(Thing): + __doc__ = m.DataWipeDocument.__doc__ + id = Integer(description=m.DataWipeDocument.id.comment, dump_only=True) + url = URL(required= False, description=m.DataWipeDocument.url.comment) + success = Boolean(required=False, default=False, description=m.DataWipeDocument.success.comment) + software = SanitizedStr(description=m.DataWipeDocument.software.comment) + date = DateTime(data_key='endTime', + required=False, + description=m.DataWipeDocument.date.comment) + id_document = SanitizedStr(data_key='documentId', + required=False, + default='', + description=m.DataWipeDocument.id_document.comment) + file_name = SanitizedStr(data_key='filename', + default='', + description=m.DataWipeDocument.file_name.comment, + validate=validate.Length(max=100)) + file_hash = SanitizedStr(data_key='hash', + default='', + description=m.DataWipeDocument.file_hash.comment, + validate=validate.Length(max=64)) + + @post_load + def get_trade_document(self, data): + data['document_type'] = 'DataWipeDocument' diff --git a/tests/files/basic.csv b/tests/files/basic.csv index 8a7851ec..b6707df9 100644 --- a/tests/files/basic.csv +++ b/tests/files/basic.csv @@ -1,2 +1,2 @@ -DevicehubID;DocumentID;Public Link;Lots;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;Trading 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 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 on (hours used);Test DataStorage 1 Lifetime remaining (percentage);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 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 on (hours used);Test DataStorage 2 Lifetime remaining (percentage);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 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 on (hours used);Test DataStorage 3 Lifetime remaining (percentage);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 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 on (hours used);Test DataStorage 4 Lifetime remaining (percentage);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;Price;Benchmark RamSysbench (points) -93652;;http://localhost/devices/93652;;;;;;;;;;;desktop-d1mr-d1ml-d1s;Desktop;Microtower;d1s;d1ml;d1mr;Wed May 26 11:29:24 2021;Workbench 11.0;2021-05-26 11:29:24.703310+02:00;;;;p1ml;0;0;Processor 6: model p1ml, S/N p1s;p1mr;p1ml;p1s;;1.6;2410.0;;;;;;;;;;RamModule 5: model rm1ml, S/N rm1s;rm1mr;rm1ml;rm1s;;1333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GraphicCard 4: model gc1ml, S/N gc1s;gc1mr;gc1ml;gc1s;;;;;;;;;;;;;;;;;;;;;;;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;; +DevicehubID;DocumentID;Public Link;Lots;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;Trading 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 on (hours used);Test DataStorage 1 Lifetime remaining (percentage);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 on (hours used);Test DataStorage 2 Lifetime remaining (percentage);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 on (hours used);Test DataStorage 3 Lifetime remaining (percentage);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 on (hours used);Test DataStorage 4 Lifetime remaining (percentage);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;Price;Benchmark RamSysbench (points) +93652;;http://localhost/devices/93652;;;;;;;;;;;desktop-d1mr-d1ml-d1s;Desktop;Microtower;d1s;d1ml;d1mr;Mon Aug 2 10:25:31 2021;Workbench 11.0;2021-08-02 10:25:31.457986+02:00;;;;p1ml;0;0;Processor 6: model p1ml, S/N p1s;p1mr;p1ml;p1s;;1.6;2410.0;;;;;;;;;;RamModule 5: model rm1ml, S/N rm1s;rm1mr;rm1ml;rm1s;;1333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GraphicCard 4: model gc1ml, S/N gc1s;gc1mr;gc1ml;gc1s;;;;;;;;;;;;;;;;;;;;;;;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;; diff --git a/tests/files/proposal_extended_csv_report.csv b/tests/files/proposal_extended_csv_report.csv index 288745f1..d8bf0c56 100644 --- a/tests/files/proposal_extended_csv_report.csv +++ b/tests/files/proposal_extended_csv_report.csv @@ -1,3 +1,3 @@ -DevicehubID;DocumentID;Public Link;Lots;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;Trading 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 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 on (hours used);Test DataStorage 1 Lifetime remaining (percentage);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 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 on (hours used);Test DataStorage 2 Lifetime remaining (percentage);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 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 on (hours used);Test DataStorage 3 Lifetime remaining (percentage);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 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 on (hours used);Test DataStorage 4 Lifetime remaining (percentage);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;Price;Benchmark RamSysbench (points) -93652;;http://localhost/devices/93652;;named;foo;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b;Laptop;Netbook;b8oaas048285;1001pxd;asustek computer inc.;Wed May 26 11:37:09 2021;Workbench 11.0a2;2021-05-26 11:37:10.462501+02:00;;;;intel atom cpu n455 @ 2.66ghz;1024;238475;Processor 6: 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 10: model None, S/N None;;;;1024;667;;;;;;;;;;;;;;;;;;;HardDrive 11: model hts54322, S/N e2024242cv86mm;hitachi;hts54322;e2024242cv86mm;238475;harddrive-hitachi-hts54322-e2024242cv86mm;e2024242cv86mm;238475;Workbench 11.0a2;Success;EraseBasic;Shred;1:16:49;2021-05-26 11:37:09.584933+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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 12: model 1001pxd, S/N eee0123456720;asustek computer inc.;1001pxd;eee0123456720;;;;;GraphicCard 7: 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 4: 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 5: 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 8: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;;;;;1.75;LOW;1.55;LOW;1.53;LOW;3.76;HIGH;52.50 €;15.7188 -J2MA2;;http://localhost/devices/J2MA2;;;;;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c;Laptop;Netbook;b8oaas048287;1001pxd;asustek computer inc.;Wed May 26 11:37:10 2021;Workbench 11.0b11;2021-05-26 11:37:10.149784+02:00;;;;intel atom cpu n455 @ 1.66ghz;2048;558558;Processor 17: 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 20: model None, S/N None;;;;1024;667;RamModule 21: model 48594d503131325336344350362d53362020, S/N 4f43487b;hynix semiconductor;48594d503131325336344350362d53362020;4f43487b;1024;667;;;;;;;;;;;;;HardDrive 22: model hts54322, S/N e2024242cv86hj;hitachi;hts54322;e2024242cv86hj;238475;harddrive-hitachi-hts54322-e2024242cv86hj;e2024242cv86hj;238475;Workbench 11.0b11;Success;EraseBasic;Shred;1:16:49;2021-05-26 11:37:10.062739+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;;;DataStorage 23: 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;2021-05-26 11:37:10.065439+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;SolidStateDrive 24: 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;2021-05-26 11:37:10.070634+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;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 25: model 1001pxd, S/N eee0123456789;asustek computer inc.;1001pxd;eee0123456789;;"auo ""auo""";auo lcd monitor;;GraphicCard 18: 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 15: 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 16: 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 9: model usb 2.0 uvc vga webcam, S/N 0x0001;azurewave;usb 2.0 uvc vga webcam;0x0001;SoundCard 19: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;1.72;LOW;1.31;LOW;1.99;LOW;3.97;HIGH;51.60 €;15.7188 +DevicehubID;DocumentID;Public Link;Lots;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;Trading 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 on (hours used);Test DataStorage 1 Lifetime remaining (percentage);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 on (hours used);Test DataStorage 2 Lifetime remaining (percentage);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 on (hours used);Test DataStorage 3 Lifetime remaining (percentage);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 on (hours used);Test DataStorage 4 Lifetime remaining (percentage);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;Price;Benchmark RamSysbench (points) +93652;;http://localhost/devices/93652;;named;foo;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b;Laptop;Netbook;b8oaas048285;1001pxd;asustek computer inc.;Mon Aug 2 10:27:27 2021;Workbench 11.0a2;2021-08-02 10:27:27.772331+02:00;;;;intel atom cpu n455 @ 2.66ghz;1024;238475;Processor 6: 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 10: model None, S/N None;;;;1024;667;;;;;;;;;;;;;;;;;;;HardDrive 11: model hts54322, S/N e2024242cv86mm;hitachi;hts54322;e2024242cv86mm;238475;harddrive-hitachi-hts54322-e2024242cv86mm;e2024242cv86mm;238475;Workbench 11.0a2;Success;;EraseBasic;Shred;1:16:49;2021-08-02 10:27:27.163611+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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 12: model 1001pxd, S/N eee0123456720;asustek computer inc.;1001pxd;eee0123456720;;;;;GraphicCard 7: 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 4: 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 5: 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 8: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;;;;;1.75;LOW;1.55;LOW;1.53;LOW;3.76;HIGH;52.50 €;15.7188 +J2MA2;;http://localhost/devices/J2MA2;;;;;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c;Laptop;Netbook;b8oaas048287;1001pxd;asustek computer inc.;Mon Aug 2 10:27:27 2021;Workbench 11.0b11;2021-08-02 10:27:27.528832+02:00;;;;intel atom cpu n455 @ 1.66ghz;2048;558558;Processor 17: 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 20: model None, S/N None;;;;1024;667;RamModule 21: model 48594d503131325336344350362d53362020, S/N 4f43487b;hynix semiconductor;48594d503131325336344350362d53362020;4f43487b;1024;667;;;;;;;;;;;;;HardDrive 22: model hts54322, S/N e2024242cv86hj;hitachi;hts54322;e2024242cv86hj;238475;harddrive-hitachi-hts54322-e2024242cv86hj;e2024242cv86hj;238475;Workbench 11.0b11;Success;;EraseBasic;Shred;1:16:49;2021-08-02 10:27:27.458348+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;;;DataStorage 23: 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;2021-08-02 10:27:27.460573+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;SolidStateDrive 24: 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;2021-08-02 10:27:27.464663+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;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 25: model 1001pxd, S/N eee0123456789;asustek computer inc.;1001pxd;eee0123456789;;"auo ""auo""";auo lcd monitor;;GraphicCard 18: 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 15: 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 16: 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 9: model usb 2.0 uvc vga webcam, S/N 0x0001;azurewave;usb 2.0 uvc vga webcam;0x0001;SoundCard 19: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;1.72;LOW;1.31;LOW;1.99;LOW;3.97;HIGH;51.60 €;15.7188 diff --git a/tests/test_action.py b/tests/test_action.py index 547ab96d..03868c3c 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -6,6 +6,7 @@ import copy import pytest from datetime import datetime, timedelta +from io import BytesIO from dateutil.tz import tzutc from decimal import Decimal from typing import Tuple, Type @@ -2408,3 +2409,32 @@ def test_trade_case14(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_from assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_action_web_erase(user: UserClient, client: Client): + import hashlib + from ereuse_devicehub.resources.documents import documents + bfile = BytesIO(b'abc') + hash3 = hashlib.sha3_256(bfile.read()).hexdigest() + snap, _ = user.post(file('acer.happy.battery.snapshot'), res=models.Snapshot) + request = {'type': 'DataWipe', 'devices': [snap['device']['id']], 'name': 'borrado universal', 'severity': 'Info', 'description': 'nada que describir', 'url': 'http://www.google.com/', 'documentId': '33', 'endTime': '2021-07-07T22:00:00.000Z', 'filename': 'Certificado de borrado1.pdf', 'hash': hash3, 'success': 1, 'software': "Blanco"} + + user.post(res=models.Action, data=request) + action = models.DataWipe.query.one() + for dev in action.devices: + assert action in dev.actions + + assert action.document.file_hash == request['hash'] + + bfile = BytesIO(b'abc') + response, _ = client.post(res=documents.DocumentDef.t, + item='stamps/', + content_type='multipart/form-data', + accept='text/html', + data={'docUpload': [(bfile, 'example.csv')]}, + status=200) + assert "alert alert-info" in response + assert "100% coincidence." in response + assert not "alert alert-danger" in response diff --git a/tests/test_basic.py b/tests/test_basic.py index 4cdce061..c04e8fb6 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -122,4 +122,4 @@ def test_api_docs(client: Client): 'scheme': 'basic', 'name': 'Authorization' } - assert len(docs['definitions']) == 125 + assert len(docs['definitions']) == 126 diff --git a/tests/test_documents.py b/tests/test_documents.py index 1f89d96b..afb48023 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -33,19 +33,22 @@ def test_erasure_certificate_public_one(user: UserClient, client: Client): snapshot, _ = user.post(s, res=Snapshot) doc, response = user.get(res=documents.DocumentDef.t, - item='erasures/{}'.format(snapshot['device']['id']), - accept=ANY) + item='erasures/{}'.format( + snapshot['device']['id']), + accept=ANY) assert 'html' in response.content_type assert ' 0 @@ -122,30 +127,31 @@ def test_export_csv_actions(user: UserClient, user2: UserClient, client: Client) "finalUserCode": "abcdefjhi", "startTime": "2020-11-01T02:00:00+00:00", "endTime": "2020-12-01T02:00:00+00:00" - } + } user.post(res=Allocate, data=post_request) hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] - hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action = [a for a in hdd['actions'] + if a['type'] == 'TestDataStorage'][0] hdd_action['lifetime'] += 1000 acer.pop('elapsed') acer['licence_version'] = '1.0.0' snapshot, _ = client.post(acer, res=Live) csv_user, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer']})]) + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) csv_user2, _ = user2.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer']})]) + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) _, res = client.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer']})], status=401) + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})], status=401) assert res.status_code == 401 assert len(csv_user) > 0 @@ -164,21 +170,22 @@ def test_live_export_csv2(user: UserClient, client: Client, app: Devicehub): "finalUserCode": "abcdefjhi", "startTime": "2020-11-01T02:00:00+00:00", "endTime": "2020-12-01T02:00:00+00:00" - } + } user.post(res=Allocate, data=post_request) acer = yaml2json('acer-happy.live-test1') live, _ = client.post(acer, res=Live) csv_user, _ = user.get(res=documents.DocumentDef.t, - item='actions/', - accept='text/csv', - query=[('filter', {'type': ['Computer']})]) + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) assert "4692" in csv_user assert "8692" in csv_user assert "DevicehubID" in csv_user + @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_live_example2(user: UserClient, client: Client, app: Devicehub): @@ -211,6 +218,7 @@ def test_export_basic_snapshot(user: UserClient): item='devices/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) + f = StringIO(csv_str) obj_csv = csv.reader(f, f, delimiter=';', quotechar='"') export_csv = list(obj_csv) @@ -275,9 +283,6 @@ def test_export_extended(app: Devicehub, user: UserClient): obj_csv = csv.reader(f, f, delimiter=';', quotechar='"') export_csv = list(obj_csv) - ff= open('ba.csv', 'w') - ff.write(csv_str) - ff.close() # Open fixture csv and transform to list with Path(__file__).parent.joinpath('files').joinpath( 'proposal_extended_csv_report.csv').open() as csv_file: @@ -290,18 +295,18 @@ def test_export_extended(app: Devicehub, user: UserClient): assert fixture_csv[0] == export_csv[0], 'Headers are not equal' assert fixture_csv[1][:19] == export_csv[1][:19], 'Computer information are not equal' assert fixture_csv[1][20] == export_csv[1][20], 'Computer information are not equal' - assert fixture_csv[1][22:81] == export_csv[1][22:81], 'Computer information are not equal' - assert fixture_csv[1][82] == export_csv[1][82], 'Computer information are not equal' - assert fixture_csv[1][85:] == export_csv[1][85:], 'Computer information are not equal' + assert fixture_csv[1][22:82] == export_csv[1][22:82], 'Computer information are not equal' + assert fixture_csv[1][83] == export_csv[1][83], 'Computer information are not equal' + assert fixture_csv[1][86:] == export_csv[1][86:], 'Computer information are not equal' assert fixture_csv[2][:19] == export_csv[2][:19], 'Computer information are not equal' assert fixture_csv[2][20] == export_csv[2][20], 'Computer information are not equal' - assert fixture_csv[2][22:81] == export_csv[2][22:81], 'Computer information are not equal' - assert fixture_csv[2][82] == export_csv[2][82], 'Computer information are not equal' - assert fixture_csv[2][85:105] == export_csv[2][85:105], 'Computer information are not equal' - assert fixture_csv[2][106] == export_csv[2][106], 'Computer information are not equal' - assert fixture_csv[2][109:129] == export_csv[2][109:129], 'Computer information are not equal' - assert fixture_csv[2][130] == export_csv[2][130], 'Computer information are not equal' - assert fixture_csv[2][133:] == export_csv[2][133:], 'Computer information are not equal' + assert fixture_csv[2][22:82] == export_csv[2][22:82], 'Computer information are not equal' + assert fixture_csv[2][83] == export_csv[2][83], 'Computer information are not equal' + assert fixture_csv[2][86:106] == export_csv[2][86:106], 'Computer information are not equal' + assert fixture_csv[2][108] == export_csv[2][108], 'Computer information are not equal' + assert fixture_csv[2][111:131] == export_csv[2][111:131], 'Computer information are not equal' + assert fixture_csv[2][131] == export_csv[2][131], 'Computer information are not equal' + assert fixture_csv[2][136:] == export_csv[2][136:], 'Computer information are not equal' @pytest.mark.mvp