This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
devicehub-teal/ereuse_devicehub/resources/event/schemas.py
2018-05-16 15:23:48 +02:00

192 lines
8 KiB
Python

from flask import current_app as app
from marshmallow import ValidationError, post_load, validates_schema
from marshmallow.fields import Boolean, DateTime, Integer, Nested, String, TimeDelta, UUID
from marshmallow.validate import Length, Range
from marshmallow_enum import EnumField
from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources.device.schemas import Component, Device
from ereuse_devicehub.resources.event.enums import Appearance, Bios, Functionality, Orientation, \
SoftwareType, StepTypes, TestHardDriveLength
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.schemas import Thing
from ereuse_devicehub.resources.user.schemas import User
from teal.marshmallow import Color, Version
from teal.resource import Schema
class Event(Thing):
id = Integer(dump_only=True)
title = String(default='',
validate=Length(STR_BIG_SIZE),
description='A name or title for the event. Used when searching for events.')
date = DateTime('iso', description='When this event happened. '
'Leave it blank if it is happening now. '
'This is used when creating events retroactively.')
secured = Boolean(default=False,
description='Can we ensure the info in this event is totally correct?'
'Devicehub will automatically set this too for some events,'
'for example in snapshots if it could detect the ids of the'
'hardware without margin of doubt.')
incidence = Boolean(default=False,
description='Was something wrong in this event?')
snapshot = NestedOn('Snapshot', dump_only=True)
description = String(default='', description='A comment about the event.')
components = NestedOn(Component, dump_only=True, many=True)
class EventWithOneDevice(Event):
device = NestedOn(Device, only='id')
class EventWithMultipleDevices(Event):
devices = NestedOn(Device, many=True, only='id')
class Add(EventWithOneDevice):
pass
class Remove(EventWithOneDevice):
pass
class Allocate(EventWithMultipleDevices):
to = NestedOn(User,
description='The user the devices are allocated to.')
organization = String(validate=Length(STR_SIZE),
description='The organization where the user was when this happened.')
class Deallocate(EventWithMultipleDevices):
from_rel = Nested(User,
data_key='from',
description='The user where the devices are not allocated to anymore.')
organization = String(validate=Length(STR_SIZE),
description='The organization where the user was when this happened.')
class EraseBasic(EventWithOneDevice):
starting_time = DateTime(required=True, data_key='startingTime')
ending_time = DateTime(required=True, data_key='endingTime')
secure_random_steps = Integer(validate=Range(min=0), required=True,
data_key='secureRandomSteps')
success = Boolean(required=True)
clean_with_zeros = Boolean(required=True, data_key='cleanWithZeros')
class EraseSectors(EraseBasic):
pass
class Step(Schema):
id = Integer(dump_only=True)
type = EnumField(StepTypes, required=True)
starting_time = DateTime(required=True, data_key='startingTime')
ending_time = DateTime(required=True, data_key='endingTime')
secure_random_steps = Integer(validate=Range(min=0),
required=True,
data_key='secureRandomSteps')
success = Boolean(required=True)
clean_with_zeros = Boolean(required=True, data_key='cleanWithZeros')
class Condition(Schema):
appearance = EnumField(Appearance,
required=True,
description='Grades the imperfections that aesthetically '
'affect the device, but not its usage.')
appearance_score = Integer(validate=Range(-3, 5), dump_only=True)
functionality = EnumField(Functionality,
required=True,
description='Grades the defects of a device that affect its usage.')
functionality_score = Integer(validate=Range(-3, 5),
dump_only=True,
data_key='functionalityScore')
labelling = Boolean(description='Sets if there are labels stuck that should be removed.')
bios = EnumField(Bios, description='How difficult it has been to set the bios to '
'boot from the network.')
general = Integer(dump_only=True,
validate=Range(0, 5),
description='The grade of the device.')
class Installation(Schema):
name = String(validate=Length(STR_BIG_SIZE),
required=True,
description='The name of the OS installed.')
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
success = Boolean(required=True)
class Inventory(Schema):
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
class Snapshot(EventWithOneDevice):
"""
The Snapshot updates the state of the device with information about
its components and events performed at them.
See docs for more info.
"""
device = NestedOn(Device) # todo and when dumping?
components = NestedOn(Component,
many=True,
description='A list of components that are inside of the device'
'at the moment of this Snapshot.'
'Order is preserved, so the component num 0 when'
'submitting is the component num 0 when returning it back.')
uuid = UUID(required=True)
version = Version(required=True, description='The version of the SnapshotSoftware.')
software = EnumField(SoftwareType,
required=True,
description='The software that generated this Snapshot.')
condition = Nested(Condition, required=True)
install = Nested(Installation)
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
inventory = Nested(Inventory)
color = Color(description='Main color of the device.')
orientation = EnumField(Orientation, description='Is the device main stand wider or larger?')
events = NestedOn(Event, many=True, dump_only=True)
@validates_schema
def validate_workbench_version(self, data: dict):
if data['software'] == SoftwareType.Workbench:
if data['version'] < app.config['MIN_WORKBENCH']:
raise ValidationError(
'Min. supported Workbench version is {}'.format(app.config['MIN_WORKBENCH']),
field_names=['version']
)
@validates_schema
def validate_components_only_workbench(self, data: dict):
if data['software'] != SoftwareType.Workbench:
if data['components'] is not None:
raise ValidationError('Only Workbench can add component info',
field_names=['components'])
@post_load
def normalize_nested(self, data: dict):
data.update(data.pop('condition'))
data['condition'] = data.pop('general', None)
data.update({'install_' + key: value for key, value in data.pop('install', {})})
data['inventory_elapsed'] = data.get('inventory', {}).pop('elapsed', None)
return data
class Test(EventWithOneDevice):
elapsed = TimeDelta(precision=TimeDelta.SECONDS, required=True)
success = Boolean(required=True)
class TestHardDrive(Test):
length = EnumField(TestHardDriveLength, required=True)
status = String(validate=Length(max=STR_SIZE), required=True)
lifetime = TimeDelta(precision=TimeDelta.DAYS, required=True)
first_error = Integer()
class StressTest(Test):
pass