Add Device problems, privacy, working; Add event ErasePhysical
This commit is contained in:
parent
e009bf4bc1
commit
bd0eb3aad3
|
@ -6,13 +6,15 @@ skinparam ranksep 1
|
||||||
[*] -> Registered
|
[*] -> Registered
|
||||||
|
|
||||||
state Attributes {
|
state Attributes {
|
||||||
|
|
||||||
state Broken : cannot turn on
|
state Broken : cannot turn on
|
||||||
state Owners
|
state Owners
|
||||||
state Usufructuarees
|
state Usufructuarees
|
||||||
state Reservees
|
state Reservees
|
||||||
state "Physical\nPossessor"
|
state "Physical\nPossessor"
|
||||||
state "Waste\n\Product"
|
state "Waste\n\Product"
|
||||||
|
state problems : List of current events \nwith Warn/Error
|
||||||
|
state privacy : Set of\ncurrent erasures
|
||||||
|
state working : List of current events\naffecting working
|
||||||
}
|
}
|
||||||
|
|
||||||
state Physical {
|
state Physical {
|
||||||
|
@ -44,10 +46,4 @@ state Trading {
|
||||||
Renting --> Cancelled : Cancel
|
Renting --> Cancelled : Cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
state DataStoragePrivacyCompliance {
|
|
||||||
state Erased
|
|
||||||
state Destroyed
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@enduml
|
@enduml
|
||||||
|
|
|
@ -8,6 +8,7 @@ from typing import Dict, List, Set
|
||||||
from boltons import urlutils
|
from boltons import urlutils
|
||||||
from citext import CIText
|
from citext import CIText
|
||||||
from ereuse_utils.naming import Naming
|
from ereuse_utils.naming import Naming
|
||||||
|
from more_itertools import unique_everseen
|
||||||
from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \
|
from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \
|
||||||
Sequence, SmallInteger, Unicode, inspect, text
|
Sequence, SmallInteger, Unicode, inspect, text
|
||||||
from sqlalchemy.ext.declarative import declared_attr
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
|
@ -22,8 +23,8 @@ from teal.marshmallow import ValidationError
|
||||||
from teal.resource import url_for_resource
|
from teal.resource import url_for_resource
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \
|
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, DisplayTech, \
|
||||||
DataStoragePrivacyCompliance, DisplayTech, PrinterTechnology, RamFormat, RamInterface
|
PrinterTechnology, RamFormat, RamInterface, Severity
|
||||||
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ class Device(Thing):
|
||||||
"""
|
"""
|
||||||
Base class for any type of physical object that can be identified.
|
Base class for any type of physical object that can be identified.
|
||||||
"""
|
"""
|
||||||
|
EVENT_SORT_KEY = attrgetter('created')
|
||||||
|
|
||||||
id = Column(BigInteger, Sequence('device_seq'), primary_key=True)
|
id = Column(BigInteger, Sequence('device_seq'), primary_key=True)
|
||||||
id.comment = """
|
id.comment = """
|
||||||
|
@ -77,6 +79,11 @@ class Device(Thing):
|
||||||
'color'
|
'color'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kw) -> None:
|
||||||
|
super().__init__(**kw)
|
||||||
|
with suppress(TypeError):
|
||||||
|
self.hid = Naming.hid(self.manufacturer, self.serial_number, self.model)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def events(self) -> list:
|
def events(self) -> list:
|
||||||
"""
|
"""
|
||||||
|
@ -86,12 +93,25 @@ class Device(Thing):
|
||||||
|
|
||||||
Events are returned by ascending creation time.
|
Events are returned by ascending creation time.
|
||||||
"""
|
"""
|
||||||
return sorted(chain(self.events_multiple, self.events_one), key=attrgetter('created'))
|
return sorted(chain(self.events_multiple, self.events_one), key=self.EVENT_SORT_KEY)
|
||||||
|
|
||||||
def __init__(self, **kw) -> None:
|
@property
|
||||||
super().__init__(**kw)
|
def problems(self):
|
||||||
with suppress(TypeError):
|
"""Current events with severity.Warning or higher.
|
||||||
self.hid = Naming.hid(self.manufacturer, self.serial_number, self.model)
|
|
||||||
|
There can be up to 3 events: current Snapshot,
|
||||||
|
current Physical event, current Trading event.
|
||||||
|
"""
|
||||||
|
from ereuse_devicehub.resources.device import states
|
||||||
|
from ereuse_devicehub.resources.event.models import Snapshot
|
||||||
|
events = set()
|
||||||
|
with suppress(LookupError, ValueError):
|
||||||
|
events.add(self.last_event_of(Snapshot))
|
||||||
|
with suppress(LookupError, ValueError):
|
||||||
|
events.add(self.last_event_of(*states.Physical.events()))
|
||||||
|
with suppress(LookupError, ValueError):
|
||||||
|
events.add(self.last_event_of(*states.Trading.events()))
|
||||||
|
return self._warning_events(events)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def physical_properties(self) -> Dict[str, object or None]:
|
def physical_properties(self) -> Dict[str, object or None]:
|
||||||
|
@ -164,6 +184,20 @@ class Device(Thing):
|
||||||
event = self.last_event_of(Receive)
|
event = self.last_event_of(Receive)
|
||||||
return event.agent
|
return event.agent
|
||||||
|
|
||||||
|
@property
|
||||||
|
def working(self):
|
||||||
|
"""A list of the current tests with warning or errors. A
|
||||||
|
device is working if the list is empty.
|
||||||
|
|
||||||
|
This property returns, for the last test performed of each type,
|
||||||
|
the one with the worst severity of them, or None if no
|
||||||
|
test has been executed.
|
||||||
|
"""
|
||||||
|
from ereuse_devicehub.resources.event.models import Test
|
||||||
|
current_tests = unique_everseen((e for e in reversed(self.events) if isinstance(e, Test)),
|
||||||
|
key=attrgetter('type')) # last test of each type
|
||||||
|
return self._warning_events(current_tests)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def __mapper_args__(cls):
|
def __mapper_args__(cls):
|
||||||
"""
|
"""
|
||||||
|
@ -188,6 +222,10 @@ class Device(Thing):
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise LookupError('{!r} does not contain events of types {}.'.format(self, types))
|
raise LookupError('{!r} does not contain events of types {}.'.format(self, types))
|
||||||
|
|
||||||
|
def _warning_events(self, events):
|
||||||
|
return sorted((ev for ev in events if ev.severity >= Severity.Warning),
|
||||||
|
key=self.EVENT_SORT_KEY)
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
return self.id < other.id
|
return self.id < other.id
|
||||||
|
|
||||||
|
@ -255,7 +293,7 @@ class Computer(Device):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def events(self) -> list:
|
def events(self) -> list:
|
||||||
return sorted(chain(super().events, self.events_parent), key=attrgetter('created'))
|
return sorted(chain(super().events, self.events_parent), key=self.EVENT_SORT_KEY)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ram_size(self) -> int:
|
def ram_size(self) -> int:
|
||||||
|
@ -294,6 +332,17 @@ class Computer(Device):
|
||||||
speeds[net.wireless] = max(net.speed or 0, speeds[net.wireless] or 0)
|
speeds[net.wireless] = max(net.speed or 0, speeds[net.wireless] or 0)
|
||||||
return speeds
|
return speeds
|
||||||
|
|
||||||
|
@property
|
||||||
|
def privacy(self):
|
||||||
|
"""Returns the privacy of all DataStorage components when
|
||||||
|
it is None.
|
||||||
|
"""
|
||||||
|
return set(
|
||||||
|
privacy for privacy in
|
||||||
|
(hdd.privacy for hdd in self.components if isinstance(hdd, DataStorage))
|
||||||
|
if privacy
|
||||||
|
)
|
||||||
|
|
||||||
def __format__(self, format_spec):
|
def __format__(self, format_spec):
|
||||||
if not format_spec:
|
if not format_spec:
|
||||||
return super().__format__(format_spec)
|
return super().__format__(format_spec)
|
||||||
|
@ -405,7 +454,7 @@ class Component(Device):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def events(self) -> list:
|
def events(self) -> list:
|
||||||
return sorted(chain(super().events, self.events_components), key=attrgetter('created'))
|
return sorted(chain(super().events, self.events_components), key=self.EVENT_SORT_KEY)
|
||||||
|
|
||||||
|
|
||||||
class JoinedComponentTableMixin:
|
class JoinedComponentTableMixin:
|
||||||
|
@ -431,11 +480,12 @@ class DataStorage(JoinedComponentTableMixin, Component):
|
||||||
@property
|
@property
|
||||||
def privacy(self):
|
def privacy(self):
|
||||||
"""Returns the privacy compliance state of the data storage."""
|
"""Returns the privacy compliance state of the data storage."""
|
||||||
# todo add physical destruction event
|
|
||||||
from ereuse_devicehub.resources.event.models import EraseBasic
|
from ereuse_devicehub.resources.event.models import EraseBasic
|
||||||
with suppress(LookupError):
|
try:
|
||||||
erase = self.last_event_of(EraseBasic)
|
ev = self.last_event_of(EraseBasic)
|
||||||
return DataStoragePrivacyCompliance.from_erase(erase)
|
except LookupError:
|
||||||
|
ev = None
|
||||||
|
return ev
|
||||||
|
|
||||||
def __format__(self, format_spec):
|
def __format__(self, format_spec):
|
||||||
v = super().__format__(format_spec)
|
v = super().__format__(format_spec)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, List, Set, Type, Union
|
from operator import attrgetter
|
||||||
|
from typing import Dict, Generator, Iterable, List, Optional, Set, Type
|
||||||
|
|
||||||
from boltons import urlutils
|
from boltons import urlutils
|
||||||
from boltons.urlutils import URL
|
from boltons.urlutils import URL
|
||||||
|
@ -11,8 +12,8 @@ from teal.enums import Layouts
|
||||||
|
|
||||||
from ereuse_devicehub.resources.agent.models import Agent
|
from ereuse_devicehub.resources.agent.models import Agent
|
||||||
from ereuse_devicehub.resources.device import states
|
from ereuse_devicehub.resources.device import states
|
||||||
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \
|
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, DisplayTech, \
|
||||||
DataStoragePrivacyCompliance, DisplayTech, PrinterTechnology, RamFormat, RamInterface
|
PrinterTechnology, RamFormat, RamInterface
|
||||||
from ereuse_devicehub.resources.event import models as e
|
from ereuse_devicehub.resources.event import models as e
|
||||||
from ereuse_devicehub.resources.image.models import ImageList
|
from ereuse_devicehub.resources.image.models import ImageList
|
||||||
from ereuse_devicehub.resources.lot.models import Lot
|
from ereuse_devicehub.resources.lot.models import Lot
|
||||||
|
@ -21,6 +22,8 @@ from ereuse_devicehub.resources.tag import Tag
|
||||||
|
|
||||||
|
|
||||||
class Device(Thing):
|
class Device(Thing):
|
||||||
|
EVENT_SORT_KEY = attrgetter('created')
|
||||||
|
|
||||||
id = ... # type: Column
|
id = ... # type: Column
|
||||||
type = ... # type: Column
|
type = ... # type: Column
|
||||||
hid = ... # type: Column
|
hid = ... # type: Column
|
||||||
|
@ -48,7 +51,6 @@ class Device(Thing):
|
||||||
self.height = ... # type: float
|
self.height = ... # type: float
|
||||||
self.depth = ... # type: float
|
self.depth = ... # type: float
|
||||||
self.color = ... # type: Color
|
self.color = ... # type: Color
|
||||||
self.events = ... # type: List[e.Event]
|
|
||||||
self.physical_properties = ... # type: Dict[str, object or None]
|
self.physical_properties = ... # type: Dict[str, object or None]
|
||||||
self.events_multiple = ... # type: Set[e.EventWithMultipleDevices]
|
self.events_multiple = ... # type: Set[e.EventWithMultipleDevices]
|
||||||
self.events_one = ... # type: Set[e.EventWithOneDevice]
|
self.events_one = ... # type: Set[e.EventWithOneDevice]
|
||||||
|
@ -57,33 +59,48 @@ class Device(Thing):
|
||||||
self.lots = ... # type: Set[Lot]
|
self.lots = ... # type: Set[Lot]
|
||||||
self.production_date = ... # type: datetime
|
self.production_date = ... # type: datetime
|
||||||
|
|
||||||
|
@property
|
||||||
|
def events(self) -> List[e.Event]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def problems(self) -> List[e.Event]:
|
||||||
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self) -> urlutils.URL:
|
def url(self) -> urlutils.URL:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rate(self) -> Union[e.AggregateRate, None]:
|
def rate(self) -> Optional[e.AggregateRate]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def price(self) -> Union[e.Price, None]:
|
def price(self) -> Optional[e.Price]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def trading(self) -> Union[states.Trading, None]:
|
def trading(self) -> Optional[states.Trading]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def physical(self) -> Union[states.Physical, None]:
|
def physical(self) -> Optional[states.Physical]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def physical_possessor(self) -> Union[Agent, None]:
|
def physical_possessor(self) -> Optional[Agent]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def working(self) -> List[e.Test]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def last_event_of(self, *types: Type[e.Event]) -> e.Event:
|
def last_event_of(self, *types: Type[e.Event]) -> e.Event:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _warning_events(self, events: Iterable[e.Event]) -> Generator[e.Event]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DisplayMixin:
|
class DisplayMixin:
|
||||||
technology = ... # type: Column
|
technology = ... # type: Column
|
||||||
|
@ -139,6 +156,10 @@ class Computer(DisplayMixin, Device):
|
||||||
def network_speeds(self) -> List[int]:
|
def network_speeds(self) -> List[int]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def privacy(self) -> Set[e.EraseBasic]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Desktop(Computer):
|
class Desktop(Computer):
|
||||||
pass
|
pass
|
||||||
|
@ -219,7 +240,7 @@ class DataStorage(Component):
|
||||||
self.interface = ... # type: DataStorageInterface
|
self.interface = ... # type: DataStorageInterface
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def privacy(self) -> DataStoragePrivacyCompliance:
|
def privacy(self) -> Optional[e.EraseBasic]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,8 @@ from teal.marshmallow import EnumField, SanitizedStr, URL, ValidationError
|
||||||
from teal.resource import Schema
|
from teal.resource import Schema
|
||||||
|
|
||||||
from ereuse_devicehub.marshmallow import NestedOn
|
from ereuse_devicehub.marshmallow import NestedOn
|
||||||
|
from ereuse_devicehub.resources import enums
|
||||||
from ereuse_devicehub.resources.device import models as m, states
|
from ereuse_devicehub.resources.device import models as m, states
|
||||||
from ereuse_devicehub.resources.enums import ComputerChassis, DataStorageInterface, \
|
|
||||||
DataStoragePrivacyCompliance, DisplayTech, PrinterTechnology, RamFormat, RamInterface
|
|
||||||
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
|
||||||
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
|
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
|
||||||
|
|
||||||
|
@ -31,6 +30,7 @@ class Device(Thing):
|
||||||
depth = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.depth.comment)
|
depth = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.depth.comment)
|
||||||
events = NestedOn('Event', many=True, dump_only=True, description=m.Device.events.__doc__)
|
events = NestedOn('Event', many=True, dump_only=True, description=m.Device.events.__doc__)
|
||||||
events_one = NestedOn('Event', many=True, load_only=True, collection_class=OrderedSet)
|
events_one = NestedOn('Event', many=True, load_only=True, collection_class=OrderedSet)
|
||||||
|
problems = NestedOn('Event', many=True, dump_only=True, description=m.Device.problems.__doc__)
|
||||||
url = URL(dump_only=True, description=m.Device.url.__doc__)
|
url = URL(dump_only=True, description=m.Device.url.__doc__)
|
||||||
lots = NestedOn('Lot',
|
lots = NestedOn('Lot',
|
||||||
many=True,
|
many=True,
|
||||||
|
@ -44,6 +44,10 @@ class Device(Thing):
|
||||||
production_date = DateTime('iso',
|
production_date = DateTime('iso',
|
||||||
description=m.Device.updated.comment,
|
description=m.Device.updated.comment,
|
||||||
data_key='productionDate')
|
data_key='productionDate')
|
||||||
|
working = NestedOn('Event',
|
||||||
|
many=True,
|
||||||
|
dump_only=True,
|
||||||
|
description=m.Device.working.__doc__)
|
||||||
|
|
||||||
@pre_load
|
@pre_load
|
||||||
def from_events_to_events_one(self, data: dict):
|
def from_events_to_events_one(self, data: dict):
|
||||||
|
@ -72,12 +76,13 @@ class Device(Thing):
|
||||||
|
|
||||||
class Computer(Device):
|
class Computer(Device):
|
||||||
components = NestedOn('Component', many=True, dump_only=True, collection_class=OrderedSet)
|
components = NestedOn('Component', many=True, dump_only=True, collection_class=OrderedSet)
|
||||||
chassis = EnumField(ComputerChassis, required=True)
|
chassis = EnumField(enums.ComputerChassis, required=True)
|
||||||
ram_size = Integer(dump_only=True, data_key='ramSize')
|
ram_size = Integer(dump_only=True, data_key='ramSize')
|
||||||
data_storage_size = Integer(dump_only=True, data_key='dataStorageSize')
|
data_storage_size = Integer(dump_only=True, data_key='dataStorageSize')
|
||||||
processor_model = Str(dump_only=True, data_key='processorModel')
|
processor_model = Str(dump_only=True, data_key='processorModel')
|
||||||
graphic_card_model = Str(dump_only=True, data_key='graphicCardModel')
|
graphic_card_model = Str(dump_only=True, data_key='graphicCardModel')
|
||||||
network_speeds = List(Integer(dump_only=True), dump_only=True, data_key='networkSpeeds')
|
network_speeds = List(Integer(dump_only=True), dump_only=True, data_key='networkSpeeds')
|
||||||
|
privacy = NestedOn('Event', many=True, dump_only=True, collection_class=set)
|
||||||
|
|
||||||
|
|
||||||
class Desktop(Computer):
|
class Desktop(Computer):
|
||||||
|
@ -94,7 +99,7 @@ class Server(Computer):
|
||||||
|
|
||||||
class DisplayMixin:
|
class DisplayMixin:
|
||||||
size = Float(description=m.DisplayMixin.size.comment, validate=Range(2, 150))
|
size = Float(description=m.DisplayMixin.size.comment, validate=Range(2, 150))
|
||||||
technology = EnumField(DisplayTech,
|
technology = EnumField(enums.DisplayTech,
|
||||||
description=m.DisplayMixin.technology.comment)
|
description=m.DisplayMixin.technology.comment)
|
||||||
resolution_width = Integer(data_key='resolutionWidth',
|
resolution_width = Integer(data_key='resolutionWidth',
|
||||||
validate=Range(10, 20000),
|
validate=Range(10, 20000),
|
||||||
|
@ -168,8 +173,8 @@ class DataStorage(Component):
|
||||||
size = Integer(validate=Range(0, 10 ** 8),
|
size = Integer(validate=Range(0, 10 ** 8),
|
||||||
unit=UnitCodes.mbyte,
|
unit=UnitCodes.mbyte,
|
||||||
description=m.DataStorage.size.comment)
|
description=m.DataStorage.size.comment)
|
||||||
interface = EnumField(DataStorageInterface)
|
interface = EnumField(enums.DataStorageInterface)
|
||||||
privacy = EnumField(DataStoragePrivacyCompliance, dump_only=True)
|
privacy = NestedOn('Event', dump_only=True)
|
||||||
|
|
||||||
|
|
||||||
class HardDrive(DataStorage):
|
class HardDrive(DataStorage):
|
||||||
|
@ -203,8 +208,8 @@ class Processor(Component):
|
||||||
class RamModule(Component):
|
class RamModule(Component):
|
||||||
size = Integer(validate=Range(min=128, max=17000), unit=UnitCodes.mbyte)
|
size = Integer(validate=Range(min=128, max=17000), unit=UnitCodes.mbyte)
|
||||||
speed = Integer(validate=Range(min=100, max=10000), unit=UnitCodes.mhz)
|
speed = Integer(validate=Range(min=100, max=10000), unit=UnitCodes.mhz)
|
||||||
interface = EnumField(RamInterface)
|
interface = EnumField(enums.RamInterface)
|
||||||
format = EnumField(RamFormat)
|
format = EnumField(enums.RamFormat)
|
||||||
|
|
||||||
|
|
||||||
class SoundCard(Component):
|
class SoundCard(Component):
|
||||||
|
@ -264,7 +269,7 @@ class WirelessAccessPoint(Networking):
|
||||||
class Printer(Device):
|
class Printer(Device):
|
||||||
wireless = Boolean(required=True, missing=False)
|
wireless = Boolean(required=True, missing=False)
|
||||||
scanning = Boolean(required=True, missing=False)
|
scanning = Boolean(required=True, missing=False)
|
||||||
technology = EnumField(PrinterTechnology, required=True)
|
technology = EnumField(enums.PrinterTechnology, required=True)
|
||||||
monochrome = Boolean(required=True, missing=True)
|
monochrome = Boolean(required=True, missing=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -260,25 +260,6 @@ class ReceiverRole(Enum):
|
||||||
Transporter = 'An user that ships the devices to another one.'
|
Transporter = 'An user that ships the devices to another one.'
|
||||||
|
|
||||||
|
|
||||||
class DataStoragePrivacyCompliance(Enum):
|
|
||||||
EraseBasic = 'EraseBasic'
|
|
||||||
EraseBasicError = 'EraseBasicError'
|
|
||||||
EraseSectors = 'EraseSectors'
|
|
||||||
EraseSectorsError = 'EraseSectorsError'
|
|
||||||
Destruction = 'Destruction'
|
|
||||||
DestructionError = 'DestructionError'
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_erase(cls, erasure) -> 'DataStoragePrivacyCompliance':
|
|
||||||
"""Returns the correct enum depending of the passed-in erasure."""
|
|
||||||
from ereuse_devicehub.resources.event.models import EraseSectors
|
|
||||||
if isinstance(erasure, EraseSectors):
|
|
||||||
c = cls.EraseSectors if erasure.severity != Severity.Error else cls.EraseSectorsError
|
|
||||||
else:
|
|
||||||
c = cls.EraseBasic if erasure.severity == Severity.Error else cls.EraseBasicError
|
|
||||||
return c
|
|
||||||
|
|
||||||
|
|
||||||
class PrinterTechnology(Enum):
|
class PrinterTechnology(Enum):
|
||||||
"""Technology of the printer."""
|
"""Technology of the printer."""
|
||||||
Toner = 'Toner / Laser'
|
Toner = 'Toner / Laser'
|
||||||
|
|
|
@ -299,6 +299,12 @@ class EraseSectors(EraseBasic):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ErasePhysical(EraseBasic):
|
||||||
|
"""Physical destruction of a data storage unit."""
|
||||||
|
# todo add attributes
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Step(db.Model):
|
class Step(db.Model):
|
||||||
erasure_id = Column(UUID(as_uuid=True), ForeignKey(EraseBasic.id), primary_key=True)
|
erasure_id = Column(UUID(as_uuid=True), ForeignKey(EraseBasic.id), primary_key=True)
|
||||||
type = Column(Unicode(STR_SM_SIZE), nullable=False)
|
type = Column(Unicode(STR_SM_SIZE), nullable=False)
|
||||||
|
|
|
@ -73,6 +73,11 @@ def test_device_model():
|
||||||
assert d.GraphicCard.query.first() is None, 'We should have deleted it –it was inside the pc'
|
assert d.GraphicCard.query.first() is None, 'We should have deleted it –it was inside the pc'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason='Test not developed')
|
||||||
|
def test_device_problems():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
@pytest.mark.usefixtures(conftest.app_context.__name__)
|
||||||
def test_device_schema():
|
def test_device_schema():
|
||||||
"""Ensures the user does not upload non-writable or extra fields."""
|
"""Ensures the user does not upload non-writable or extra fields."""
|
||||||
|
|
|
@ -86,18 +86,35 @@ def test_erase_sectors_steps():
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
||||||
def test_test_data_storage():
|
def test_test_data_storage_working():
|
||||||
|
"""Tests TestDataStorage with the resulting properties in Device."""
|
||||||
|
hdd = HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar')
|
||||||
test = models.TestDataStorage(
|
test = models.TestDataStorage(
|
||||||
device=HardDrive(serial_number='foo', manufacturer='bar', model='foo-bar'),
|
device=hdd,
|
||||||
severity=Severity.Info,
|
severity=Severity.Error,
|
||||||
elapsed=timedelta(minutes=25),
|
elapsed=timedelta(minutes=25),
|
||||||
length=TestDataStorageLength.Short,
|
length=TestDataStorageLength.Short,
|
||||||
status='ok!',
|
status=':-(',
|
||||||
lifetime=timedelta(days=120)
|
lifetime=timedelta(days=120)
|
||||||
)
|
)
|
||||||
db.session.add(test)
|
db.session.add(test)
|
||||||
db.session.commit()
|
db.session.flush()
|
||||||
assert models.TestDataStorage.query.one()
|
assert hdd.working == [test]
|
||||||
|
assert not hdd.problems
|
||||||
|
# Add new test overriding the first test in the problems
|
||||||
|
# / working condition
|
||||||
|
test2 = models.TestDataStorage(
|
||||||
|
device=hdd,
|
||||||
|
severity=Severity.Warning,
|
||||||
|
elapsed=timedelta(minutes=25),
|
||||||
|
length=TestDataStorageLength.Short,
|
||||||
|
status=':-(',
|
||||||
|
lifetime=timedelta(days=120)
|
||||||
|
)
|
||||||
|
db.session.add(test2)
|
||||||
|
db.session.flush()
|
||||||
|
assert hdd.working == [test2]
|
||||||
|
assert hdd.problems == []
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
|
||||||
|
|
|
@ -289,8 +289,10 @@ def test_snapshot_component_containing_components(user: UserClient):
|
||||||
user.post(s, res=Snapshot, status=ValidationError)
|
user.post(s, res=Snapshot, status=ValidationError)
|
||||||
|
|
||||||
|
|
||||||
def test_erase(user: UserClient):
|
def test_erase_privacy(user: UserClient):
|
||||||
"""Tests a Snapshot with EraseSectors."""
|
"""Tests a Snapshot with EraseSectors and the resulting
|
||||||
|
privacy properties.
|
||||||
|
"""
|
||||||
s = file('erase-sectors.snapshot')
|
s = file('erase-sectors.snapshot')
|
||||||
snapshot = snapshot_and_check(user, s, (EraseSectors.t,), perform_second_snapshot=True)
|
snapshot = snapshot_and_check(user, s, (EraseSectors.t,), perform_second_snapshot=True)
|
||||||
storage, *_ = snapshot['components']
|
storage, *_ = snapshot['components']
|
||||||
|
@ -312,14 +314,19 @@ def test_erase(user: UserClient):
|
||||||
assert step['type'] == 'StepZero'
|
assert step['type'] == 'StepZero'
|
||||||
assert step['severity'] == 'Info'
|
assert step['severity'] == 'Info'
|
||||||
assert 'num' not in step
|
assert 'num' not in step
|
||||||
assert storage['privacy'] == erasure['device']['privacy'] == 'EraseSectors'
|
assert storage['privacy']['type'] == 'EraseSectors'
|
||||||
|
pc, _ = user.get(res=m.Device, item=snapshot['device']['id'])
|
||||||
|
assert pc['privacy'] == [storage['privacy']]
|
||||||
|
|
||||||
# Let's try a second erasure with an error
|
# Let's try a second erasure with an error
|
||||||
s['uuid'] = uuid4()
|
s['uuid'] = uuid4()
|
||||||
s['components'][0]['events'][0]['severity'] = 'Error'
|
s['components'][0]['events'][0]['severity'] = 'Error'
|
||||||
snapshot, _ = user.post(s, res=Snapshot)
|
snapshot, _ = user.post(s, res=Snapshot)
|
||||||
assert snapshot['components'][0]['hid'] == 'c1mr-c1s-c1ml'
|
storage, _ = user.get(res=m.Device, item=storage['id'])
|
||||||
assert snapshot['components'][0]['privacy'] == 'EraseSectorsError'
|
assert storage['hid'] == 'c1mr-c1s-c1ml'
|
||||||
|
assert storage['privacy']['type'] == 'EraseSectors'
|
||||||
|
pc, _ = user.get(res=m.Device, item=snapshot['device']['id'])
|
||||||
|
assert pc['privacy'] == [storage['privacy']]
|
||||||
|
|
||||||
|
|
||||||
def test_test_data_storage(user: UserClient):
|
def test_test_data_storage(user: UserClient):
|
||||||
|
@ -330,7 +337,7 @@ def test_test_data_storage(user: UserClient):
|
||||||
ev for ev in snapshot['events']
|
ev for ev in snapshot['events']
|
||||||
if ev.get('reallocatedSectorCount', None) == 15
|
if ev.get('reallocatedSectorCount', None) == 15
|
||||||
)
|
)
|
||||||
incidence_test['severity'] == 'Error'
|
assert incidence_test['severity'] == 'Error'
|
||||||
|
|
||||||
|
|
||||||
def test_snapshot_computer_monitor(user: UserClient):
|
def test_snapshot_computer_monitor(user: UserClient):
|
||||||
|
|
Reference in New Issue