diff --git a/docs/states.puml b/docs/states.puml
index b20e2ab6..f22416af 100644
--- a/docs/states.puml
+++ b/docs/states.puml
@@ -23,8 +23,8 @@ state Physical {
ToBeRepaired --> Repaired : Repair
Repaired -> Preparing : ToPrepare
Preparing --> Prepared : Prepare
- Prepared --> ReadyToBeUsed : ReadyToUse
- ReadyToBeUsed --> InUse : Live
+ Prepared --> Ready : ReadyToUse
+ Ready --> InUse : Live
InUse -> InUse : Live
state DisposeWaste
state Recover
diff --git a/docs/states.rst b/docs/states.rst
index 7c253e9a..840e80ba 100644
--- a/docs/states.rst
+++ b/docs/states.rst
@@ -44,5 +44,5 @@ Physical
:cvar Repaired: The device has been repaired.
:cvar Preparing: The device is going to be or being prepared.
:cvar Prepared: The device has been prepared.
-:cvar ReadyToBeUsed: The device is in working conditions.
+:cvar Ready: The device is in working conditions.
:cvar InUse: The device is being reported to be in active use.
diff --git a/ereuse_devicehub/devicehub.py b/ereuse_devicehub/devicehub.py
index 4499268b..834fdcc7 100644
--- a/ereuse_devicehub/devicehub.py
+++ b/ereuse_devicehub/devicehub.py
@@ -18,11 +18,13 @@ from ereuse_devicehub.db import db
from ereuse_devicehub.dummy.dummy import Dummy
from ereuse_devicehub.resources.device.search import DeviceSearch
from ereuse_devicehub.resources.inventory import Inventory, InventoryDef
+from ereuse_devicehub.templating import Environment
class Devicehub(Teal):
test_client_class = Client
Dummy = Dummy
+ jinja_environment = Environment
def __init__(self,
inventory: str,
diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py
index 829bfa6f..89d39893 100644
--- a/ereuse_devicehub/dummy/dummy.py
+++ b/ereuse_devicehub/dummy/dummy.py
@@ -104,7 +104,7 @@ class Dummy:
# Perform generic actions
for pc, model in zip(pcs,
- {m.ToRepair, m.Repair, m.ToPrepare, m.Available, m.ToPrepare,
+ {m.ToRepair, m.Repair, m.ToPrepare, m.Ready, m.ToPrepare,
m.Prepare}):
user.post({'type': model.t, 'devices': [pc]}, res=m.Action)
@@ -144,7 +144,7 @@ class Dummy:
user.post({'type': m.ToPrepare.t, 'devices': [sample_pc]}, res=m.Action)
user.post({'type': m.Prepare.t, 'devices': [sample_pc]}, res=m.Action)
- user.post({'type': m.Available.t, 'devices': [sample_pc]}, res=m.Action)
+ user.post({'type': m.Ready.t, 'devices': [sample_pc]}, res=m.Action)
user.post({'type': m.Price.t, 'device': sample_pc, 'currency': 'EUR', 'price': 85},
res=m.Action)
# todo test reserve
diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py
index 6b9588c9..0a940e5c 100644
--- a/ereuse_devicehub/resources/action/__init__.py
+++ b/ereuse_devicehub/resources/action/__init__.py
@@ -188,9 +188,9 @@ class RepairDef(ActionDef):
SCHEMA = schemas.Repair
-class Available(ActionDef):
+class ReadyDef(ActionDef):
VIEW = None
- SCHEMA = schemas.Available
+ SCHEMA = schemas.Ready
class ToPrepareDef(ActionDef):
@@ -233,6 +233,11 @@ class RentDef(ActionDef):
SCHEMA = schemas.Rent
+class MakeAvailable(ActionDef):
+ VIEW = None
+ SCHEMA = schemas.MakeAvailable
+
+
class CancelTradeDef(ActionDef):
VIEW = None
SCHEMA = schemas.CancelTrade
diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py
index 0ea6817f..9937a0a8 100644
--- a/ereuse_devicehub/resources/action/models.py
+++ b/ereuse_devicehub/resources/action/models.py
@@ -1256,7 +1256,7 @@ class Repair(ActionWithMultipleDevices):
"""
-class Available(ActionWithMultipleDevices):
+class Ready(ActionWithMultipleDevices):
"""The device is ready to be used.
This involves greater preparation from the ``Prepare`` action,
@@ -1420,6 +1420,11 @@ class DisposeProduct(Trade):
# ``RecyclingCenter``.
+class MakeAvailable(ActionWithMultipleDevices):
+ """The act of setting willingness for trading."""
+ pass
+
+
class Receive(JoinedTableMixin, ActionWithMultipleDevices):
"""The act of physically taking delivery of a device.
diff --git a/ereuse_devicehub/resources/action/models.pyi b/ereuse_devicehub/resources/action/models.pyi
index e18c9eb9..6d9ab5b4 100644
--- a/ereuse_devicehub/resources/action/models.pyi
+++ b/ereuse_devicehub/resources/action/models.pyi
@@ -434,7 +434,7 @@ class Repair(ActionWithMultipleDevices):
pass
-class ReadyToUse(ActionWithMultipleDevices):
+class Ready(ActionWithMultipleDevices):
pass
@@ -505,6 +505,10 @@ class Rent(Trade):
pass
+class MakeAvailable(ActionWithMultipleDevices):
+ pass
+
+
class CancelTrade(Trade):
pass
diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py
index 5daee52a..63ed2d3a 100644
--- a/ereuse_devicehub/resources/action/schemas.py
+++ b/ereuse_devicehub/resources/action/schemas.py
@@ -47,7 +47,11 @@ class ActionWithOneDevice(Action):
class ActionWithMultipleDevices(Action):
__doc__ = m.ActionWithMultipleDevices.__doc__
- devices = NestedOn(s_device.Device, many=True, only_query='id', collection_class=OrderedSet)
+ devices = NestedOn(s_device.Device,
+ many=True,
+ required=True, # todo test ensuring len(devices) >= 1
+ only_query='id',
+ collection_class=OrderedSet)
class Add(ActionWithOneDevice):
@@ -347,8 +351,8 @@ class Repair(ActionWithMultipleDevices):
__doc__ = m.Repair.__doc__
-class Available(ActionWithMultipleDevices):
- __doc__ = m.Available.__doc__
+class Ready(ActionWithMultipleDevices):
+ __doc__ = m.Ready.__doc__
class ToPrepare(ActionWithMultipleDevices):
@@ -405,6 +409,10 @@ class Rent(Trade):
__doc__ = m.Rent.__doc__
+class MakeAvailable(ActionWithMultipleDevices):
+ __doc__ = m.MakeAvailable.__doc__
+
+
class CancelTrade(Trade):
__doc__ = m.CancelTrade.__doc__
diff --git a/ereuse_devicehub/resources/device/definitions.py b/ereuse_devicehub/resources/device/definitions.py
index 4d2dc07b..559e5428 100644
--- a/ereuse_devicehub/resources/device/definitions.py
+++ b/ereuse_devicehub/resources/device/definitions.py
@@ -302,9 +302,9 @@ class Mixer(CookingDef):
SCHEMA = schemas.Mixer
-class DrillDef(DeviceDef):
+class DIYAndGardeningDef(DeviceDef):
VIEW = None
- SCHEMA = schemas.Drill
+ SCHEMA = schemas.DIYAndGardening
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
@@ -313,7 +313,12 @@ class DrillDef(DeviceDef):
url_prefix, subdomain, url_defaults, root_path, cli_commands)
-class PackOfScrewdriversDef(DeviceDef):
+class DrillDef(DIYAndGardeningDef):
+ VIEW = None
+ SCHEMA = schemas.Drill
+
+
+class PackOfScrewdriversDef(DIYAndGardeningDef):
VIEW = None
SCHEMA = schemas.PackOfScrewdrivers
@@ -324,21 +329,31 @@ class PackOfScrewdriversDef(DeviceDef):
url_prefix, subdomain, url_defaults, root_path, cli_commands)
-class DehumidifierDef(DeviceDef):
+class HomeDef(DeviceDef):
+ VIEW = None
+ SCHEMA = schemas.Home
+
+ def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
+ template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
+ root_path=None, cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
+ super().__init__(app, import_name, static_folder, static_url_path, template_folder,
+ url_prefix, subdomain, url_defaults, root_path, cli_commands)
+
+
+class DehumidifierDef(HomeDef):
VIEW = None
SCHEMA = schemas.Dehumidifier
- def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
- template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
- root_path=None, cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
- super().__init__(app, import_name, static_folder, static_url_path, template_folder,
- url_prefix, subdomain, url_defaults, root_path, cli_commands)
-
-class StairsDef(DeviceDef):
+class StairsDef(HomeDef):
VIEW = None
SCHEMA = schemas.Stairs
+
+class RecreationDef(DeviceDef):
+ VIEW = None
+ SCHEMA = schemas.Recreation
+
def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
root_path=None, cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
@@ -346,27 +361,15 @@ class StairsDef(DeviceDef):
url_prefix, subdomain, url_defaults, root_path, cli_commands)
-class BikeDef(DeviceDef):
+class BikeDef(RecreationDef):
VIEW = None
SCHEMA = schemas.Bike
- def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
- template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
- root_path=None, cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
- super().__init__(app, import_name, static_folder, static_url_path, template_folder,
- url_prefix, subdomain, url_defaults, root_path, cli_commands)
-
-class RacketDef(DeviceDef):
+class RacketDef(RecreationDef):
VIEW = None
SCHEMA = schemas.Racket
- def __init__(self, app, import_name=__name__, static_folder=None, static_url_path=None,
- template_folder=None, url_prefix=None, subdomain=None, url_defaults=None,
- root_path=None, cli_commands: Iterable[Tuple[Callable, str or None]] = tuple()):
- super().__init__(app, import_name, static_folder, static_url_path, template_folder,
- url_prefix, subdomain, url_defaults, root_path, cli_commands)
-
class ManufacturerDef(Resource):
VIEW = ManufacturerView
diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py
index 51364bf8..ce5ac219 100644
--- a/ereuse_devicehub/resources/device/models.py
+++ b/ereuse_devicehub/resources/device/models.py
@@ -79,14 +79,14 @@ class Device(Thing):
generation = db.Column(db.SmallInteger, check_range('generation', 0))
generation.comment = """The generation of the device."""
version = db.Column(db.CIText())
- version.comment = """The version code this device, like v1 or A001."""
- weight = Column(Float(decimal_return_scale=3), check_range('weight', 0.1, 5))
- weight.comment = """The weight of the device."""
- width = Column(Float(decimal_return_scale=3), check_range('width', 0.1, 5))
+ version.comment = """The version code of this device, like v1 or A001."""
+ weight = Column(Float(decimal_return_scale=4), check_range('weight', 0.1, 5))
+ weight.comment = """The weight of the device in Kg."""
+ width = Column(Float(decimal_return_scale=4), check_range('width', 0.1, 5))
width.comment = """The width of the device in meters."""
- height = Column(Float(decimal_return_scale=3), check_range('height', 0.1, 5))
+ height = Column(Float(decimal_return_scale=4), check_range('height', 0.1, 5))
height.comment = """The height of the device in meters."""
- depth = Column(Float(decimal_return_scale=3), check_range('depth', 0.1, 5))
+ depth = Column(Float(decimal_return_scale=4), check_range('depth', 0.1, 5))
depth.comment = """The depth of the device in meters."""
color = Column(ColorType)
color.comment = """The predominant color of the device."""
@@ -101,6 +101,8 @@ class Device(Thing):
sku.comment = """The Stock Keeping Unit (SKU), i.e. a
merchant-specific identifier for a product or service.
"""
+ image = db.Column(db.URL)
+ image.comment = "An image of the device."
_NON_PHYSICAL_PROPS = {
'id',
@@ -120,7 +122,8 @@ class Device(Thing):
'production_date',
'variant',
'version',
- 'sku'
+ 'sku',
+ 'image'
}
__table_args__ = (
@@ -167,7 +170,7 @@ class Device(Thing):
def physical_properties(self) -> Dict[str, object or None]:
"""Fields that describe the physical properties of a device.
- :return A generator where each value is a tuple with tho fields:
+ :return A dictionary:
- Column.
- Actual value of the column or None.
"""
@@ -291,9 +294,13 @@ class Device(Thing):
if 't' in format_spec:
v += '{0.t} {0.model}'.format(self)
if 's' in format_spec:
- v += '({0.manufacturer})'.format(self)
+ superclass = self.__class__.mro()[1]
+ if not isinstance(self, Device) and superclass != Device:
+ assert issubclass(superclass, Thing)
+ v += superclass.__name__ + ' '
+ v += '{0.manufacturer}'.format(self)
if self.serial_number:
- v += ' S/N ' + self.serial_number.upper()
+ v += ' ' + self.serial_number.upper()
return v
@@ -787,7 +794,11 @@ class Mixer(Cooking):
pass
-class Drill(Device):
+class DIYAndGardening(Device):
+ pass
+
+
+class Drill(DIYAndGardening):
max_drill_bit_size = db.Column(db.SmallInteger)
@@ -795,21 +806,29 @@ class PackOfScrewdrivers(Device):
pass
-class Dehumidifier(Device):
+class Home(Device):
+ pass
+
+
+class Dehumidifier(Home):
size = db.Column(db.SmallInteger)
size.comment = """The capacity in Liters."""
-class Stairs(Device):
+class Stairs(Home):
max_allowed_weight = db.Column(db.Integer)
-class Bike(Device):
+class Recreation(Device):
+ pass
+
+
+class Bike(Recreation):
wheel_size = db.Column(db.SmallInteger)
gears = db.Column(db.SmallInteger)
-class Racket(Device):
+class Racket(Recreation):
pass
diff --git a/ereuse_devicehub/resources/device/models.pyi b/ereuse_devicehub/resources/device/models.pyi
index 76bae791..51a8ea53 100644
--- a/ereuse_devicehub/resources/device/models.pyi
+++ b/ereuse_devicehub/resources/device/models.pyi
@@ -45,6 +45,7 @@ class Device(Thing):
version = ... # type: Column
variant = ... # type: Column
sku = ... # type: Column
+ image = ... #type: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@@ -70,6 +71,7 @@ class Device(Thing):
self.version = ... # type: Optional[str]
self.variant = ... # type: Optional[str]
self.sku = ... # type: Optional[str]
+ self.image = ... # type: Optional[urlutils.URL]
@property
def actions(self) -> List[e.Action]:
diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py
index d2b5b4d1..e5ce1c77 100644
--- a/ereuse_devicehub/resources/device/schemas.py
+++ b/ereuse_devicehub/resources/device/schemas.py
@@ -60,8 +60,9 @@ class Device(Thing):
many=True,
dump_only=True,
description=m.Device.working.__doc__)
- variant = SanitizedStr(description=m.Device.variant)
- sku = SanitizedStr(description=m.Device.sku)
+ variant = SanitizedStr(description=m.Device.variant.comment)
+ sku = SanitizedStr(description=m.Device.sku.comment)
+ image = URL(description=m.Device.image.comment)
@pre_load
def from_actions_to_actions_one(self, data: dict):
@@ -413,26 +414,38 @@ class Mixer(Cooking):
__doc__ = m.Mixer.__doc__
-class Drill(Device):
+class DIYAndGardening(Device):
+ pass
+
+
+class Drill(DIYAndGardening):
max_drill_bit_size = Integer(data_key='maxDrillBitSize')
-class PackOfScrewdrivers(Device):
+class PackOfScrewdrivers(DIYAndGardening):
size = Integer()
-class Dehumidifier(Device):
+class Home(Device):
+ pass
+
+
+class Dehumidifier(Home):
size = Integer()
-class Stairs(Device):
+class Stairs(Home):
max_allowed_weight = Integer(data_key='maxAllowedWeight')
-class Bike(Device):
+class Recreation(Device):
+ pass
+
+
+class Bike(Recreation):
wheel_size = Integer(data_key='wheelSize')
gears = Integer()
-class Racket(Device):
+class Racket(Recreation):
pass
diff --git a/ereuse_devicehub/resources/device/states.py b/ereuse_devicehub/resources/device/states.py
index daaff20a..b0d0d439 100644
--- a/ereuse_devicehub/resources/device/states.py
+++ b/ereuse_devicehub/resources/device/states.py
@@ -40,6 +40,7 @@ class Trading(State):
# todo add Pay = e.Pay
ToBeDisposed = e.ToDisposeProduct
ProductDisposed = e.DisposeProduct
+ Available = e.MakeAvailable
class Physical(State):
@@ -49,12 +50,12 @@ class Physical(State):
:cvar Repaired: The device has been repaired.
:cvar Preparing: The device is going to be or being prepared.
:cvar Prepared: The device has been prepared.
- :cvar ReadyToBeUsed: The device is in working conditions.
+ :cvar Ready: The device is in working conditions.
:cvar InUse: The device is being reported to be in active use.
"""
ToBeRepaired = e.ToRepair
Repaired = e.Repair
Preparing = e.ToPrepare
Prepared = e.Prepare
- ReadyToBeUsed = e.Available
+ Ready = e.Ready
InUse = e.Live
diff --git a/ereuse_devicehub/resources/device/templates/devices/layout.html b/ereuse_devicehub/resources/device/templates/devices/layout.html
index afd62ae9..9b3a5f93 100644
--- a/ereuse_devicehub/resources/device/templates/devices/layout.html
+++ b/ereuse_devicehub/resources/device/templates/devices/layout.html
@@ -2,223 +2,208 @@
-
-
-
- Devicehub | {{ device.__format__('t') }}
+
+
+
+
+ Devicehub | {{ device.__format__('t') }}
-
+
-
-
-
-
-