Add docstrings to event models; remove redundant generic test
This commit is contained in:
parent
0ec06808ce
commit
560e0ed8dc
335
docs/actions.rst
335
docs/actions.rst
|
@ -38,43 +38,27 @@ to the `Swagger docs
|
||||||
|
|
||||||
Physical Actions
|
Physical Actions
|
||||||
****************
|
****************
|
||||||
The following actions describe and react on the physical condition
|
The following actions describe and react on the
|
||||||
|
:class:`ereuse_devicehub.resources.device.states.Physical` condition
|
||||||
of the devices.
|
of the devices.
|
||||||
|
|
||||||
ToPrepare, Prepare
|
ToPrepare, Prepare
|
||||||
==================
|
==================
|
||||||
Work has been performed to the device to a defined point of
|
.. autoclass:: ereuse_devicehub.resources.event.models.Prepare
|
||||||
acceptance. Users using this event have to agree what is this point
|
.. autoclass:: ereuse_devicehub.resources.event.models.ToPrepare
|
||||||
of acceptance; for some is when the device just works, for others
|
|
||||||
when some testing has been performed.
|
|
||||||
|
|
||||||
**Prepare** dictates that the device has been prepared, whereas
|
|
||||||
**ToPrepare** that the device has been selected to be prepared.
|
|
||||||
|
|
||||||
Usually **ToPrepare** is the next event done after registering the
|
|
||||||
device.
|
|
||||||
|
|
||||||
ToRepair, Repair
|
ToRepair, Repair
|
||||||
================
|
================
|
||||||
ToRepair is the act of selecting a device to be repaired, and
|
.. autoclass:: ereuse_devicehub.resources.event.models.Repair
|
||||||
Repair the act of performing the actual reparations. If a repair
|
.. autoclass:: ereuse_devicehub.resources.event.models.ToRepair
|
||||||
without an error is performed, it represents that the reparation
|
|
||||||
has been successful.
|
|
||||||
|
|
||||||
ReadyToUse
|
ReadyToUse
|
||||||
==========
|
==========
|
||||||
The device is ready to be used. This involves greater preparation
|
.. autoclass:: ereuse_devicehub.resources.event.models.ReadyToUse
|
||||||
from the ``Prepare`` event, and users should only use a device
|
|
||||||
after this event is performed.
|
|
||||||
|
|
||||||
Users usually require devices with this event before shipping them
|
|
||||||
to costumers.
|
|
||||||
|
|
||||||
Live
|
Live
|
||||||
====
|
====
|
||||||
A keep-alive from a device connected to the Internet with information
|
.. autoclass:: ereuse_devicehub.resources.event.models.Live
|
||||||
about its state (in the form of a ``Snapshot`` event) and usage
|
|
||||||
statistics.
|
|
||||||
|
|
||||||
DisposeWaste, Recover
|
DisposeWaste, Recover
|
||||||
=====================
|
=====================
|
||||||
|
@ -86,6 +70,8 @@ DisposeWaste, Recover
|
||||||
|
|
||||||
See `ToDisposeProduct, DisposeProduct`_.
|
See `ToDisposeProduct, DisposeProduct`_.
|
||||||
|
|
||||||
|
.. todo:: Events not developed yet.
|
||||||
|
|
||||||
Association actions
|
Association actions
|
||||||
*******************
|
*******************
|
||||||
Actions that change the associations users have with devices;
|
Actions that change the associations users have with devices;
|
||||||
|
@ -99,43 +85,29 @@ and **organize** actions.
|
||||||
|
|
||||||
Trade actions
|
Trade actions
|
||||||
=============
|
=============
|
||||||
Trade actions log the political exchange of devices between users,
|
Not fully developed.
|
||||||
stating **owner** xor **usufructuaree**. Every time a trade event
|
.. autoclass:: ereuse_devicehub.resources.event.models.Trade
|
||||||
is performed, the old user looses its political possession in favor
|
|
||||||
of another one.
|
|
||||||
|
|
||||||
Sell
|
Sell
|
||||||
----
|
----
|
||||||
The act of taking money from a buyer in exchange of a device.
|
.. autoclass:: ereuse_devicehub.resources.event.models.Sell
|
||||||
|
|
||||||
Donate
|
Donate
|
||||||
------
|
------
|
||||||
The act of giving devices without compensation.
|
.. autoclass:: ereuse_devicehub.resources.event.models.Donate
|
||||||
|
|
||||||
Rent
|
Rent
|
||||||
----
|
----
|
||||||
The act of giving money in return for temporary use, but not
|
.. autoclass:: ereuse_devicehub.resources.event.models.Rent
|
||||||
ownership, of a device.
|
|
||||||
|
|
||||||
CancelTrade
|
CancelTrade
|
||||||
-----------
|
-----------
|
||||||
The act of cancelling a `Sell`_, `Donate`_ or `Rent`_.
|
.. autoclass:: ereuse_devicehub.resources.event.models.CancelTrade
|
||||||
|
|
||||||
ToDisposeProduct, DisposeProduct
|
ToDisposeProduct, DisposeProduct
|
||||||
-------------------------
|
--------------------------------
|
||||||
``ToDispose`` and ``DisposeProduct`` manage the process of getting
|
.. autoclass:: ereuse_devicehub.resources.event.models.DisposeProduct
|
||||||
rid of devices by giving (selling, donating) to another organization
|
.. autoclass:: ereuse_devicehub.resources.event.models.ToDisposeProduct
|
||||||
like a waste manager.
|
|
||||||
|
|
||||||
``ToDispose`` marks a device for being disposed, and
|
|
||||||
``DisposeProduct`` dictates that the device has been disposed.
|
|
||||||
|
|
||||||
See `DisposeWaste, Recover`_ events for disposing without trading
|
|
||||||
the device.
|
|
||||||
|
|
||||||
.. note:: For usability purposes, users might not directly perform
|
|
||||||
``Dispose``, but this could automatically be done when
|
|
||||||
performing ``ToDispose`` + ``Receive`` to a ``RecyclingCenter``.
|
|
||||||
|
|
||||||
Transfer actions
|
Transfer actions
|
||||||
================
|
================
|
||||||
|
@ -143,34 +115,27 @@ The act of transferring/moving devices from one place to another.
|
||||||
|
|
||||||
Receive
|
Receive
|
||||||
-------
|
-------
|
||||||
The act of physically taking delivery of a device. The receiver
|
.. autoclass:: ereuse_devicehub.resources.event.models.Receive
|
||||||
confirms that the devices have arrived, and thus, they
|
.. autoclass:: ereuse_devicehub.resources.enums.ReceiverRole
|
||||||
**physically possess** them. Note that
|
:members:
|
||||||
there can only be one **physical possessor** per device, and
|
:undoc-members:
|
||||||
``Receive`` changes it.
|
.. autoattribute:: ereuse_devicehub.resources.device.models.Device.physical_possessor
|
||||||
|
|
||||||
The receiver can optionally take a role in the reception, giving
|
|
||||||
it meaning; an user that takes the ``FinalUser`` role in the
|
|
||||||
reception express that it will use the device, whereas a role
|
|
||||||
``Transporter`` is used by intermediaries in shipping.
|
|
||||||
|
|
||||||
.. todo:: how do we ensure users specify type of reception?
|
|
||||||
|
|
||||||
Organize actions
|
Organize actions
|
||||||
================
|
================
|
||||||
The act of manipulating/administering/supervising/controlling one or
|
.. autoclass:: ereuse_devicehub.resources.event.models.Organize
|
||||||
more devices.
|
|
||||||
|
|
||||||
Reserve, CancelReservation
|
Reserve, CancelReservation
|
||||||
--------------------------
|
-------------------------
|
||||||
The act of reserving devices and cancelling them.
|
Not fully developed.
|
||||||
|
|
||||||
After this event is performed, the user is the **reservee** of the
|
.. autoclass:: ereuse_devicehub.resources.event.models.Reserve
|
||||||
devices. There can only be one non-cancelled reservation for
|
.. autoclass:: ereuse_devicehub.resources.event.models.CancelReservation
|
||||||
a device, and a reservation can only have one reservee.
|
|
||||||
|
|
||||||
Assign, Accept, Reject
|
Assign, Accept, Reject
|
||||||
----------------------
|
----------------------
|
||||||
|
Not developed.
|
||||||
|
|
||||||
``Assign`` allocates devices to an user. The purpose or meaning
|
``Assign`` allocates devices to an user. The purpose or meaning
|
||||||
of the association is defined by the users.
|
of the association is defined by the users.
|
||||||
|
|
||||||
|
@ -179,9 +144,7 @@ assignments.
|
||||||
|
|
||||||
.. todo:: shall we add ``Deassign`` or make ``Assign``
|
.. todo:: shall we add ``Deassign`` or make ``Assign``
|
||||||
always define all active users?
|
always define all active users?
|
||||||
|
Assign won't be developed until further notice.
|
||||||
.. todo:: Assign won't be developed until further notice.
|
|
||||||
|
|
||||||
|
|
||||||
Internal state actions
|
Internal state actions
|
||||||
**********************
|
**********************
|
||||||
|
@ -190,254 +153,88 @@ their state.
|
||||||
|
|
||||||
Snapshot
|
Snapshot
|
||||||
========
|
========
|
||||||
The Snapshot sets the physical information of the device (S/N, model...)
|
.. autoclass:: ereuse_devicehub.resources.event.models.Snapshot
|
||||||
and updates it with erasures, benchmarks, ratings, and tests; updates the
|
|
||||||
composition of its components (adding / removing them), and links tags
|
|
||||||
to the device.
|
|
||||||
|
|
||||||
When receiving a Snapshot, the DeviceHub creates, adds and removes
|
|
||||||
components to match the Snapshot. For example, if a Snapshot of a computer
|
|
||||||
contains a new component, the system searches for the component in its
|
|
||||||
database and, if not found, its creates it; finally linking it to the
|
|
||||||
computer.
|
|
||||||
|
|
||||||
A Snapshot is used with Remove to represent changes in components for
|
|
||||||
a device:
|
|
||||||
|
|
||||||
1. ``Snapshot`` creates a device if it does not exist, and the same
|
|
||||||
for its components. This is all done in one ``Snapshot``.
|
|
||||||
2. If the device exists, it updates its component composition by
|
|
||||||
*adding* and *removing* them. If,
|
|
||||||
for example, this new Snasphot doesn't have a component, it means that
|
|
||||||
this component is not present anymore in the device, thus removing it
|
|
||||||
from it. Then we have that:
|
|
||||||
|
|
||||||
- Components that are added to the device: snapshot2.components -
|
|
||||||
snapshot1.components
|
|
||||||
- Components that are removed to the device: snapshot1.components -
|
|
||||||
snapshot2.components
|
|
||||||
|
|
||||||
When adding a component, there may be the case this component existed
|
|
||||||
before and it was inside another device. In such case, DeviceHub will
|
|
||||||
perform ``Remove`` on the old parent.
|
|
||||||
|
|
||||||
Snapshots from Workbench
|
|
||||||
------------------------
|
|
||||||
When processing a device from the Workbench, this one performs a Snapshot
|
|
||||||
and then performs more events (like testings, benchmarking...).
|
|
||||||
|
|
||||||
There are two ways of sending this information. In an async way,
|
|
||||||
this is, submitting events as soon as Workbench performs then, or
|
|
||||||
submitting only one Snapshot event with all the other events embedded.
|
|
||||||
|
|
||||||
Asynced
|
|
||||||
^^^^^^^
|
|
||||||
The use case, which is represented in the ``test_workbench_phases``,
|
|
||||||
is as follows:
|
|
||||||
|
|
||||||
1. In **T1**, WorkbenchServer (as the middleware from Workbench and
|
|
||||||
Devicehub) submits:
|
|
||||||
|
|
||||||
- A ``Snapshot`` event with the required information to **synchronize**
|
|
||||||
and **rate** the device. This is:
|
|
||||||
|
|
||||||
- Identification information about the device and components
|
|
||||||
(S/N, model, physical characteristics...)
|
|
||||||
- ``Tags`` in a ``tags`` property in the ``device``.
|
|
||||||
- ``Rate`` in an ``events`` property in the ``device``.
|
|
||||||
- ``Benchmarks`` in an ``events`` property in each ``component``
|
|
||||||
or ``device``.
|
|
||||||
- ``TestDataStorage`` as in ``Benchmarks``.
|
|
||||||
- An ordered set of **expected events**, defining which are the next
|
|
||||||
events that Workbench will perform to the device in ideal
|
|
||||||
conditions (device doesn't fail, no Internet drop...).
|
|
||||||
|
|
||||||
Devicehub **syncs** the device with the database and perform the
|
|
||||||
``Benchmark``, the ``TestDataStorage``, and finally the ``Rate``.
|
|
||||||
This leaves the Snapshot **open** to wait for the next events
|
|
||||||
to come.
|
|
||||||
2. Assuming that we expect all events, in **T2**, WorkbenchServer
|
|
||||||
submits a ``StressTest`` with a ``snapshot`` field containing the
|
|
||||||
ID of the Snapshot in 1, and Devicehub links the event with such
|
|
||||||
``Snapshot``.
|
|
||||||
3. In **T3**, WorkbenchServer submits the ``Erase`` with the ``Snapshot``
|
|
||||||
and ``component`` IDs from 1, linking it to them. It repeats
|
|
||||||
this for all the erased data storage devices; **T3+Tn** being
|
|
||||||
*n* the erased data storage devices.
|
|
||||||
4. WorkbenchServer does like in 3. but for the event ``Install``,
|
|
||||||
finishing in **T3+Tn+Tx**, being *x* the number of data storage
|
|
||||||
devices with an OS installed into.
|
|
||||||
5. In **T3+Tn+Tx**, when all *expected events* have been performed,
|
|
||||||
Devicehub **closes** the ``Snapshot`` from 1.
|
|
||||||
|
|
||||||
Synced
|
|
||||||
^^^^^^
|
|
||||||
Optionally, Devicehub understands receiving a ``Snapshot`` with all
|
|
||||||
the events in an ``events`` property inside each affected ``component``
|
|
||||||
or ``device``.
|
|
||||||
|
|
||||||
Add, Remove
|
Add, Remove
|
||||||
===========
|
===========
|
||||||
The act of adding and removing components of and from a device.
|
.. autoclass:: ereuse_devicehub.resources.event.models.Add
|
||||||
|
.. autoclass:: ereuse_devicehub.resources.event.models.Remove
|
||||||
These are usually used internally from `Snapshot`_, or manually, for
|
|
||||||
example, when removing a component (like a ``DataStorage`` unit) from
|
|
||||||
a broken computer.
|
|
||||||
|
|
||||||
EraseBasic, EraseSectors
|
EraseBasic, EraseSectors
|
||||||
========================
|
========================
|
||||||
An erasure attempt to a ``DataStorage``. The event contains
|
.. autoclass:: ereuse_devicehub.resources.event.models.EraseBasic
|
||||||
information about success and nature of the erasure.
|
.. autoclass:: ereuse_devicehub.resources.event.models.EraseSectors
|
||||||
|
.. autoclass:: ereuse_devicehub.resources.event.models.ErasePhysical
|
||||||
``EraseBasic`` is a fast non-secured way of erasing data storage, and
|
|
||||||
``EraseSectors`` is a slower secured, sector-by-sector, erasure
|
|
||||||
method.
|
|
||||||
|
|
||||||
Users can generate erasure certificates from successful erasures.
|
|
||||||
|
|
||||||
Erasures are an accumulation of **erasure steps**, that are performed
|
|
||||||
as separate actions, called ``StepRandom``, for an erasure step
|
|
||||||
that has overwritten data with random bits, and ``StepZero``,
|
|
||||||
for an erasure step that has overwritten data with zeros.
|
|
||||||
|
|
||||||
Install
|
Install
|
||||||
=======
|
=======
|
||||||
The action of install an Operative System to a data storage unit.
|
.. autoclass:: ereuse_devicehub.resources.event.models.Install
|
||||||
|
|
||||||
Test
|
Test
|
||||||
====
|
====
|
||||||
The act of testing the physical condition of a device and its
|
.. autoclass:: ereuse_devicehub.resources.event.models.Test
|
||||||
components.
|
|
||||||
|
|
||||||
TestDataStorage
|
TestDataStorage
|
||||||
---------------
|
---------------
|
||||||
The act of testing the data storage.
|
.. autoclass:: ereuse_devicehub.resources.event.models.TestDataStorage
|
||||||
|
|
||||||
Testing is done using the `S.M.A.R.T self test
|
|
||||||
<https://en.wikipedia.org/wiki/S.M.A.R.T.#Self-tests>`_. Note
|
|
||||||
that not all data storage units, specially some new PCIe ones, do not
|
|
||||||
support SMART testing.
|
|
||||||
|
|
||||||
The test takes to other SMART values indicators of the overall health
|
|
||||||
of the data storage.
|
|
||||||
|
|
||||||
StressTest
|
StressTest
|
||||||
----------
|
----------
|
||||||
The act of stressing (putting to the maximum capacity)
|
.. autoclass:: ereuse_devicehub.resources.event.models.StressTest
|
||||||
a device for an amount of minutes. If the device is not in great
|
|
||||||
condition won't probably survive such test.
|
|
||||||
|
|
||||||
Benchmark
|
Benchmark
|
||||||
=========
|
=========
|
||||||
The act of gauging the performance of a device.
|
.. autoclass:: ereuse_devicehub.resources.event.models.Benchmark
|
||||||
|
|
||||||
|
|
||||||
BenchmarkDataStorage
|
BenchmarkDataStorage
|
||||||
--------------------
|
--------------------
|
||||||
Benchmarks the data storage unit reading and writing speeds.
|
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkDataStorage
|
||||||
|
|
||||||
|
|
||||||
BenchmarkWithRate
|
BenchmarkWithRate
|
||||||
-----------------
|
-----------------
|
||||||
The act of benchmarking a device with a single rate.
|
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkWithRate
|
||||||
|
|
||||||
|
|
||||||
BenchmarkProcessor
|
BenchmarkProcessor
|
||||||
------------------
|
------------------
|
||||||
Benchmarks a processor by executing `BogoMips
|
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkProcessor
|
||||||
<https://en.wikipedia.org/wiki/BogoMips>`_. Note that this is not
|
|
||||||
a reliable way of rating processors and we keep it for compatibility
|
|
||||||
purposes.
|
|
||||||
|
|
||||||
BenchmarkProcessorSysbench
|
BenchmarkProcessorSysbench
|
||||||
--------------------------
|
--------------------------
|
||||||
Benchmarks a processor by using the processor benchmarking utility of
|
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkProcessorSysbench
|
||||||
`sysbench <https://github.com/akopytov/sysbench>`_.
|
|
||||||
|
|
||||||
|
|
||||||
|
BenchmarkRamSysbench
|
||||||
|
--------------------
|
||||||
|
.. autoclass:: ereuse_devicehub.resources.event.models.BenchmarkRamSysbench
|
||||||
|
|
||||||
Rate
|
Rate
|
||||||
====
|
====
|
||||||
Devicehub generates an rating for a device taking into consideration the
|
.. autoclass:: ereuse_devicehub.resources.event.models.Rate
|
||||||
visual, functional, and performance.
|
|
||||||
|
|
||||||
A Workflow is as follows:
|
|
||||||
|
|
||||||
1. An agent generates feedback from the device in the form of benchmark,
|
|
||||||
visual, and functional information; which is filled in a ``Rate``
|
|
||||||
event. This is done through a **software**, defining the type
|
|
||||||
of ``Rate`` event. At the moment we have two rates: ``WorkbenchRate``
|
|
||||||
and ``PhotoboxRate``.
|
|
||||||
2. Devicehub gathers this information and computes a score that updates
|
|
||||||
the ``Rate`` event.
|
|
||||||
3. Devicehub aggregates different rates and computes a final score for
|
|
||||||
the device by performing a new ``AggregateRating`` event.
|
|
||||||
|
|
||||||
There are three **types** of ``Rate``: ``WorkbenchRate``,
|
|
||||||
``AppRate``, and ``PhotoboxRate``. ``WorkbenchRate`` can have different
|
|
||||||
**software** algorithms, and each software algorithm can have several
|
|
||||||
**versions**. So, we have 3 dimensions for ``WorkbenchRate``:
|
|
||||||
type, software, version.
|
|
||||||
|
|
||||||
Devicehub generates a rate event for each software and version. So,
|
|
||||||
if an agent fulfills a ``WorkbenchRate`` and there are 2 software
|
|
||||||
algorithms and each has two versions, Devicehub will generate 4 rates.
|
|
||||||
Devicehub understands that only one software and version are the
|
|
||||||
**oficial** (set in the settings of each inventory),
|
|
||||||
and it will generate an ``AggregateRating`` for only the official
|
|
||||||
versions. At the same time, ``Price`` only computes the price of
|
|
||||||
the **oficial** version.
|
|
||||||
|
|
||||||
The technical Workflow in Devicehub is as follows:
|
|
||||||
|
|
||||||
1. In **T1**, the user performs a ``Snapshot`` by processing the device
|
|
||||||
through the Workbench. From the benchmarks and the visual and
|
|
||||||
functional ratings the user does in the device, the system generates
|
|
||||||
many ``WorkbenchRate`` (as many as software and versions defined).
|
|
||||||
With only this information, the system generates an ``AggregateRating``,
|
|
||||||
which is the event that the user will see in the web.
|
|
||||||
2. In **T2**, the user takes pictures from the device through the
|
|
||||||
Photobox, and DeviceHub crates an ``ImageSet`` with multiple
|
|
||||||
``Image`` with information from the photobox.
|
|
||||||
3. In **T3**, an agent (user or AI) rates the pictures, creating a
|
|
||||||
``PhotoboxRate`` **for each** picture. When Devicehub receives the
|
|
||||||
first ``PhotoboxRate`` it creates an ``AggregateRating`` linked
|
|
||||||
to such ``PhotoboxRate``. So, the agent will perform as many
|
|
||||||
``PhotoboxRate`` as pictures are in the ``ImageSet``, and Devicehub
|
|
||||||
will link each ``PhotoboxRate`` to the same ``AggregateRating``.
|
|
||||||
This will end in **T3+Tn**, being *n* the number of photos to rate.
|
|
||||||
4. In **T3+Tn**, after the last photo is rated, Devicehub will generate
|
|
||||||
a new rate for the device: it takes the ``AggregateRating`` from 3.
|
|
||||||
and computes a rate from all the linked ``PhotoboxRate`` plus the
|
|
||||||
last available ``WorkbenchRate`` for that device.
|
|
||||||
|
|
||||||
If the agent in 3. is an user, Devicehub creates ``PhotoboxUserRate``
|
|
||||||
and if it is an AI it creates ``PhotoboxAIRate``.
|
|
||||||
|
|
||||||
The same ``ImageSet`` can be rated multiple times, generating a new
|
|
||||||
``AggregateRating`` each time.
|
|
||||||
|
|
||||||
Price
|
Price
|
||||||
=====
|
=====
|
||||||
Price states a selling price for the device, but not necessariliy the
|
.. autoclass:: ereuse_devicehub.resources.event.models.Price
|
||||||
final price this was sold (which is set in the Sell event).
|
|
||||||
|
|
||||||
Devicehub automatically computes a price from ``AggregateRating``
|
|
||||||
events. As in a **Rate**, price can have **software** and **version**,
|
|
||||||
and there is an **official** price that is used to automatically
|
|
||||||
compute the price from an ``AggregateRating``. Only the official price
|
|
||||||
is computed from an ``AggregateRating``.
|
|
||||||
|
|
||||||
Migrate
|
Migrate
|
||||||
=======
|
=======
|
||||||
Moves the devices to a new database/inventory. Devices cannot be
|
Not done.
|
||||||
modified anymore at the previous database.
|
|
||||||
|
|
||||||
Donation
|
|
||||||
========
|
|
||||||
.. todo:: nextcloud/eReuse/99. Tasks/224. Definir datos necesarios
|
|
||||||
configuración licencia
|
|
||||||
|
|
||||||
|
.. autoclass:: ereuse_devicehub.resources.event.models.Migrate
|
||||||
|
|
||||||
States
|
States
|
||||||
******
|
******
|
||||||
.. todo:: work on september.
|
.. autoclass:: ereuse_devicehub.resources.device.states.State
|
||||||
|
|
||||||
.. uml:: states.puml
|
.. uml:: states.puml
|
||||||
|
|
||||||
|
.. autoclass:: ereuse_devicehub.resources.device.states.Trading
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
.. autoclass:: ereuse_devicehub.resources.device.states.Physical
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#
|
#
|
||||||
# import os
|
# import os
|
||||||
# import sys
|
# import sys
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
# sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
@ -42,7 +42,8 @@ extensions = [
|
||||||
'sphinx.ext.todo',
|
'sphinx.ext.todo',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
'sphinxcontrib.plantuml',
|
'sphinxcontrib.plantuml',
|
||||||
'sphinx.ext.autosectionlabel'
|
'sphinx.ext.autosectionlabel',
|
||||||
|
'sphinx.ext.autodoc'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
@ -159,7 +160,7 @@ texinfo_documents = [
|
||||||
# -- Options for intersphinx extension ---------------------------------------
|
# -- Options for intersphinx extension ---------------------------------------
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
|
||||||
|
|
||||||
# -- Options for todo extension ----------------------------------------------
|
# -- Options for todo extension ----------------------------------------------
|
||||||
|
|
||||||
|
@ -174,3 +175,4 @@ html_favicon = 'img/favicon.ico'
|
||||||
|
|
||||||
# autosectionlabel
|
# autosectionlabel
|
||||||
autosectionlabel_prefix_document = True
|
autosectionlabel_prefix_document = True
|
||||||
|
autodoc_member_order = 'bysource'
|
||||||
|
|
|
@ -46,3 +46,10 @@ The result is a JSON object with the following fields:
|
||||||
or ``1``.
|
or ``1``.
|
||||||
- **perPage**: How many devices are in every page, fixed to ``30``.
|
- **perPage**: How many devices are in every page, fixed to ``30``.
|
||||||
- **total**: How many total devices passed the filters.
|
- **total**: How many total devices passed the filters.
|
||||||
|
|
||||||
|
Models
|
||||||
|
******
|
||||||
|
|
||||||
|
.. automodule:: ereuse_devicehub.resources.device.models
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
|
@ -178,6 +178,10 @@ class Device(Thing):
|
||||||
that has it physically. As an example, a transporter could
|
that has it physically. As an example, a transporter could
|
||||||
be a physical possessor of a device although it does not
|
be a physical possessor of a device although it does not
|
||||||
own it legally.
|
own it legally.
|
||||||
|
|
||||||
|
Note that there can only be one physical possessor per device,
|
||||||
|
and :class:`ereuse_devicehub.resources.event.models.Receive`
|
||||||
|
changes it.
|
||||||
"""
|
"""
|
||||||
from ereuse_devicehub.resources.event.models import Receive
|
from ereuse_devicehub.resources.event.models import Receive
|
||||||
with suppress(LookupError):
|
with suppress(LookupError):
|
||||||
|
@ -190,7 +194,7 @@ class Device(Thing):
|
||||||
device is working if the list is empty.
|
device is working if the list is empty.
|
||||||
|
|
||||||
This property returns, for the last test performed of each type,
|
This property returns, for the last test performed of each type,
|
||||||
the one with the worst severity of them, or None if no
|
the one with the worst severity of them, or `None` if no
|
||||||
test has been executed.
|
test has been executed.
|
||||||
"""
|
"""
|
||||||
from ereuse_devicehub.resources.event.models import Test
|
from ereuse_devicehub.resources.event.models import Test
|
||||||
|
|
|
@ -263,11 +263,19 @@ class EventDevice(db.Model):
|
||||||
|
|
||||||
|
|
||||||
class Add(EventWithOneDevice):
|
class Add(EventWithOneDevice):
|
||||||
pass
|
"""The act of adding components to a device.
|
||||||
|
|
||||||
|
It is usually used internally from a :class:`.Snapshot`, for
|
||||||
|
example, when adding a secondary data storage to a computer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Remove(EventWithOneDevice):
|
class Remove(EventWithOneDevice):
|
||||||
pass
|
"""The act of removing components from a device.
|
||||||
|
|
||||||
|
It is usually used internally from a :class:`.Snapshot`, for
|
||||||
|
example, when removing a component from a broken computer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Allocate(JoinedTableMixin, EventWithMultipleDevices):
|
class Allocate(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
|
@ -283,6 +291,30 @@ class Deallocate(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
|
|
||||||
|
|
||||||
class EraseBasic(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class EraseBasic(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""An erasure attempt to a ``DataStorage``. The event contains
|
||||||
|
information about success and nature of the erasure.
|
||||||
|
|
||||||
|
EraseBasic is a software-based fast non-100%-secured way of
|
||||||
|
erasing data storage, performed
|
||||||
|
by Workbench Computer when executing the open-source
|
||||||
|
`shred <https://en.wikipedia.org/wiki/Shred_(Unix)>`_.
|
||||||
|
|
||||||
|
Users can generate erasure certificates from successful erasures.
|
||||||
|
|
||||||
|
Erasures are an accumulation of **erasure steps**, that are performed
|
||||||
|
as separate actions, called ``StepRandom``, for an erasure step
|
||||||
|
that has overwritten data with random bits, and ``StepZero``,
|
||||||
|
for an erasure step that has overwritten data with zeros.
|
||||||
|
|
||||||
|
For example, if steps are set in the following order and the user
|
||||||
|
used `EraseSectors`, the event represents a
|
||||||
|
`British HMG Infosec Standard 5 (HMG IS5) <https://en.wikipedia.org/
|
||||||
|
wiki/Infosec_Standard_5>`_:
|
||||||
|
|
||||||
|
1. A first step writing zeroes to the hard-drives.
|
||||||
|
2. A second step erasing with random data, verifying the erasure
|
||||||
|
success in each hard-drive sector.
|
||||||
|
"""
|
||||||
zeros = Column(Boolean, nullable=False)
|
zeros = Column(Boolean, nullable=False)
|
||||||
zeros.comment = """
|
zeros.comment = """
|
||||||
Whether this erasure had a first erasure step consisting of
|
Whether this erasure had a first erasure step consisting of
|
||||||
|
@ -296,11 +328,14 @@ class EraseBasic(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
|
||||||
|
|
||||||
class EraseSectors(EraseBasic):
|
class EraseSectors(EraseBasic):
|
||||||
pass
|
"""A secured-way of erasing data storages, checking sector-by-sector
|
||||||
|
the erasure, using `badblocks <https://en.wikipedia.org/wiki/Badblocks>`_.
|
||||||
|
"""
|
||||||
|
# todo make a property that says if the data wiping process is british...
|
||||||
|
|
||||||
|
|
||||||
class ErasePhysical(EraseBasic):
|
class ErasePhysical(EraseBasic):
|
||||||
"""Physical destruction of a data storage unit."""
|
"""The act of physically destroying a data storage unit."""
|
||||||
# todo add attributes
|
# todo add attributes
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -346,6 +381,92 @@ class StepRandom(Step):
|
||||||
|
|
||||||
|
|
||||||
class Snapshot(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Snapshot(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""The Snapshot sets the physical information of the device (S/N, model...)
|
||||||
|
and updates it with erasures, benchmarks, ratings, and tests; updates the
|
||||||
|
composition of its components (adding / removing them), and links tags
|
||||||
|
to the device.
|
||||||
|
|
||||||
|
When receiving a Snapshot, the DeviceHub creates, adds and removes
|
||||||
|
components to match the Snapshot. For example, if a Snapshot of a computer
|
||||||
|
contains a new component, the system searches for the component in its
|
||||||
|
database and, if not found, its creates it; finally linking it to the
|
||||||
|
computer.
|
||||||
|
|
||||||
|
A Snapshot is used with Remove to represent changes in components for
|
||||||
|
a device:
|
||||||
|
|
||||||
|
1. ``Snapshot`` creates a device if it does not exist, and the same
|
||||||
|
for its components. This is all done in one ``Snapshot``.
|
||||||
|
2. If the device exists, it updates its component composition by
|
||||||
|
*adding* and *removing* them. If,
|
||||||
|
for example, this new Snasphot doesn't have a component, it means that
|
||||||
|
this component is not present anymore in the device, thus removing it
|
||||||
|
from it. Then we have that:
|
||||||
|
|
||||||
|
- Components that are added to the device: snapshot2.components -
|
||||||
|
snapshot1.components
|
||||||
|
- Components that are removed to the device: snapshot1.components -
|
||||||
|
snapshot2.components
|
||||||
|
|
||||||
|
When adding a component, there may be the case this component existed
|
||||||
|
before and it was inside another device. In such case, DeviceHub will
|
||||||
|
perform ``Remove`` on the old parent.
|
||||||
|
|
||||||
|
**Snapshots from Workbench**
|
||||||
|
|
||||||
|
When processing a device from the Workbench, this one performs a Snapshot
|
||||||
|
and then performs more events (like testings, benchmarking...).
|
||||||
|
|
||||||
|
There are two ways of sending this information. In an async way,
|
||||||
|
this is, submitting events as soon as Workbench performs then, or
|
||||||
|
submitting only one Snapshot event with all the other events embedded.
|
||||||
|
|
||||||
|
**Asynced**
|
||||||
|
|
||||||
|
The use case, which is represented in the ``test_workbench_phases``,
|
||||||
|
is as follows:
|
||||||
|
|
||||||
|
1. In **T1**, WorkbenchServer (as the middleware from Workbench and
|
||||||
|
Devicehub) submits:
|
||||||
|
|
||||||
|
- A ``Snapshot`` event with the required information to **synchronize**
|
||||||
|
and **rate** the device. This is:
|
||||||
|
|
||||||
|
- Identification information about the device and components
|
||||||
|
(S/N, model, physical characteristics...)
|
||||||
|
- ``Tags`` in a ``tags`` property in the ``device``.
|
||||||
|
- ``Rate`` in an ``events`` property in the ``device``.
|
||||||
|
- ``Benchmarks`` in an ``events`` property in each ``component``
|
||||||
|
or ``device``.
|
||||||
|
- ``TestDataStorage`` as in ``Benchmarks``.
|
||||||
|
- An ordered set of **expected events**, defining which are the next
|
||||||
|
events that Workbench will perform to the device in ideal
|
||||||
|
conditions (device doesn't fail, no Internet drop...).
|
||||||
|
|
||||||
|
Devicehub **syncs** the device with the database and perform the
|
||||||
|
``Benchmark``, the ``TestDataStorage``, and finally the ``Rate``.
|
||||||
|
This leaves the Snapshot **open** to wait for the next events
|
||||||
|
to come.
|
||||||
|
2. Assuming that we expect all events, in **T2**, WorkbenchServer
|
||||||
|
submits a ``StressTest`` with a ``snapshot`` field containing the
|
||||||
|
ID of the Snapshot in 1, and Devicehub links the event with such
|
||||||
|
``Snapshot``.
|
||||||
|
3. In **T3**, WorkbenchServer submits the ``Erase`` with the ``Snapshot``
|
||||||
|
and ``component`` IDs from 1, linking it to them. It repeats
|
||||||
|
this for all the erased data storage devices; **T3+Tn** being
|
||||||
|
*n* the erased data storage devices.
|
||||||
|
4. WorkbenchServer does like in 3. but for the event ``Install``,
|
||||||
|
finishing in **T3+Tn+Tx**, being *x* the number of data storage
|
||||||
|
devices with an OS installed into.
|
||||||
|
5. In **T3+Tn+Tx**, when all *expected events* have been performed,
|
||||||
|
Devicehub **closes** the ``Snapshot`` from 1.
|
||||||
|
|
||||||
|
**Synced**
|
||||||
|
|
||||||
|
Optionally, Devicehub understands receiving a ``Snapshot`` with all
|
||||||
|
the events in an ``events`` property inside each affected ``component``
|
||||||
|
or ``device``.
|
||||||
|
"""
|
||||||
uuid = Column(UUID(as_uuid=True), unique=True)
|
uuid = Column(UUID(as_uuid=True), unique=True)
|
||||||
version = Column(StrictVersionType(STR_SM_SIZE), nullable=False)
|
version = Column(StrictVersionType(STR_SM_SIZE), nullable=False)
|
||||||
software = Column(DBEnum(SnapshotSoftware), nullable=False)
|
software = Column(DBEnum(SnapshotSoftware), nullable=False)
|
||||||
|
@ -361,6 +482,9 @@ class Snapshot(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
|
||||||
|
|
||||||
class Install(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Install(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""The action of installing an Operative System to a data
|
||||||
|
storage unit.
|
||||||
|
"""
|
||||||
elapsed = Column(Interval, nullable=False)
|
elapsed = Column(Interval, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,6 +499,48 @@ class SnapshotRequest(db.Model):
|
||||||
|
|
||||||
|
|
||||||
class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Rate(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""Devicehub generates an rating for a device taking into consideration the
|
||||||
|
visual, functional, and performance.
|
||||||
|
|
||||||
|
A Workflow is as follows:
|
||||||
|
|
||||||
|
1. An agent generates feedback from the device in the form of benchmark,
|
||||||
|
visual, and functional information; which is filled in a ``Rate``
|
||||||
|
event. This is done through a **software**, defining the type
|
||||||
|
of ``Rate`` event. At the moment we have ``WorkbenchRate``.
|
||||||
|
2. Devicehub gathers this information and computes a score that updates
|
||||||
|
the ``Rate`` event.
|
||||||
|
3. Devicehub aggregates different rates and computes a final score for
|
||||||
|
the device by performing a new ``AggregateRating`` event.
|
||||||
|
|
||||||
|
There are two base **types** of ``Rate``: ``WorkbenchRate``,
|
||||||
|
``ManualRate``. ``WorkbenchRate`` can have different
|
||||||
|
**software** algorithms, and each software algorithm can have several
|
||||||
|
**versions**. So, we have 3 dimensions for ``WorkbenchRate``:
|
||||||
|
type, software, version.
|
||||||
|
|
||||||
|
Devicehub generates a rate event for each software and version. So,
|
||||||
|
if an agent fulfills a ``WorkbenchRate`` and there are 2 software
|
||||||
|
algorithms and each has two versions, Devicehub will generate 4 rates.
|
||||||
|
Devicehub understands that only one software and version are the
|
||||||
|
**oficial** (set in the settings of each inventory),
|
||||||
|
and it will generate an ``AggregateRating`` for only the official
|
||||||
|
versions. At the same time, ``Price`` only computes the price of
|
||||||
|
the **oficial** version.
|
||||||
|
|
||||||
|
The technical Workflow in Devicehub is as follows:
|
||||||
|
|
||||||
|
1. In **T1**, the user performs a ``Snapshot`` by processing the device
|
||||||
|
through the Workbench. From the benchmarks and the visual and
|
||||||
|
functional ratings the user does in the device, the system generates
|
||||||
|
many ``WorkbenchRate`` (as many as software and versions defined).
|
||||||
|
With only this information, the system generates an ``AggregateRating``,
|
||||||
|
which is the event that the user will see in the web.
|
||||||
|
2. In **T2**, the agent can optionally visually re-rate the device
|
||||||
|
using the mobile app, generating an ``AppRate``. This new
|
||||||
|
action generates a new ``AggregateRating`` with the ``AppRate``
|
||||||
|
plus the ``WorkbenchRate`` from 1.
|
||||||
|
"""
|
||||||
rating = Column(Float(decimal_return_scale=2), check_range('rating', *RATE_POSITIVE))
|
rating = Column(Float(decimal_return_scale=2), check_range('rating', *RATE_POSITIVE))
|
||||||
rating.comment = """The rating for the content."""
|
rating.comment = """The rating for the content."""
|
||||||
software = Column(DBEnum(RatingSoftware))
|
software = Column(DBEnum(RatingSoftware))
|
||||||
|
@ -572,6 +738,16 @@ class AggregateRate(Rate):
|
||||||
|
|
||||||
|
|
||||||
class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Price(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""Price states a selling price for the device, but not
|
||||||
|
necessarily the final price this is sold (which is set in the Sell
|
||||||
|
event).
|
||||||
|
|
||||||
|
Devicehub automatically computes a price from ``AggregateRating``
|
||||||
|
events. As in a **Rate**, price can have **software** and **version**,
|
||||||
|
and there is an **official** price that is used to automatically
|
||||||
|
compute the price from an ``AggregateRating``. Only the official price
|
||||||
|
is computed from an ``AggregateRating``.
|
||||||
|
"""
|
||||||
SCALE = 4
|
SCALE = 4
|
||||||
ROUND = ROUND_HALF_EVEN
|
ROUND = ROUND_HALF_EVEN
|
||||||
currency = Column(DBEnum(Currency), nullable=False)
|
currency = Column(DBEnum(Currency), nullable=False)
|
||||||
|
@ -713,6 +889,12 @@ class EreusePrice(Price):
|
||||||
|
|
||||||
|
|
||||||
class Test(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Test(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""The act of testing the physical condition of a device and its
|
||||||
|
components.
|
||||||
|
|
||||||
|
Testing errors and warnings are easily taken in
|
||||||
|
:attr:`ereuse_devicehub.resources.device.models.Device.working`.
|
||||||
|
"""
|
||||||
elapsed = Column(Interval, nullable=False)
|
elapsed = Column(Interval, nullable=False)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
|
@ -731,6 +913,17 @@ class Test(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
|
||||||
|
|
||||||
class TestDataStorage(Test):
|
class TestDataStorage(Test):
|
||||||
|
"""
|
||||||
|
The act of testing the data storage.
|
||||||
|
|
||||||
|
Testing is done using the `S.M.A.R.T self test
|
||||||
|
<https://en.wikipedia.org/wiki/S.M.A.R.T.#Self-tests>`_. Note
|
||||||
|
that not all data storage units, specially some new PCIe ones, do not
|
||||||
|
support SMART testing.
|
||||||
|
|
||||||
|
The test takes to other SMART values indicators of the overall health
|
||||||
|
of the data storage.
|
||||||
|
"""
|
||||||
id = Column(UUID(as_uuid=True), ForeignKey(Test.id), primary_key=True)
|
id = Column(UUID(as_uuid=True), ForeignKey(Test.id), primary_key=True)
|
||||||
length = Column(DBEnum(TestDataStorageLength), nullable=False) # todo from type
|
length = Column(DBEnum(TestDataStorageLength), nullable=False) # todo from type
|
||||||
status = Column(Unicode(), check_lower('status'), nullable=False)
|
status = Column(Unicode(), check_lower('status'), nullable=False)
|
||||||
|
@ -768,6 +961,10 @@ class TestDataStorage(Test):
|
||||||
|
|
||||||
|
|
||||||
class StressTest(Test):
|
class StressTest(Test):
|
||||||
|
"""The act of stressing (putting to the maximum capacity)
|
||||||
|
a device for an amount of minutes. If the device is not in great
|
||||||
|
condition won't probably survive such test.
|
||||||
|
"""
|
||||||
|
|
||||||
@validates('elapsed')
|
@validates('elapsed')
|
||||||
def is_minute_and_bigger_than_1_minute(self, _, value: timedelta):
|
def is_minute_and_bigger_than_1_minute(self, _, value: timedelta):
|
||||||
|
@ -781,6 +978,7 @@ class StressTest(Test):
|
||||||
|
|
||||||
|
|
||||||
class Benchmark(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Benchmark(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""The act of gauging the performance of a device."""
|
||||||
elapsed = Column(Interval)
|
elapsed = Column(Interval)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
|
@ -799,6 +997,7 @@ class Benchmark(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkDataStorage(Benchmark):
|
class BenchmarkDataStorage(Benchmark):
|
||||||
|
"""Benchmarks the data storage unit reading and writing speeds."""
|
||||||
id = Column(UUID(as_uuid=True), ForeignKey(Benchmark.id), primary_key=True)
|
id = Column(UUID(as_uuid=True), ForeignKey(Benchmark.id), primary_key=True)
|
||||||
read_speed = Column(Float(decimal_return_scale=2), nullable=False)
|
read_speed = Column(Float(decimal_return_scale=2), nullable=False)
|
||||||
write_speed = Column(Float(decimal_return_scale=2), nullable=False)
|
write_speed = Column(Float(decimal_return_scale=2), nullable=False)
|
||||||
|
@ -808,6 +1007,7 @@ class BenchmarkDataStorage(Benchmark):
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkWithRate(Benchmark):
|
class BenchmarkWithRate(Benchmark):
|
||||||
|
"""The act of benchmarking a device with a single rate."""
|
||||||
id = Column(UUID(as_uuid=True), ForeignKey(Benchmark.id), primary_key=True)
|
id = Column(UUID(as_uuid=True), ForeignKey(Benchmark.id), primary_key=True)
|
||||||
rate = Column(Float, nullable=False)
|
rate = Column(Float, nullable=False)
|
||||||
|
|
||||||
|
@ -816,11 +1016,18 @@ class BenchmarkWithRate(Benchmark):
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkProcessor(BenchmarkWithRate):
|
class BenchmarkProcessor(BenchmarkWithRate):
|
||||||
|
"""Benchmarks a processor by executing `BogoMips
|
||||||
|
<https://en.wikipedia.org/wiki/BogoMips>`_. Note that this is not
|
||||||
|
a reliable way of rating processors and we keep it for compatibility
|
||||||
|
purposes.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkProcessorSysbench(BenchmarkProcessor):
|
class BenchmarkProcessorSysbench(BenchmarkProcessor):
|
||||||
pass
|
"""Benchmarks a processor by using the processor benchmarking
|
||||||
|
utility of `sysbench <https://github.com/akopytov/sysbench>`_.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BenchmarkRamSysbench(BenchmarkWithRate):
|
class BenchmarkRamSysbench(BenchmarkWithRate):
|
||||||
|
@ -828,26 +1035,54 @@ class BenchmarkRamSysbench(BenchmarkWithRate):
|
||||||
|
|
||||||
|
|
||||||
class ToRepair(EventWithMultipleDevices):
|
class ToRepair(EventWithMultipleDevices):
|
||||||
pass
|
"""Select a device to be repaired."""
|
||||||
|
|
||||||
|
|
||||||
class Repair(EventWithMultipleDevices):
|
class Repair(EventWithMultipleDevices):
|
||||||
pass
|
"""Repair is the act of performing reparations.
|
||||||
|
|
||||||
|
If a repair without an error is performed,
|
||||||
|
it represents that the reparation has been successful.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ReadyToUse(EventWithMultipleDevices):
|
class ReadyToUse(EventWithMultipleDevices):
|
||||||
pass
|
"""The device is ready to be used.
|
||||||
|
|
||||||
|
This involves greater preparation from the ``Prepare`` event,
|
||||||
|
and users should only use a device after this event is performed.
|
||||||
|
|
||||||
|
Users usually require devices with this event before shipping them
|
||||||
|
to costumers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ToPrepare(EventWithMultipleDevices):
|
class ToPrepare(EventWithMultipleDevices):
|
||||||
|
"""The device has been selected for preparation.
|
||||||
|
|
||||||
|
See Prepare for more info.
|
||||||
|
|
||||||
|
Usually **ToPrepare** is the next event done after registering the
|
||||||
|
device.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Prepare(EventWithMultipleDevices):
|
class Prepare(EventWithMultipleDevices):
|
||||||
pass
|
"""Work has been performed to the device to a defined point of
|
||||||
|
acceptance.
|
||||||
|
|
||||||
|
Users using this event have to agree what is this point
|
||||||
|
of acceptance; for some is when the device just works, for others
|
||||||
|
when some testing has been performed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Live(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
class Live(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
"""A keep-alive from a device connected to the Internet with
|
||||||
|
information about its state (in the form of a ``Snapshot`` event)
|
||||||
|
and usage statistics.
|
||||||
|
"""
|
||||||
ip = Column(IP, nullable=False,
|
ip = Column(IP, nullable=False,
|
||||||
comment='The IP where the live was triggered.')
|
comment='The IP where the live was triggered.')
|
||||||
subdivision_confidence = Column(SmallInteger,
|
subdivision_confidence = Column(SmallInteger,
|
||||||
|
@ -870,18 +1105,34 @@ class Live(JoinedWithOneDeviceMixin, EventWithOneDevice):
|
||||||
|
|
||||||
|
|
||||||
class Organize(JoinedTableMixin, EventWithMultipleDevices):
|
class Organize(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
pass
|
"""The act of manipulating/administering/supervising/controlling
|
||||||
|
one or more devices.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Reserve(Organize):
|
class Reserve(Organize):
|
||||||
pass
|
"""The act of reserving devices and cancelling them.
|
||||||
|
|
||||||
|
After this event is performed, the user is the **reservee** of the
|
||||||
|
devices. There can only be one non-cancelled reservation for
|
||||||
|
a device, and a reservation can only have one reservee.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class CancelReservation(Organize):
|
class CancelReservation(Organize):
|
||||||
pass
|
"""The act of cancelling a reservation."""
|
||||||
|
|
||||||
|
|
||||||
class Trade(JoinedTableMixin, EventWithMultipleDevices):
|
class Trade(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
|
"""Trade actions log the political exchange of devices between users.
|
||||||
|
Every time a trade event is performed, the old user looses its
|
||||||
|
political possession, for example ownership, in favor of another
|
||||||
|
user.
|
||||||
|
|
||||||
|
|
||||||
|
Performing trade events changes the *Trading* state of the
|
||||||
|
device —:class:`ereuse_devicehub.resources.device.states.Trading`.
|
||||||
|
"""
|
||||||
shipping_date = Column(DateTime)
|
shipping_date = Column(DateTime)
|
||||||
shipping_date.comment = """
|
shipping_date.comment = """
|
||||||
When are the devices going to be ready for shipping?
|
When are the devices going to be ready for shipping?
|
||||||
|
@ -924,36 +1175,67 @@ class Trade(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
|
|
||||||
|
|
||||||
class Sell(Trade):
|
class Sell(Trade):
|
||||||
pass
|
"""The act of taking money from a buyer in exchange of a device."""
|
||||||
|
|
||||||
|
|
||||||
class Donate(Trade):
|
class Donate(Trade):
|
||||||
pass
|
"""The act of giving devices without compensation."""
|
||||||
|
|
||||||
|
|
||||||
class Rent(Trade):
|
class Rent(Trade):
|
||||||
pass
|
"""The act of giving money in return for temporary use, but not
|
||||||
|
ownership, of a device.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class CancelTrade(Trade):
|
class CancelTrade(Trade):
|
||||||
pass
|
"""The act of cancelling a `Sell`_, `Donate`_ or `Rent`_."""
|
||||||
|
# todo cancelTrade does not do anything
|
||||||
|
|
||||||
|
|
||||||
class ToDisposeProduct(Trade):
|
class ToDisposeProduct(Trade):
|
||||||
pass
|
"""The act of setting a device for being disposed.
|
||||||
|
|
||||||
|
See :class:`.DisposeProduct`.
|
||||||
|
"""
|
||||||
|
# todo test this
|
||||||
|
|
||||||
|
|
||||||
class DisposeProduct(Trade):
|
class DisposeProduct(Trade):
|
||||||
pass
|
"""The act of getting rid of devices by giving (selling, donating)
|
||||||
|
to another organization, like a waste manager.
|
||||||
|
|
||||||
|
|
||||||
|
See :class:`.ToDispose` and :class:`.DisposeProduct` for
|
||||||
|
disposing without trading the device. See :class:`.DisposeWaste`
|
||||||
|
and :class:`.Recover` for disposing in-house, this is,
|
||||||
|
without trading the device.
|
||||||
|
"""
|
||||||
|
# todo For usability purposes, users might not directly perform
|
||||||
|
# *DisposeProduct*, but this could automatically be done when
|
||||||
|
# performing :class:`.ToDispose` + :class:`.Receive` to a
|
||||||
|
# ``RecyclingCenter``.
|
||||||
|
|
||||||
|
|
||||||
class Receive(JoinedTableMixin, EventWithMultipleDevices):
|
class Receive(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
|
"""The act of physically taking delivery of a device.
|
||||||
|
|
||||||
|
The receiver confirms that the devices have arrived, and thus,
|
||||||
|
they are the
|
||||||
|
:attr:`ereuse_devicehub.resources.device.models.Device.physical_possessor`.
|
||||||
|
|
||||||
|
The receiver can optionally take a
|
||||||
|
:class:`ereuse_devicehub.resources.enums.ReceiverRole`.
|
||||||
|
"""
|
||||||
role = Column(DBEnum(ReceiverRole),
|
role = Column(DBEnum(ReceiverRole),
|
||||||
nullable=False,
|
nullable=False,
|
||||||
default=ReceiverRole.Intermediary)
|
default=ReceiverRole.Intermediary)
|
||||||
|
|
||||||
|
|
||||||
class Migrate(JoinedTableMixin, EventWithMultipleDevices):
|
class Migrate(JoinedTableMixin, EventWithMultipleDevices):
|
||||||
|
"""Moves the devices to a new database/inventory. Devices cannot be
|
||||||
|
modified anymore at the previous database.
|
||||||
|
"""
|
||||||
other = Column(URL(), nullable=False)
|
other = Column(URL(), nullable=False)
|
||||||
other.comment = """
|
other.comment = """
|
||||||
The URL of the Migrate in the other end.
|
The URL of the Migrate in the other end.
|
||||||
|
|
|
@ -14,7 +14,7 @@ from teal.db import CASCADE_OWN, UUIDLtree
|
||||||
from teal.resource import url_for_resource
|
from teal.resource import url_for_resource
|
||||||
|
|
||||||
from ereuse_devicehub.db import create_view, db
|
from ereuse_devicehub.db import create_view, db
|
||||||
from ereuse_devicehub.resources.device.models import Component, Computer, Device
|
from ereuse_devicehub.resources.device.models import Component, Device
|
||||||
from ereuse_devicehub.resources.models import Thing
|
from ereuse_devicehub.resources.models import Thing
|
||||||
from ereuse_devicehub.resources.user.models import User
|
from ereuse_devicehub.resources.user.models import User
|
||||||
|
|
||||||
|
@ -90,16 +90,6 @@ class Lot(Thing):
|
||||||
_id = UUIDLtree.convert(id)
|
_id = UUIDLtree.convert(id)
|
||||||
return (cls.id == Path.lot_id) & Path.path.lquery(exp.cast('*.{}.*'.format(_id), LQUERY))
|
return (cls.id == Path.lot_id) & Path.path.lquery(exp.cast('*.{}.*'.format(_id), LQUERY))
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def device_in_lotq(cls):
|
|
||||||
parent = Computer.__table__.alias()
|
|
||||||
device_inside_lot = (Device.id == LotDevice.device_id) & (Lot.id == LotDevice.lot_id)
|
|
||||||
parent_device_in_lot = (Device.id == Component.id) \
|
|
||||||
& (Component.parent_id == parent.c.id) \
|
|
||||||
& (parent.c.id == LotDevice.device_id) \
|
|
||||||
& (Lot.id == LotDevice.lot_id)
|
|
||||||
return device_inside_lot | parent_device_in_lot
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parents(self):
|
def parents(self):
|
||||||
return self.parentsq(self.id)
|
return self.parentsq(self.id)
|
||||||
|
|
|
@ -209,7 +209,6 @@ def test_update_parent():
|
||||||
(models.Repair, states.Physical.Repaired),
|
(models.Repair, states.Physical.Repaired),
|
||||||
(models.ToPrepare, states.Physical.Preparing),
|
(models.ToPrepare, states.Physical.Preparing),
|
||||||
(models.ReadyToUse, states.Physical.ReadyToBeUsed),
|
(models.ReadyToUse, states.Physical.ReadyToBeUsed),
|
||||||
(models.ToPrepare, states.Physical.Preparing),
|
|
||||||
(models.Prepare, states.Physical.Prepared)
|
(models.Prepare, states.Physical.Prepared)
|
||||||
])
|
])
|
||||||
def test_generic_event(event_model_state: Tuple[models.Event, states.Trading], user: UserClient):
|
def test_generic_event(event_model_state: Tuple[models.Event, states.Trading], user: UserClient):
|
||||||
|
|
Reference in a new issue