diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 1ac963d8..9904c80f 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -27,9 +27,9 @@ from wtforms.fields import FormField from ereuse_devicehub.db import db from ereuse_devicehub.parser.parser import ParseSnapshotLsHw +from ereuse_devicehub.parser.schemas import Snapshot_lite from ereuse_devicehub.resources.action.models import Snapshot, Trade from ereuse_devicehub.resources.action.schemas import Snapshot as SnapshotSchema -from ereuse_devicehub.resources.action.schemas import Snapshot_lite from ereuse_devicehub.resources.action.views.snapshot import move_json, save_json from ereuse_devicehub.resources.device.models import ( SAI, @@ -233,6 +233,13 @@ class UploadSnapshotForm(FlaskForm): return True + def is_wb_lite_snapshot(self, version: str) -> bool: + is_lite = False + if version in app.config['WORKBENCH_LITE']: + is_lite = True + + return is_lite + def save(self, commit=True): if any([x == 'Error' for x in self.result.values()]): return @@ -243,7 +250,8 @@ class UploadSnapshotForm(FlaskForm): for filename, snapshot_json in self.snapshots: path_snapshot = save_json(snapshot_json, self.tmp_snapshots, g.user.email) snapshot_json.pop('debug', None) - if snapshot_json.get('version') in ["2022.03"]: + version = snapshot_json.get('version') + if self.is_wb_lite_snapshot(version): self.snapshot_json = schema_lite.load(snapshot_json) snap = ParseSnapshotLsHw(self.snapshot_json) snapshot_json = snap.snapshot_json diff --git a/ereuse_devicehub/parser/computer.py b/ereuse_devicehub/parser/computer.py index 7a1439c5..01434da6 100644 --- a/ereuse_devicehub/parser/computer.py +++ b/ereuse_devicehub/parser/computer.py @@ -7,8 +7,7 @@ from math import hypot from typing import Iterator, List, Optional, Type, TypeVar import dateutil.parser -from ereuse_utils import getter as g -from ereuse_utils import text +from ereuse_utils import getter, text from ereuse_utils.nested_lookup import ( get_nested_dicts_with_key_containing_value, get_nested_dicts_with_key_value, @@ -33,15 +32,15 @@ class Device(Dumpeable): super().__init__() def from_lshw(self, lshw_node: dict): - self.manufacturer = g.dict(lshw_node, 'vendor', default=None, type=str) - self.model = g.dict( + self.manufacturer = getter.dict(lshw_node, 'vendor', default=None, type=str) + self.model = getter.dict( lshw_node, 'product', remove={self.manufacturer} if self.manufacturer else set(), default=None, type=str, ) - self.serial_number = g.dict(lshw_node, 'serial', default=None, type=str) + self.serial_number = getter.dict(lshw_node, 'serial', default=None, type=str) def __str__(self) -> str: return ' '.join(x for x in (self.model, self.serial_number) if x) @@ -208,7 +207,7 @@ class Motherboard(Component): bios_node = next(get_nested_dicts_with_key_value(lshw, 'id', 'firmware')) # bios_node = '1' memory_array = next( - g.indents(hwinfo, 'Physical Memory Array', indent=' '), None + getter.indents(hwinfo, 'Physical Memory Array', indent=' '), None ) return cls(node, bios_node, memory_array) @@ -234,8 +233,8 @@ class Motherboard(Component): self.version = bios_node['version'] self.ram_slots = self.ram_max_size = None if memory_array: - self.ram_slots = g.kv(memory_array, 'Slots', default=None) - self.ram_max_size = g.kv(memory_array, 'Max. Size', default=None) + self.ram_slots = getter.kv(memory_array, 'Slots', default=None) + self.ram_max_size = getter.kv(memory_array, 'Max. Size', default=None) if self.ram_max_size: self.ram_max_size = next(text.numbers(self.ram_max_size)) @@ -306,33 +305,34 @@ class Display(Component): @classmethod def new(cls, lshw, hwinfo, **kwargs) -> Iterator[C]: - for node in g.indents(hwinfo, 'Monitor'): + for node in getter.indents(hwinfo, 'Monitor'): yield cls(node) def __init__(self, node: dict) -> None: super().__init__(node) - self.model = g.kv(node, 'Model') - self.manufacturer = g.kv(node, 'Vendor') - self.serial_number = g.kv(node, 'Serial ID', default=None, type=str) + self.model = getter.kv(node, 'Model') + self.manufacturer = getter.kv(node, 'Vendor') + self.serial_number = getter.kv(node, 'Serial ID', default=None, type=str) self.resolution_width, self.resolution_height, refresh_rate = text.numbers( - g.kv(node, 'Resolution') + getter.kv(node, 'Resolution') ) self.refresh_rate = unit.Quantity(refresh_rate, 'Hz').m with suppress(StopIteration): # some monitors can have several resolutions, and the one # in "Detailed Timings" seems the highest one - timings = next(g.indents(node, 'Detailed Timings', indent=' ')) + timings = next(getter.indents(node, 'Detailed Timings', indent=' ')) self.resolution_width, self.resolution_height = text.numbers( - g.kv(timings, 'Resolution') + getter.kv(timings, 'Resolution') ) x, y = ( unit.convert(v, 'millimeter', 'inch') - for v in text.numbers(g.kv(node, 'Size')) + for v in text.numbers(getter.kv(node, 'Size')) ) self.size = hypot(x, y) self.technology = next((t for t in self.TECHS if t in node[0]), None) d = '{} {} 0'.format( - g.kv(node, 'Year of Manufacture'), g.kv(node, 'Week of Manufacture') + getter.kv(node, 'Year of Manufacture'), + getter.kv(node, 'Week of Manufacture'), ) # We assume it has been produced the first day of such week self.production_date = datetime.strptime(d, '%Y %W %w').isoformat() @@ -413,8 +413,8 @@ class Computer(Device): self.chassis = next( t for t, values in self.CHASSIS_DH.items() if chassis in values ) - self.sku = g.dict(node, ('configuration', 'sku'), default=None, type=str) - self.version = g.dict(node, 'version', default=None, type=str) + self.sku = getter.dict(node, ('configuration', 'sku'), default=None, type=str) + self.version = getter.dict(node, 'version', default=None, type=str) self._ram = None @classmethod diff --git a/ereuse_devicehub/parser/schemas.py b/ereuse_devicehub/parser/schemas.py new file mode 100644 index 00000000..71e56b91 --- /dev/null +++ b/ereuse_devicehub/parser/schemas.py @@ -0,0 +1,32 @@ +from flask import current_app as app +from marshmallow import Schema as MarshmallowSchema +from marshmallow import ValidationError, validates_schema +from marshmallow.fields import Nested, String + + +class Snapshot_lite_data(MarshmallowSchema): + dmidecode = String(required=False) + hwinfo = String(required=False) + smart = String(required=False) + lshw = String(required=False) + + +class Snapshot_lite(MarshmallowSchema): + uuid = String(required=True) + version = String(required=True) + software = String(required=True) + wbid = String(required=True) + type = String(required=True) + timestamp = String(required=True) + data = Nested(Snapshot_lite_data) + + @validates_schema + def validate_workbench_version(self, data: dict): + if data['version'] not in app.config['WORKBENCH_LITE']: + raise ValidationError( + 'Min. supported Workbench version is ' + '{} but yours is {}.'.format( + app.config['WORKBENCH_LITE'][0], data['version'] + ), + field_names=['version'], + ) diff --git a/ereuse_devicehub/parser/snapshot.py b/ereuse_devicehub/parser/snapshot.py index c77d8f55..559a7f48 100644 --- a/ereuse_devicehub/parser/snapshot.py +++ b/ereuse_devicehub/parser/snapshot.py @@ -1,21 +1,10 @@ from datetime import datetime, timezone -from enum import Enum, unique from typing import List from ereuse_workbench.computer import Component, Computer, DataStorage from ereuse_workbench.utils import Dumpeable -@unique -class SnapshotSoftware(Enum): - """The algorithm_software used to perform the Snapshot.""" - - Workbench = 'Workbench' - AndroidApp = 'AndroidApp' - Web = 'Web' - DesktopApp = 'DesktopApp' - - class Snapshot(Dumpeable): """ Generates the Snapshot report for Devicehub by obtaining the