fix a lot of bugs and add storage and disk to the snapshot

This commit is contained in:
Cayo Puigdefabregas 2022-03-25 13:55:05 +01:00
parent 7d1e1589b6
commit 883c01053f
5 changed files with 195 additions and 103 deletions

View File

@ -13,7 +13,7 @@ from ereuse_devicehub.parser.computer import (
class ParseSnapshot: class ParseSnapshot:
def __init__(self, snapshot, default="n/a"): def __init__(self, snapshot, default="n/a"):
self.default = default self.default = default
self.dmidecode_raw = snapshot["data"]["demidecode"] self.dmidecode_raw = snapshot["data"]["dmidecode"]
self.smart_raw = snapshot["data"]["smart"] self.smart_raw = snapshot["data"]["smart"]
self.hwinfo_raw = snapshot["data"]["hwinfo"] self.hwinfo_raw = snapshot["data"]["hwinfo"]
self.device = {"actions": []} self.device = {"actions": []}
@ -24,16 +24,16 @@ class ParseSnapshot:
self.hwinfo = self.parse_hwinfo() self.hwinfo = self.parse_hwinfo()
self.set_basic_datas() self.set_basic_datas()
self.set_components()
self.snapshot_json = { self.snapshot_json = {
"device": self.device, "device": self.device,
"software": "Workbench", "software": "Workbench",
"components": self.components(), "components": self.components,
"uuid": snapshot['uuid'], "uuid": snapshot['uuid'],
"type": snapshot['type'], "type": snapshot['type'],
"version": snapshot["version"], "version": snapshot["version"],
"endTime": snapshot["endTime"], "endTime": snapshot["timestamp"],
"elapsed": 0, "elapsed": 1,
"closed": True,
} }
def set_basic_datas(self): def set_basic_datas(self):
@ -43,12 +43,14 @@ class ParseSnapshot:
self.device['type'] = self.get_type() self.device['type'] = self.get_type()
self.device['sku'] = self.get_sku() self.device['sku'] = self.get_sku()
self.device['version'] = self.get_version() self.device['version'] = self.get_version()
self.device['uuid'] = self.get_uuid() # self.device['uuid'] = self.get_uuid()
def set_components(self): def set_components(self):
self.get_cpu() self.get_cpu()
self.get_ram() self.get_ram()
self.get_mother_board() self.get_mother_board()
self.get_data_storage()
self.get_networks()
def get_cpu(self): def get_cpu(self):
# TODO @cayop generation, brand and address not exist in dmidecode # TODO @cayop generation, brand and address not exist in dmidecode
@ -57,7 +59,7 @@ class ParseSnapshot:
{ {
"actions": [], "actions": [],
"type": "Processor", "type": "Processor",
"speed": cpu.get('Max Speed'), "speed": self.get_cpu_speed(cpu),
"cores": int(cpu.get('Core Count', 1)), "cores": int(cpu.get('Core Count', 1)),
"model": cpu.get('Version'), "model": cpu.get('Version'),
"threads": int(cpu.get('Thread Count', 1)), "threads": int(cpu.get('Thread Count', 1)),
@ -80,8 +82,8 @@ class ParseSnapshot:
"speed": self.get_ram_speed(ram), "speed": self.get_ram_speed(ram),
"manufacturer": ram.get("Manufacturer", self.default), "manufacturer": ram.get("Manufacturer", self.default),
"serialNumber": ram.get("Serial Number", self.default), "serialNumber": ram.get("Serial Number", self.default),
"interface": ram.get("Type", self.default), "interface": ram.get("Type", "DDR"),
"format": ram.get("Format", self.default), # "DIMM", "format": ram.get("Format", "DIMM"), # "DIMM",
"model": ram.get( "model": ram.get(
"Model", self.default "Model", self.default
), # "48594D503131325336344350362D53362020", ), # "48594D503131325336344350362D53362020",
@ -98,11 +100,11 @@ class ParseSnapshot:
"version": moder_board.get("Version"), "version": moder_board.get("Version"),
"serialNumber": moder_board.get("Serial Number"), "serialNumber": moder_board.get("Serial Number"),
"manufacturer": moder_board.get("Manufacturer"), "manufacturer": moder_board.get("Manufacturer"),
"ramSlots": self.get_ram_slots(),
"ramMaxSize": self.get_max_ram_size(),
"slots": len(self.dmi.get("Number Of Devices")),
"biosDate": self.get_bios_date(), "biosDate": self.get_bios_date(),
"firewire": self.get_firmware(), "firewire": self.get_firmware(),
"ramMaxSize": self.get_max_ram_size(),
"ramSlots": len(self.dmi.get("Memory Device")),
"slots": self.get_ram_slots(),
"model": moder_board.get("Product Name"), # ?? "model": moder_board.get("Product Name"), # ??
"pcmcia": self.get_pcmcia_num(), # ?? "pcmcia": self.get_pcmcia_num(), # ??
"serial": self.get_serial_num(), # ?? "serial": self.get_serial_num(), # ??
@ -112,57 +114,70 @@ class ParseSnapshot:
def get_usb_num(self): def get_usb_num(self):
return len( return len(
[u for u in self.get("Port Connector") if u.get("Port Type") == "USB"] [u for u in self.dmi.get("Port Connector") if u.get("Port Type") == "USB"]
) )
def get_serial_num(self): def get_serial_num(self):
return len( return len(
[u for u in self.get("Port Connector") if u.get("Port Type") == "SERIAL"] [
u
for u in self.dmi.get("Port Connector")
if u.get("Port Type") == "SERIAL"
]
) )
def get_pcmcia_num(self): def get_pcmcia_num(self):
return len( return len(
[u for u in self.get("Port Connector") if u.get("Port Type") == "PCMCIA"] [
u
for u in self.dmi.get("Port Connector")
if u.get("Port Type") == "PCMCIA"
]
) )
def get_bios_date(self): def get_bios_date(self):
return self.get("BIOS")[0].get("Release Date", self.default) return self.dmi.get("BIOS")[0].get("Release Date", self.default)
def get_firmware(self): def get_firmware(self):
return self.get("BIOS")[0].get("Firmware Revision", self.default) return int(float(self.dmi.get("BIOS")[0].get("Firmware Revision", 1)))
def get_max_ram_size(self): def get_max_ram_size(self):
size = self.dmi.get("Physical Memory Array") size = 0
if size: for slot in self.dmi.get("Physical Memory Array"):
size = size.get("Maximum Capacity") capacity = slot.get("Maximum Capacity", '0').split(" ")[0]
size += int(capacity)
return size.split(" GB")[0] if size else self.default return size
def get_ram_slots(self): def get_ram_slots(self):
slots = self.dmi.get("Physical Memory Array") slots = 0
if slots: for x in self.dmi.get("Physical Memory Array"):
slots = slots.get("Number Of Devices") slots += int(x.get("Number Of Devices", 0))
return int(slots) if slots else self.default return slots
def get_ram_size(self, ram): def get_ram_size(self, ram):
size = ram.get("Size") size = ram.get("Size", "0")
return size.split(" MB")[0] if size else self.default return int(size.split(" ")[0])
def get_ram_speed(self, ram): def get_ram_speed(self, ram):
size = ram.get("Speed") size = ram.get("Speed", "0")
return size.split(" MT/s")[0] if size else self.default return int(size.split(" ")[0])
def get_cpu_speed(self, cpu):
speed = cpu.get('Max Speed', "0")
return float(speed.split(" ")[0]) / 1024
def get_sku(self): def get_sku(self):
return self.get("System")[0].get("SKU Number", self.default) return self.dmi.get("System")[0].get("SKU Number", self.default)
def get_version(self): def get_version(self):
return self.get("System")[0].get("Version", self.default) return self.dmi.get("System")[0].get("Version", self.default)
def get_uuid(self): def get_uuid(self):
return self.get("System")[0].get("UUID", self.default) return self.dmi.get("System")[0].get("UUID", self.default)
def get_chassis(self): def get_chassis(self):
return self.get("Chassis")[0].get("Type", self.default) return self.dmi.get("Chassis")[0].get("Type", self.default)
def get_type(self): def get_type(self):
chassis_type = self.get_chassis() chassis_type = self.get_chassis()
@ -205,6 +220,7 @@ class ParseSnapshot:
def get_data_storage(self): def get_data_storage(self):
for sm in self.smart: for sm in self.smart:
# import pdb; pdb.set_trace()
model = sm.get('model_name') model = sm.get('model_name')
manufacturer = None manufacturer = None
if len(model.split(" ")) == 2: if len(model.split(" ")) == 2:
@ -241,23 +257,42 @@ class ParseSnapshot:
return x.get(total_capacity) / 1024**2 return x.get(total_capacity) / 1024**2
def get_networks(self): def get_networks(self):
addr = [] hw_class = " Hardware Class: "
for line in self.hwinfo: mac = " Permanent HW Address: "
for y in line: model = " Model: "
if "Permanent HW Address:" in y: wireless = "wireless"
mac = y.split(" Permanent HW Address: ")[1]
addr.extend(mac)
return addr for line in self.hwinfo:
iface = {
"variant": "1",
"actions": [],
"speed": 100.0,
"type": "NetworkAdapter",
"wireless": False,
"manufacturer": "Ethernet",
}
for y in line:
if hw_class in y and not y.split(hw_class)[1] == 'network':
break
if mac in y:
iface["serialNumber"] = y.split(mac)[1]
if model in y:
iface["model"] = y.split(model)[1]
if wireless in y:
iface["wireless"] = True
if iface.get("serialNumber"):
self.components.append(iface)
def parse_hwinfo(self): def parse_hwinfo(self):
hw_blocks = self.hwinfo_raw.split("\n\n") hw_blocks = self.hwinfo_raw.split("\n\n")
return [x.split("\n") for x in hw_blocks] return [x.split("\n") for x in hw_blocks]
def loads(self, x): def loads(self, x):
if isinstance(x, dict) or isinstance(x, list): if isinstance(x, str):
return x return json.loads(x)
return json.loads(x) return x
class LsHw: class LsHw:

View File

@ -416,11 +416,18 @@ class Install(ActionWithOneDevice):
address = Integer(validate=OneOf({8, 16, 32, 64, 128, 256})) address = Integer(validate=OneOf({8, 16, 32, 64, 128, 256}))
class Snapshot2(MarshmallowSchema): class Snapshot_lite_data(MarshmallowSchema):
uuid = UUID() dmidecode = String(required=False)
version = Version(required=True, description='The version of the software.') hwinfo = String(required=False)
smart = String(required=False)
class Snapshot_lite(MarshmallowSchema):
uuid = String()
version = String()
type = String() type = String()
endTime = DateTime('iso', dump_only=True, description=m.Thing.updated.comment) timestamp = String()
data = Nested(Snapshot_lite_data)
@validates_schema @validates_schema
def validate_workbench_version(self, data: dict): def validate_workbench_version(self, data: dict):

View File

@ -14,7 +14,7 @@ from ereuse_devicehub.db import db
from ereuse_devicehub.parser.parser import ParseSnapshot from ereuse_devicehub.parser.parser import ParseSnapshot
from ereuse_devicehub.resources.action.models import RateComputer, Snapshot from ereuse_devicehub.resources.action.models import RateComputer, Snapshot
from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate
from ereuse_devicehub.resources.action.schemas import Snapshot2 from ereuse_devicehub.resources.action.schemas import Snapshot_lite
from ereuse_devicehub.resources.device.models import Computer from ereuse_devicehub.resources.device.models import Computer
from ereuse_devicehub.resources.enums import Severity, SnapshotSoftware from ereuse_devicehub.resources.enums import Severity, SnapshotSoftware
from ereuse_devicehub.resources.user.exceptions import InsufficientPermission from ereuse_devicehub.resources.user.exceptions import InsufficientPermission
@ -136,14 +136,14 @@ class SnapshotView:
if db_device.owner_id != g.user.id: if db_device.owner_id != g.user.id:
raise InsufficientPermission() raise InsufficientPermission()
# Compute ratings # Compute ratings
try: # try:
rate_computer, price = RateComputer.compute(db_device) # rate_computer, price = RateComputer.compute(db_device)
except CannotRate: # except CannotRate:
pass # pass
else: # else:
snapshot.actions.add(rate_computer) # snapshot.actions.add(rate_computer)
if price: # if price:
snapshot.actions.add(price) # snapshot.actions.add(price)
elif snapshot.software == SnapshotSoftware.WorkbenchAndroid: elif snapshot.software == SnapshotSoftware.WorkbenchAndroid:
pass # TODO try except to compute RateMobile pass # TODO try except to compute RateMobile
# Check if HID is null and add Severity:Warning to Snapshot # Check if HID is null and add Severity:Warning to Snapshot
@ -158,10 +158,11 @@ class SnapshotView:
return ret return ret
def validate_json(self, snapshot_json): def validate_json(self, snapshot_json):
self.schema2 = Snapshot2() self.schema2 = Snapshot_lite()
self.snapshot_json = self.schema2.load(snapshot_json) self.snapshot_json = self.schema2.load(snapshot_json)
def build2(self): def build2(self):
snap = ParseSnapshot(self.snapshot_json) snap = ParseSnapshot(self.snapshot_json)
self.snapshot_json = snap.snapshot_json snap_json = snap.snapshot_json
self.snapshot_json = self.resource_def.schema.load(snap_json)
return self.build() return self.build()

View File

@ -1,35 +1,49 @@
""" This is the view for Snapshots """ """ This is the view for Snapshots """
import jwt
import ereuse_utils
from datetime import timedelta from datetime import timedelta
from distutils.version import StrictVersion from distutils.version import StrictVersion
from uuid import UUID from uuid import UUID
from flask import current_app as app, request, g import ereuse_utils
import jwt
from flask import current_app as app
from flask import g, request
from teal.db import ResourceNotFound from teal.db import ResourceNotFound
from teal.marshmallow import ValidationError from teal.marshmallow import ValidationError
from teal.resource import View from teal.resource import View
from ereuse_devicehub.db import db from ereuse_devicehub.db import db
from ereuse_devicehub.query import things_response from ereuse_devicehub.query import things_response
from ereuse_devicehub.resources.action.models import (Action, Snapshot, VisualTest, from ereuse_devicehub.resources.action.models import (
InitTransfer, Live, Allocate, Deallocate, Action,
Trade, Confirm, Revoke) Allocate,
Confirm,
Deallocate,
InitTransfer,
Live,
Revoke,
Snapshot,
Trade,
VisualTest,
)
from ereuse_devicehub.resources.action.views import trade as trade_view 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.action.views.documents import ErasedView
from ereuse_devicehub.resources.device.models import Device, Computer, DataStorage from ereuse_devicehub.resources.action.views.snapshot import (
SnapshotView,
move_json,
save_json,
)
from ereuse_devicehub.resources.device.models import Computer, DataStorage, Device
from ereuse_devicehub.resources.enums import Severity from ereuse_devicehub.resources.enums import Severity
SUPPORTED_WORKBENCH = StrictVersion('11.0') SUPPORTED_WORKBENCH = StrictVersion('11.0')
class AllocateMix(): class AllocateMix:
model = None model = None
def post(self): def post(self):
""" Create one res_obj """ """Create one res_obj"""
res_json = request.get_json() res_json = request.get_json()
res_obj = self.model(**res_json) res_obj = self.model(**res_json)
db.session.add(res_obj) db.session.add(res_obj)
@ -40,13 +54,18 @@ class AllocateMix():
return ret return ret
def find(self, args: dict): def find(self, args: dict):
res_objs = self.model.query.filter_by(author=g.user) \ res_objs = (
.order_by(self.model.created.desc()) \ self.model.query.filter_by(author=g.user)
.order_by(self.model.created.desc())
.paginate(per_page=200) .paginate(per_page=200)
)
return things_response( return things_response(
self.schema.dump(res_objs.items, many=True, nested=0), self.schema.dump(res_objs.items, many=True, nested=0),
res_objs.page, res_objs.per_page, res_objs.total, res_objs.page,
res_objs.prev_num, res_objs.next_num res_objs.per_page,
res_objs.total,
res_objs.prev_num,
res_objs.next_num,
) )
@ -99,7 +118,9 @@ class LiveView(View):
if not serial_number: if not serial_number:
"""There aren't any disk""" """There aren't any disk"""
raise ResourceNotFound("There aren't any disk in this device {}".format(device)) raise ResourceNotFound(
"There aren't any disk in this device {}".format(device)
)
return usage_time_hdd, serial_number return usage_time_hdd, serial_number
def get_hid(self, snapshot): def get_hid(self, snapshot):
@ -109,8 +130,11 @@ class LiveView(View):
return None return None
if not components: if not components:
return device.hid return device.hid
macs = [c.serial_number for c in components macs = [
if c.type == 'NetworkAdapter' and c.serial_number is not None] c.serial_number
for c in components
if c.type == 'NetworkAdapter' and c.serial_number is not None
]
macs.sort() macs.sort()
mac = '' mac = ''
hid = device.hid hid = device.hid
@ -124,12 +148,10 @@ class LiveView(View):
def live(self, snapshot): def live(self, snapshot):
"""If the device.allocated == True, then this snapshot create an action live.""" """If the device.allocated == True, then this snapshot create an action live."""
hid = self.get_hid(snapshot) hid = self.get_hid(snapshot)
if not hid or not Device.query.filter( if not hid or not Device.query.filter(Device.hid == hid).count():
Device.hid == hid).count():
raise ValidationError('Device not exist.') raise ValidationError('Device not exist.')
device = Device.query.filter( device = Device.query.filter(Device.hid == hid, Device.allocated == True).one()
Device.hid == hid, Device.allocated == True).one()
# Is not necessary # Is not necessary
if not device: if not device:
raise ValidationError('Device not exist.') raise ValidationError('Device not exist.')
@ -138,16 +160,18 @@ class LiveView(View):
usage_time_hdd, serial_number = self.get_hdd_details(snapshot, device) usage_time_hdd, serial_number = self.get_hdd_details(snapshot, device)
data_live = {'usage_time_hdd': usage_time_hdd, data_live = {
'serial_number': serial_number, 'usage_time_hdd': usage_time_hdd,
'snapshot_uuid': snapshot['uuid'], 'serial_number': serial_number,
'description': '', 'snapshot_uuid': snapshot['uuid'],
'software': snapshot['software'], 'description': '',
'software_version': snapshot['version'], 'software': snapshot['software'],
'licence_version': snapshot['licence_version'], 'software_version': snapshot['version'],
'author_id': device.owner_id, 'licence_version': snapshot['licence_version'],
'agent_id': device.owner.individual.id, 'author_id': device.owner_id,
'device': device} 'agent_id': device.owner.individual.id,
'device': device,
}
live = Live(**data_live) live = Live(**data_live)
@ -172,7 +196,12 @@ class LiveView(View):
def decode_snapshot(data): def decode_snapshot(data):
try: try:
return jwt.decode(data['data'], app.config['JWT_PASS'], algorithms="HS256", json_encoder=ereuse_utils.JSONEncoder) return jwt.decode(
data['data'],
app.config['JWT_PASS'],
algorithms="HS256",
json_encoder=ereuse_utils.JSONEncoder,
)
except jwt.exceptions.InvalidSignatureError as err: except jwt.exceptions.InvalidSignatureError as err:
txt = 'Invalid snapshot' txt = 'Invalid snapshot'
raise ValidationError(txt) raise ValidationError(txt)
@ -200,13 +229,13 @@ class ActionView(View):
# TODO @cayop uncomment at four weeks # TODO @cayop uncomment at four weeks
# if not 'data' in json: # if not 'data' in json:
# txt = 'Invalid snapshot' # txt = 'Invalid snapshot'
# raise ValidationError(txt) # raise ValidationError(txt)
# snapshot_data = decode_snapshot(json) # snapshot_data = decode_snapshot(json)
snapshot_data = json snapshot_data = json
if 'data' in json: if 'data' in json and not json.get("data", {}).get("dmidecode"):
snapshot_data = decode_snapshot(json) snapshot_data = decode_snapshot(json)
if not snapshot_data: if not snapshot_data:
@ -248,7 +277,9 @@ class ActionView(View):
return confirm.post() return confirm.post()
if json['type'] == 'ConfirmRevokeDocument': if json['type'] == 'ConfirmRevokeDocument':
confirm_revoke = trade_view.ConfirmRevokeDocumentView(json, resource_def, self.schema) confirm_revoke = trade_view.ConfirmRevokeDocumentView(
json, resource_def, self.schema
)
return confirm_revoke.post() return confirm_revoke.post()
if json['type'] == 'DataWipe': if json['type'] == 'DataWipe':

View File

@ -8,6 +8,7 @@ import inflection
@unique @unique
class SnapshotSoftware(Enum): class SnapshotSoftware(Enum):
"""The software used to perform the Snapshot.""" """The software used to perform the Snapshot."""
Workbench = 'Workbench' Workbench = 'Workbench'
WorkbenchAndroid = 'WorkbenchAndroid' WorkbenchAndroid = 'WorkbenchAndroid'
AndroidApp = 'AndroidApp' AndroidApp = 'AndroidApp'
@ -36,6 +37,7 @@ class RatingRange(IntEnum):
3. Medium. 3. Medium.
4. High. 4. High.
""" """
VERY_LOW = 1 VERY_LOW = 1
LOW = 2 LOW = 2
MEDIUM = 3 MEDIUM = 3
@ -69,6 +71,7 @@ class PriceSoftware(Enum):
@unique @unique
class AppearanceRange(Enum): class AppearanceRange(Enum):
"""Grades the imperfections that aesthetically affect the device, but not its usage.""" """Grades the imperfections that aesthetically affect the device, but not its usage."""
Z = 'Z. The device is new' Z = 'Z. The device is new'
A = 'A. Is like new; without visual damage' A = 'A. Is like new; without visual damage'
B = 'B. Is in really good condition; small visual damage in difficult places to spot' B = 'B. Is in really good condition; small visual damage in difficult places to spot'
@ -83,6 +86,7 @@ class AppearanceRange(Enum):
@unique @unique
class FunctionalityRange(Enum): class FunctionalityRange(Enum):
"""Grades the defects of a device that affect its usage.""" """Grades the defects of a device that affect its usage."""
A = 'A. All the buttons works perfectly, no screen/camera defects and chassis without usage issues' A = 'A. All the buttons works perfectly, no screen/camera defects and chassis without usage issues'
B = 'B. There is a button difficult to press or unstable it, a screen/camera defect or chassis problem' B = 'B. There is a button difficult to press or unstable it, a screen/camera defect or chassis problem'
C = 'C. Chassis defects or multiple buttons don\'t work; broken or unusable it, some screen/camera defect' C = 'C. Chassis defects or multiple buttons don\'t work; broken or unusable it, some screen/camera defect'
@ -95,6 +99,7 @@ class FunctionalityRange(Enum):
@unique @unique
class BatteryHealthRange(Enum): class BatteryHealthRange(Enum):
"""Grade the battery health status, depending on self report Android system""" """Grade the battery health status, depending on self report Android system"""
A = 'A. The battery health is very good' A = 'A. The battery health is very good'
B = 'B. Battery health is good' B = 'B. Battery health is good'
C = 'C. Battery health is overheat / over voltage status but can stand the minimum duration' C = 'C. Battery health is overheat / over voltage status but can stand the minimum duration'
@ -109,6 +114,7 @@ class BatteryHealthRange(Enum):
@unique @unique
class BiosAccessRange(Enum): class BiosAccessRange(Enum):
"""How difficult it has been to set the bios to boot from the network.""" """How difficult it has been to set the bios to boot from the network."""
A = 'A. If by pressing a key you could access a boot menu with the network boot' A = 'A. If by pressing a key you could access a boot menu with the network boot'
B = 'B. You had to get into the BIOS, and in less than 5 steps you could set the network boot' B = 'B. You had to get into the BIOS, and in less than 5 steps you could set the network boot'
C = 'C. Like B, but with more than 5 steps' C = 'C. Like B, but with more than 5 steps'
@ -139,6 +145,7 @@ class ImageSoftware(Enum):
@unique @unique
class ImageMimeTypes(Enum): class ImageMimeTypes(Enum):
"""Supported image Mimetypes for Devicehub.""" """Supported image Mimetypes for Devicehub."""
jpg = 'image/jpeg' jpg = 'image/jpeg'
png = 'image/png' png = 'image/png'
@ -149,6 +156,7 @@ BOX_RATE_3 = 1, 3
# After looking at own databases # After looking at own databases
@unique @unique
class RamInterface(Enum): class RamInterface(Enum):
""" """
@ -163,6 +171,7 @@ class RamInterface(Enum):
here for those cases where there is no more specific information. here for those cases where there is no more specific information.
Please, try to always use DDRø-6 denominations. Please, try to always use DDRø-6 denominations.
""" """
SDRAM = 'SDRAM' SDRAM = 'SDRAM'
DDR = 'DDR SDRAM' DDR = 'DDR SDRAM'
DDR2 = 'DDR2 SDRAM' DDR2 = 'DDR2 SDRAM'
@ -170,6 +179,7 @@ class RamInterface(Enum):
DDR4 = 'DDR4 SDRAM' DDR4 = 'DDR4 SDRAM'
DDR5 = 'DDR5 SDRAM' DDR5 = 'DDR5 SDRAM'
DDR6 = 'DDR6 SDRAM' DDR6 = 'DDR6 SDRAM'
LPDDR3 = 'LPDDR3'
def __str__(self): def __str__(self):
return self.value return self.value
@ -189,6 +199,7 @@ class DataStorageInterface(Enum):
ATA = 'ATA' ATA = 'ATA'
USB = 'USB' USB = 'USB'
PCI = 'PCI' PCI = 'PCI'
NVMe = 'NVMe'
def __str__(self): def __str__(self):
return self.value return self.value
@ -211,6 +222,7 @@ class DisplayTech(Enum):
@unique @unique
class ComputerChassis(Enum): class ComputerChassis(Enum):
"""The chassis of a computer.""" """The chassis of a computer."""
Tower = 'Tower' Tower = 'Tower'
Docking = 'Docking' Docking = 'Docking'
AllInOne = 'All in one' AllInOne = 'All in one'
@ -235,6 +247,7 @@ class ReceiverRole(Enum):
The role that the receiver takes in the reception; The role that the receiver takes in the reception;
the meaning of the reception. the meaning of the reception.
""" """
Intermediary = 'Generic user in the workflow of the device.' Intermediary = 'Generic user in the workflow of the device.'
FinalUser = 'The user that will use the device.' FinalUser = 'The user that will use the device.'
CollectionPoint = 'A collection point.' CollectionPoint = 'A collection point.'
@ -244,6 +257,7 @@ class ReceiverRole(Enum):
class PrinterTechnology(Enum): class PrinterTechnology(Enum):
"""Technology of the printer.""" """Technology of the printer."""
Toner = 'Toner / Laser' Toner = 'Toner / Laser'
Inkjet = 'Liquid inkjet' Inkjet = 'Liquid inkjet'
SolidInk = 'Solid ink' SolidInk = 'Solid ink'
@ -260,6 +274,7 @@ class CameraFacing(Enum):
@unique @unique
class BatteryHealth(Enum): class BatteryHealth(Enum):
"""The battery health status as in Android.""" """The battery health status as in Android."""
Cold = 'Cold' Cold = 'Cold'
Dead = 'Dead' Dead = 'Dead'
Good = 'Good' Good = 'Good'
@ -274,6 +289,7 @@ class BatteryTechnology(Enum):
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power
adding ``Alkaline``. adding ``Alkaline``.
""" """
LiIon = 'Lithium-ion' LiIon = 'Lithium-ion'
NiCd = 'Nickel-Cadmium' NiCd = 'Nickel-Cadmium'
NiMH = 'Nickel-metal hydride' NiMH = 'Nickel-metal hydride'
@ -329,10 +345,11 @@ class PhysicalErasureMethod(Enum):
and non able to be re-built. and non able to be re-built.
""" """
Shred = 'Reduction of the data-storage to the required certified ' \ Shred = 'Reduction of the data-storage to the required certified ' 'standard sizes.'
'standard sizes.' Disintegration = (
Disintegration = 'Reduction of the data-storage to smaller sizes ' \ 'Reduction of the data-storage to smaller sizes '
'than the certified standard ones.' 'than the certified standard ones.'
)
def __str__(self): def __str__(self):
return self.name return self.name
@ -362,20 +379,21 @@ class ErasureStandards(Enum):
def from_data_storage(cls, erasure) -> Set['ErasureStandards']: def from_data_storage(cls, erasure) -> Set['ErasureStandards']:
"""Returns a set of erasure standards.""" """Returns a set of erasure standards."""
from ereuse_devicehub.resources.action import models as actions from ereuse_devicehub.resources.action import models as actions
standards = set() standards = set()
if isinstance(erasure, actions.EraseSectors): if isinstance(erasure, actions.EraseSectors):
with suppress(ValueError): with suppress(ValueError):
first_step, *other_steps = erasure.steps first_step, *other_steps = erasure.steps
if isinstance(first_step, actions.StepZero) \ if isinstance(first_step, actions.StepZero) and all(
and all(isinstance(step, actions.StepRandom) for step in other_steps): isinstance(step, actions.StepRandom) for step in other_steps
):
standards.add(cls.HMG_IS5) standards.add(cls.HMG_IS5)
return standards return standards
@unique @unique
class TransferState(IntEnum): class TransferState(IntEnum):
"""State of transfer for a given Lot of devices. """State of transfer for a given Lot of devices."""
"""
""" """
* Initial: No transfer action in place. * Initial: No transfer action in place.
@ -393,7 +411,7 @@ class TransferState(IntEnum):
def __str__(self): def __str__(self):
return self.name return self.name
@unique @unique
class SessionType(IntEnum): class SessionType(IntEnum):