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/device/schemas.py

307 lines
9 KiB
Python
Raw Normal View History

from marshmallow import post_load, pre_load
from marshmallow.fields import Boolean, DateTime, Float, Integer, List, Str, String
from marshmallow.validate import Length, OneOf, Range
from sqlalchemy.util import OrderedSet
from stdnum import imei, meid
from teal.enums import Layouts
2018-09-30 17:40:28 +00:00
from teal.marshmallow import EnumField, SanitizedStr, URL, ValidationError
from teal.resource import Schema
2018-06-20 21:18:15 +00:00
from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources import enums
from ereuse_devicehub.resources.device import models as m, states
2018-06-20 21:18:15 +00:00
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
2018-04-10 15:06:39 +00:00
class Device(Thing):
2018-06-26 13:35:13 +00:00
id = Integer(description=m.Device.id.comment, dump_only=True)
hid = SanitizedStr(lower=True, dump_only=True, description=m.Device.hid.comment)
tags = NestedOn('Tag',
many=True,
collection_class=OrderedSet,
description='The set of tags that identify the device.')
model = SanitizedStr(lower=True, validate=Length(max=STR_BIG_SIZE))
manufacturer = SanitizedStr(lower=True, validate=Length(max=STR_SIZE))
serial_number = SanitizedStr(lower=True, data_key='serialNumber')
weight = Float(validate=Range(0.1, 5), unit=UnitCodes.kgm, description=m.Device.weight.comment)
width = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.width.comment)
height = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.height.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_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__)
lots = NestedOn('Lot',
many=True,
dump_only=True,
description='The lots where this device is directly under.')
rate = NestedOn('AggregateRate', dump_only=True, description=m.Device.rate.__doc__)
price = NestedOn('Price', dump_only=True, description=m.Device.price.__doc__)
trading = EnumField(states.Trading, dump_only=True, description=m.Device.trading.__doc__)
physical = EnumField(states.Physical, dump_only=True, description=m.Device.physical.__doc__)
physical_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor')
production_date = DateTime('iso',
description=m.Device.updated.comment,
data_key='productionDate')
working = NestedOn('Event',
many=True,
dump_only=True,
description=m.Device.working.__doc__)
@pre_load
def from_events_to_events_one(self, data: dict):
"""
Not an elegant way of allowing submitting events to a device
(in the context of Snapshots) without creating an ``events``
field at the model (which is not possible).
:param data:
:return:
"""
# Note that it is secure to allow uploading events_one
# as the only time an user can send a device object is
# in snapshots.
data['events_one'] = data.pop('events', [])
return data
@post_load
def validate_snapshot_events(self, data):
"""Validates that only snapshot-related events can be uploaded."""
2018-06-19 16:38:42 +00:00
from ereuse_devicehub.resources.event.models import EraseBasic, Test, Rate, Install, \
Benchmark
for event in data['events_one']:
2018-06-19 16:38:42 +00:00
if not isinstance(event, (Install, EraseBasic, Rate, Test, Benchmark)):
raise ValidationError('You cannot upload {}'.format(event), field_names=['events'])
2018-04-10 15:06:39 +00:00
class Computer(Device):
components = NestedOn('Component', many=True, dump_only=True, collection_class=OrderedSet)
chassis = EnumField(enums.ComputerChassis, required=True)
ram_size = Integer(dump_only=True, data_key='ramSize')
data_storage_size = Integer(dump_only=True, data_key='dataStorageSize')
processor_model = Str(dump_only=True, data_key='processorModel')
graphic_card_model = Str(dump_only=True, data_key='graphicCardModel')
network_speeds = List(Integer(dump_only=True), dump_only=True, data_key='networkSpeeds')
privacy = NestedOn('Event', many=True, dump_only=True, collection_class=set)
2018-04-10 15:06:39 +00:00
class Desktop(Computer):
pass
class Laptop(Computer):
pass
2018-06-26 13:35:13 +00:00
class Server(Computer):
2018-04-10 15:06:39 +00:00
pass
2018-06-26 13:35:13 +00:00
class DisplayMixin:
size = Float(description=m.DisplayMixin.size.comment, validate=Range(2, 150))
technology = EnumField(enums.DisplayTech,
2018-06-26 13:35:13 +00:00
description=m.DisplayMixin.technology.comment)
resolution_width = Integer(data_key='resolutionWidth',
validate=Range(10, 20000),
description=m.DisplayMixin.resolution_width.comment)
resolution_height = Integer(data_key='resolutionHeight',
validate=Range(10, 20000),
description=m.DisplayMixin.resolution_height.comment)
refresh_rate = Integer(data_key='refreshRate', validate=Range(10, 1000))
contrast_ratio = Integer(data_key='contrastRatio', validate=Range(100, 100000))
touchable = Boolean(missing=False, description=m.DisplayMixin.touchable.comment)
2018-06-26 13:35:13 +00:00
class NetworkMixin:
speed = Integer(validate=Range(min=10, max=10000),
unit=UnitCodes.mbps,
description=m.NetworkAdapter.speed.comment)
wireless = Boolean(required=True)
2018-06-26 13:35:13 +00:00
class Monitor(DisplayMixin, Device):
2018-04-10 15:06:39 +00:00
pass
2018-06-26 13:35:13 +00:00
class ComputerMonitor(Monitor):
2018-04-10 15:06:39 +00:00
pass
2018-06-26 13:35:13 +00:00
class TelevisionSet(Monitor):
pass
class Mobile(Device):
imei = Integer(description=m.Mobile.imei.comment)
meid = Str(description=m.Mobile.meid.comment)
2018-06-26 13:35:13 +00:00
@pre_load
def convert_check_imei(self, data):
if data.get('imei', None):
data['imei'] = int(imei.validate(data['imei']))
return data
@pre_load
def convert_check_meid(self, data: dict):
if data.get('meid', None):
2018-06-26 13:35:13 +00:00
data['meid'] = meid.compact(data['meid'])
return data
2018-06-26 13:35:13 +00:00
class Smartphone(Mobile):
pass
class Tablet(Mobile):
pass
class Cellphone(Mobile):
pass
2018-06-20 21:18:15 +00:00
2018-04-10 15:06:39 +00:00
class Component(Device):
parent = NestedOn(Device, dump_only=True)
2018-04-10 15:06:39 +00:00
class GraphicCard(Component):
2018-04-27 17:16:43 +00:00
memory = Integer(validate=Range(0, 10000),
unit=UnitCodes.mbyte,
2018-06-26 13:35:13 +00:00
description=m.GraphicCard.memory.comment)
2018-04-10 15:06:39 +00:00
2018-06-10 16:47:49 +00:00
class DataStorage(Component):
2018-04-27 17:16:43 +00:00
size = Integer(validate=Range(0, 10 ** 8),
unit=UnitCodes.mbyte,
2018-06-26 13:35:13 +00:00
description=m.DataStorage.size.comment)
interface = EnumField(enums.DataStorageInterface)
privacy = NestedOn('Event', dump_only=True)
2018-04-10 15:06:39 +00:00
2018-06-10 16:47:49 +00:00
class HardDrive(DataStorage):
pass
class SolidStateDrive(DataStorage):
pass
2018-04-10 15:06:39 +00:00
class Motherboard(Component):
2018-07-02 10:52:54 +00:00
slots = Integer(validate=Range(0, 20),
2018-06-26 13:35:13 +00:00
description=m.Motherboard.slots.comment)
2018-04-10 15:06:39 +00:00
usb = Integer(validate=Range(0, 20))
firewire = Integer(validate=Range(0, 20))
serial = Integer(validate=Range(0, 20))
pcmcia = Integer(validate=Range(0, 20))
2018-06-26 13:36:21 +00:00
class NetworkAdapter(NetworkMixin, Component):
pass
2018-04-27 17:16:43 +00:00
class Processor(Component):
speed = Float(validate=Range(min=0.1, max=15), unit=UnitCodes.ghz)
cores = Integer(validate=Range(min=1, max=10))
threads = Integer(validate=Range(min=1, max=20))
address = Integer(validate=OneOf({8, 16, 32, 64, 128, 256}))
2018-04-27 17:16:43 +00:00
class RamModule(Component):
size = Integer(validate=Range(min=128, max=17000), unit=UnitCodes.mbyte)
speed = Integer(validate=Range(min=100, max=10000), unit=UnitCodes.mhz)
interface = EnumField(enums.RamInterface)
format = EnumField(enums.RamFormat)
2018-06-26 13:36:21 +00:00
2018-07-02 10:52:54 +00:00
class SoundCard(Component):
pass
2018-06-26 13:36:21 +00:00
class Display(DisplayMixin, Component):
pass
2018-09-30 17:40:28 +00:00
class Manufacturer(Schema):
name = String(dump_only=True)
url = URL(dump_only=True)
logo = URL(dump_only=True)
class ComputerAccessory(Device):
pass
class Mouse(ComputerAccessory):
pass
class MemoryCardReader(ComputerAccessory):
pass
class SAI(ComputerAccessory):
pass
class Keyboard(ComputerAccessory):
layout = EnumField(Layouts)
class Networking(NetworkMixin, Device):
pass
class Router(Networking):
pass
class Switch(Networking):
pass
class Hub(Networking):
pass
class WirelessAccessPoint(Networking):
pass
class Printer(Device):
wireless = Boolean(required=True, missing=False)
scanning = Boolean(required=True, missing=False)
technology = EnumField(enums.PrinterTechnology, required=True)
monochrome = Boolean(required=True, missing=True)
class LabelPrinter(Printer):
pass
class Sound(Device):
pass
class Microphone(Sound):
pass
class Video(Device):
pass
class VideoScaler(Video):
pass
class Videoconference(Video):
pass
2018-11-12 10:59:49 +00:00
class Cooking(Device):
pass
class Mixer(Cooking):
pass