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

594 lines
16 KiB
Python

import datetime
from marshmallow import fields as f
from marshmallow import post_load, pre_load
from marshmallow.fields import (
UUID,
Boolean,
Date,
DateTime,
Dict,
Float,
Integer,
List,
Str,
String,
)
from marshmallow.validate import Length, OneOf, Range
from sqlalchemy.util import OrderedSet
from stdnum import imei, meid
from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources import enums
from ereuse_devicehub.resources.device import models as m
from ereuse_devicehub.resources.device import states
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.schemas import Thing, UnitCodes
from ereuse_devicehub.teal.enums import Layouts
from ereuse_devicehub.teal.marshmallow import (
URL,
EnumField,
SanitizedStr,
ValidationError,
)
from ereuse_devicehub.teal.resource import Schema
class Device(Thing):
__doc__ = m.Device.__doc__
id = Integer(description=m.Device.id.comment, dump_only=True)
hid = SanitizedStr(lower=True, description=m.Device.hid.comment)
tags = NestedOn(
'Tag',
many=True,
collection_class=OrderedSet,
description='A set of tags that identify the device.',
)
model = SanitizedStr(
lower=True,
validate=Length(max=STR_BIG_SIZE),
description=m.Device.model.comment,
)
manufacturer = SanitizedStr(
lower=True,
validate=Length(max=STR_SIZE),
description=m.Device.manufacturer.comment,
)
serial_number = SanitizedStr(
lower=True, validate=Length(max=STR_BIG_SIZE), data_key='serialNumber'
)
part_number = SanitizedStr(
lower=True, validate=Length(max=STR_BIG_SIZE), data_key='partNumber'
)
brand = SanitizedStr(
validate=Length(max=STR_BIG_SIZE), description=m.Device.brand.comment
)
generation = Integer(
validate=Range(1, 100), description=m.Device.generation.comment
)
version = SanitizedStr(description=m.Device.version)
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
)
# TODO TimeOut 2. Comment actions and lots if there are time out.
actions = NestedOn(
'Action', many=True, dump_only=True, description=m.Device.actions.__doc__
)
# TODO TimeOut 2. Comment actions_one and lots if there are time out.
actions_one = NestedOn(
'Action', many=True, load_only=True, collection_class=OrderedSet
)
problems = NestedOn(
'Action', many=True, dump_only=True, description=m.Device.problems.__doc__
)
url = URL(dump_only=True, description=m.Device.url.__doc__)
# TODO TimeOut 2. Comment actions and lots if there are time out.
lots = NestedOn(
'Lot',
many=True,
dump_only=True,
description='The lots where this device is directly under.',
)
rate = NestedOn('Rate', dump_only=True, description=m.Device.rate.__doc__)
price = NestedOn('Price', dump_only=True, description=m.Device.price.__doc__)
tradings = Dict(dump_only=True, description='')
physical = EnumField(
states.Physical, dump_only=True, description=m.Device.physical.__doc__
)
traking = EnumField(
states.Traking, dump_only=True, description=m.Device.physical.__doc__
)
usage = EnumField(
states.Usage, dump_only=True, description=m.Device.physical.__doc__
)
revoke = UUID(dump_only=True)
physical_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor')
production_date = DateTime(
'iso', description=m.Device.updated.comment, data_key='productionDate'
)
working = NestedOn(
'Action', many=True, dump_only=True, description=m.Device.working.__doc__
)
variant = SanitizedStr(description=m.Device.variant.comment)
sku = SanitizedStr(description=m.Device.sku.comment)
image = URL(description=m.Device.image.comment)
allocated = Boolean(description=m.Device.allocated.comment)
dhid = SanitizedStr(
data_key='devicehubID', description=m.Device.devicehub_id.comment
)
family = SanitizedStr(validate=Length(max=STR_BIG_SIZE))
@pre_load
def from_actions_to_actions_one(self, data: dict):
"""
Not an elegant way of allowing submitting actions to a device
(in the context of Snapshots) without creating an ``actions``
field at the model (which is not possible).
:param data:
:return:
"""
# Note that it is secure to allow uploading actions_one
# as the only time an user can send a device object is
# in snapshots.
data['actions_one'] = data.pop('actions', [])
return data
@post_load
def validate_snapshot_actions(self, data):
"""Validates that only snapshot-related actions can be uploaded."""
from ereuse_devicehub.resources.action.models import (
Benchmark,
EraseBasic,
Install,
Rate,
Test,
)
for action in data['actions_one']:
if not isinstance(action, (Install, EraseBasic, Rate, Test, Benchmark)):
raise ValidationError(
'You cannot upload {}'.format(action), field_names=['actions']
)
class Computer(Device):
__doc__ = m.Computer.__doc__
# TODO TimeOut 1. Comment components if there are time out.
components = NestedOn(
'Component',
many=True,
dump_only=True,
collection_class=OrderedSet,
description='The components that are inside this computer.',
)
chassis = EnumField(enums.ComputerChassis, description=m.Computer.chassis.comment)
ram_size = Integer(
dump_only=True, data_key='ramSize', description=m.Computer.ram_size.__doc__
)
data_storage_size = Integer(
dump_only=True,
data_key='dataStorageSize',
description=m.Computer.data_storage_size.__doc__,
)
processor_model = Str(
dump_only=True,
data_key='processorModel',
description=m.Computer.processor_model.__doc__,
)
graphic_card_model = Str(
dump_only=True,
data_key='graphicCardModel',
description=m.Computer.graphic_card_model.__doc__,
)
network_speeds = List(
Integer(dump_only=True),
dump_only=True,
data_key='networkSpeeds',
description=m.Computer.network_speeds.__doc__,
)
privacy = NestedOn(
'Action',
many=True,
dump_only=True,
collection_class=set,
description=m.Computer.privacy.__doc__,
)
amount = Integer(
validate=f.validate.Range(min=0, max=100), description=m.Computer.amount.__doc__
)
# author_id = NestedOn(s_user.User, only_query='author_id')
owner_id = UUID(data_key='ownerID')
transfer_state = EnumField(
enums.TransferState, description=m.Computer.transfer_state.comment
)
receiver_id = UUID(data_key='receiverID')
system_uuid = UUID(required=False)
class Desktop(Computer):
__doc__ = m.Desktop.__doc__
class Laptop(Computer):
__doc__ = m.Laptop.__doc__
layout = EnumField(Layouts, description=m.Laptop.layout.comment)
class Server(Computer):
__doc__ = m.Server.__doc__
class DisplayMixin:
__doc__ = m.DisplayMixin.__doc__
size = Float(description=m.DisplayMixin.size.comment, validate=Range(2, 150))
technology = EnumField(
enums.DisplayTech, 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(description=m.DisplayMixin.touchable.comment)
aspect_ratio = String(
dump_only=True, description=m.DisplayMixin.aspect_ratio.__doc__
)
widescreen = Boolean(dump_only=True, description=m.DisplayMixin.widescreen.__doc__)
class NetworkMixin:
__doc__ = m.NetworkMixin.__doc__
speed = Integer(
validate=Range(min=10, max=10000),
unit=UnitCodes.mbps,
description=m.NetworkAdapter.speed.comment,
)
wireless = Boolean(required=True)
class Monitor(DisplayMixin, Device):
__doc__ = m.Monitor.__doc__
class ComputerMonitor(Monitor):
__doc__ = m.ComputerMonitor.__doc__
class TelevisionSet(Monitor):
__doc__ = m.TelevisionSet.__doc__
class Projector(Monitor):
__doc__ = m.Projector.__doc__
class Mobile(Device):
__doc__ = m.Mobile.__doc__
imei = Integer(description=m.Mobile.imei.comment)
meid = Str(description=m.Mobile.meid.comment)
ram_size = Integer(
validate=Range(min=128, max=36000),
data_key='ramSize',
unit=UnitCodes.mbyte,
description=m.Mobile.ram_size.comment,
)
data_storage_size = Integer(
validate=Range(0, 10**8),
data_key='dataStorageSize',
description=m.Mobile.data_storage_size,
)
display_size = Float(
validate=Range(min=0.1, max=30.0),
data_key='displaySize',
description=m.Mobile.display_size.comment,
)
@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):
data['meid'] = meid.compact(data['meid'])
return data
class Smartphone(Mobile):
__doc__ = m.Smartphone.__doc__
class Tablet(Mobile):
__doc__ = m.Tablet.__doc__
class Cellphone(Mobile):
__doc__ = m.Cellphone.__doc__
class Component(Device):
__doc__ = m.Component.__doc__
parent = NestedOn(Device, dump_only=True)
class GraphicCard(Component):
__doc__ = m.GraphicCard.__doc__
memory = Integer(
validate=Range(0, 10000),
unit=UnitCodes.mbyte,
description=m.GraphicCard.memory.comment,
)
class DataStorage(Component):
__doc__ = m.DataStorage.__doc__
size = Integer(
validate=Range(0, 10**8),
unit=UnitCodes.mbyte,
description=m.DataStorage.size.comment,
)
interface = EnumField(enums.DataStorageInterface)
privacy = NestedOn('Action', dump_only=True)
class HardDrive(DataStorage):
__doc__ = m.HardDrive.__doc__
class SolidStateDrive(DataStorage):
__doc__ = m.SolidStateDrive.__doc__
class Motherboard(Component):
__doc__ = m.Motherboard.__doc__
slots = Integer(validate=Range(0, 20), description=m.Motherboard.slots.comment)
usb = Integer(validate=Range(0, 20), description=m.Motherboard.usb.comment)
firewire = Integer(
validate=Range(0, 20), description=m.Motherboard.firewire.comment
)
serial = Integer(validate=Range(0, 20), description=m.Motherboard.serial.comment)
pcmcia = Integer(validate=Range(0, 20), description=m.Motherboard.pcmcia.comment)
bios_date = Date(
validate=Range(
datetime.date(year=1980, month=1, day=1),
datetime.date(year=2030, month=1, day=1),
),
data_key='biosDate',
description=m.Motherboard.bios_date,
)
ram_slots = Integer(validate=Range(1), data_key='ramSlots')
ram_max_size = Integer(validate=Range(1), data_key='ramMaxSize')
class NetworkAdapter(NetworkMixin, Component):
__doc__ = m.NetworkAdapter.__doc__
class Processor(Component):
__doc__ = m.Processor.__doc__
speed = Float(
validate=Range(min=0.1, max=15),
unit=UnitCodes.ghz,
description=m.Processor.speed.comment,
)
cores = Integer(
validate=Range(min=1, max=10), description=m.Processor.cores.comment
)
threads = Integer(
validate=Range(min=1, max=20), description=m.Processor.threads.comment
)
address = Integer(
validate=OneOf({8, 16, 32, 64, 128, 256}),
description=m.Processor.address.comment,
)
abi = SanitizedStr(lower=True, description=m.Processor.abi.comment)
class RamModule(Component):
__doc__ = m.RamModule.__doc__
size = Integer(
validate=Range(min=128, max=17000),
unit=UnitCodes.mbyte,
description=m.RamModule.size.comment,
)
speed = Integer(validate=Range(min=100, max=10000), unit=UnitCodes.mhz)
interface = EnumField(enums.RamInterface)
format = EnumField(enums.RamFormat)
class SoundCard(Component):
__doc__ = m.SoundCard.__doc__
class Display(DisplayMixin, Component):
__doc__ = m.Display.__doc__
class Battery(Component):
__doc__ = m.Battery.__doc__
wireless = Boolean(description=m.Battery.wireless.comment)
technology = EnumField(
enums.BatteryTechnology, description=m.Battery.technology.comment
)
size = Integer(required=True, description=m.Battery.size.comment)
class Camera(Component):
__doc__ = m.Camera.__doc__
focal_length = Integer(data_key='focalLength')
video_height = Integer(data_key='videoHeight')
video_width = Integer(data_key='videoWidth')
horizontal_view_angle = Integer(data_key='horizontalViewAngle')
facing = Integer()
vertical_view_angle = Integer(data_key='verticalViewAngle')
video_stabilization = Integer(data_key='videoStabilization')
flash = Integer()
class Manufacturer(Schema):
__doc__ = m.Manufacturer.__doc__
name = String(dump_only=True)
url = URL(dump_only=True)
logo = URL(dump_only=True)
class ComputerAccessory(Device):
__doc__ = m.ComputerAccessory.__doc__
class Mouse(ComputerAccessory):
__doc__ = m.Mouse.__doc__
class MemoryCardReader(ComputerAccessory):
__doc__ = m.MemoryCardReader.__doc__
class SAI(ComputerAccessory):
__doc__ = m.SAI.__doc__
class Keyboard(ComputerAccessory):
__doc__ = m.Keyboard.__doc__
layout = EnumField(Layouts)
class Networking(NetworkMixin, Device):
__doc__ = m.Networking.__doc__
class Router(Networking):
__doc__ = m.Router.__doc__
class Switch(Networking):
__doc__ = m.Switch.__doc__
class Hub(Networking):
__doc__ = m.Hub.__doc__
class WirelessAccessPoint(Networking):
__doc__ = m.WirelessAccessPoint.__doc__
class Printer(Device):
__doc__ = m.Printer.__doc__
wireless = Boolean(
required=True, missing=False, description=m.Printer.wireless.comment
)
scanning = Boolean(
required=True, missing=False, description=m.Printer.scanning.comment
)
technology = EnumField(
enums.PrinterTechnology, required=True, description=m.Printer.technology.comment
)
monochrome = Boolean(
required=True, missing=True, description=m.Printer.monochrome.comment
)
class LabelPrinter(Printer):
__doc__ = m.LabelPrinter.__doc__
class Sound(Device):
__doc__ = m.Sound.__doc__
class Microphone(Sound):
__doc__ = m.Microphone.__doc__
class Video(Device):
__doc__ = m.Video.__doc__
class VideoScaler(Video):
__doc__ = m.VideoScaler.__doc__
class Videoconference(Video):
__doc__ = m.Videoconference.__doc__
class Cooking(Device):
__doc__ = m.Cooking.__doc__
class Mixer(Cooking):
__doc__ = m.Mixer.__doc__
class DIYAndGardening(Device):
pass
class Drill(DIYAndGardening):
max_drill_bit_size = Integer(data_key='maxDrillBitSize')
class PackOfScrewdrivers(DIYAndGardening):
size = Integer()
class Home(Device):
pass
class Dehumidifier(Home):
size = Integer()
class Stairs(Home):
max_allowed_weight = Integer(data_key='maxAllowedWeight')
class Recreation(Device):
pass
class Bike(Recreation):
wheel_size = Integer(data_key='wheelSize')
gears = Integer()
class Racket(Recreation):
pass
class Other(Device):
pass