diff --git a/README.md b/README.md
index b4293312..53164936 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,9 @@ call the new file ``app.py``.
Create a PostgreSQL database called *devicehub* by running
[create-db](examples/create-db.sh):
-- In Debian 9: `sudo su - postgres; examples/create-db.sh devicehub`
+- In a Debian 9 terminal, execute the following two commands:
+ 1. `sudo su - postgres`.
+ 2. `bash examples/create-db.sh devicehub`.
- In MacOS: `examples/create-db.sh devicehub`.
Create the tables in the database by executing in the same directory
diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py
index 5aba1421..1b59aa05 100644
--- a/ereuse_devicehub/dummy/dummy.py
+++ b/ereuse_devicehub/dummy/dummy.py
@@ -58,16 +58,28 @@ class Dummy:
'-o', org_id
],
catch_exceptions=False)
+ # create tag for pc-laudem
+ runner.invoke(args=[
+ 'create-tag', 'tagA',
+ '-p', 'https://t.devicetag.io',
+ '-s', 'tagA-secondary'
+ ],
+ catch_exceptions=False)
files = tuple(Path(__file__).parent.joinpath('files').iterdir())
print('done.')
+ sample_pc = None # We treat this one as a special sample for demonstrations
pcs = set() # type: Set[int]
with click.progressbar(files, label='Creating devices...'.ljust(28)) as bar:
for path in bar:
with path.open() as f:
snapshot = yaml.load(f)
s, _ = user.post(res=m.Snapshot, data=snapshot)
- pcs.add(s['device']['id'])
-
+ if s.get('uuid', None) == 'ec23c11b-80b6-42cd-ac5c-73ba7acddbc4':
+ sample_pc = s['device']['id']
+ else:
+ pcs.add(s['device']['id'])
+ assert sample_pc
+ print('PC sample is', sample_pc)
# Link tags and eTags
for tag, pc in zip((self.TAGS[1], self.TAGS[2], self.ET[0][0], self.ET[1][1]), pcs):
user.put({}, res=Tag, item='{}/device/{}'.format(tag, pc), status=204)
@@ -105,9 +117,29 @@ class Dummy:
assert len(inventory['items'])
i, _ = user.get(res=Device, query=[('search', 'intel')])
- assert len(i['items']) == 10
- i, _ = user.get(res=Device, query=[('search', 'pc')])
assert len(i['items']) == 11
+ i, _ = user.get(res=Device, query=[('search', 'pc')])
+ assert len(i['items']) == 12
+
+ # Let's create a set of events for the pc device
+ # Make device Ready
+
+ user.post({'type': m.ToPrepare.t, 'devices': [sample_pc]}, res=m.Event)
+ user.post({'type': m.Prepare.t, 'devices': [sample_pc]}, res=m.Event)
+ user.post({'type': m.ReadyToUse.t, 'devices': [sample_pc]}, res=m.Event)
+ user.post({'type': m.Price.t, 'device': sample_pc, 'currency': 'EUR', 'price': 85},
+ res=m.Event)
+ # todo test reserve
+ user.post( # Sell device
+ {
+ 'type': m.Sell.t,
+ 'to': user.user['individuals'][0]['id'],
+ 'devices': [sample_pc]
+ },
+ res=m.Event)
+ # todo Receive
+
+ # For netbook: to preapre -> torepair -> to dispose -> disposed
print('⭐ Done.')
def user_client(self, email: str, password: str):
diff --git a/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml b/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml
new file mode 100644
index 00000000..cf2c6749
--- /dev/null
+++ b/ereuse_devicehub/dummy/files/pc-laudem.snapshot.11.yaml
@@ -0,0 +1,146 @@
+{
+ "closed": true,
+ "components": [
+ {
+ "events": [],
+ "manufacturer": "Intel Corporation",
+ "model": "82567LM-3 Gigabit Network Connection",
+ "serialNumber": "00:23:7d:49:5e:31",
+ "speed": 1000,
+ "type": "NetworkAdapter",
+ "wireless": false
+ },
+ {
+ "events": [],
+ "manufacturer": "Intel Corporation",
+ "model": "82801JD/DO HD Audio Controller",
+ "serialNumber": null,
+ "type": "SoundCard"
+ },
+ {
+ "events": [],
+ "format": "DIMM",
+ "interface": "DDR2",
+ "manufacturer": null,
+ "model": "HYMP125U64CP8-S6",
+ "serialNumber": null,
+ "size": 2048,
+ "speed": 800.0,
+ "type": "RamModule"
+ },
+ {
+ "address": 64,
+ "cores": 2,
+ "events": [
+ {
+ "elapsed": 0,
+ "rate": 11970.54,
+ "type": "BenchmarkProcessor"
+ },
+ {
+ "elapsed": 20,
+ "rate": 19.6233,
+ "type": "BenchmarkProcessorSysbench"
+ }
+ ],
+ "manufacturer": "Intel Corp.",
+ "model": "Intel Core2 Duo CPU E8400 @ 3.00GHz",
+ "serialNumber": null,
+ "speed": 3.0,
+ "threads": 2,
+ "type": "Processor"
+ },
+ {
+ "events": [
+ {
+ "elapsed": 16,
+ "readSpeed": 76.8,
+ "type": "BenchmarkDataStorage",
+ "writeSpeed": 21.1
+ },
+ {
+ "assessment": true,
+ "currentPendingSectorCount": 0,
+ "elapsed": 134,
+ "error": false,
+ "length": "Short",
+ "lifetime": 19549,
+ "offlineUncorrectable": 0,
+ "powerCycleCount": 3354,
+ "reallocatedSectorCount": 33,
+ "reportedUncorrectableErrors": 0,
+ "status": "Completed without error",
+ "type": "TestDataStorage"
+ }
+ ],
+ "interface": "ATA",
+ "manufacturer": "Seagate",
+ "model": "ST3160815AS",
+ "serialNumber": "6RX7AWEZ",
+ "size": 152627,
+ "type": "HardDrive"
+ },
+ {
+ "events": [],
+ "manufacturer": "Intel Corporation",
+ "memory": 256.0,
+ "model": "4 Series Chipset Integrated Graphics Controller",
+ "serialNumber": null,
+ "type": "GraphicCard"
+ },
+ {
+ "events": [],
+ "firewire": 0,
+ "manufacturer": "Hewlett-Packard",
+ "model": "3031h",
+ "pcmcia": 0,
+ "serial": 0,
+ "serialNumber": "CZC901381R",
+ "slots": 0,
+ "type": "Motherboard",
+ "usb": 8
+ }
+ ],
+ "device": {
+ "chassis": "Tower",
+ "events": [
+ {
+ "elapsed": 60,
+ "error": false,
+ "type": "StressTest"
+ },
+ {
+ "elapsed": 6,
+ "rate": 5.7674,
+ "type": "BenchmarkRamSysbench"
+ },
+ {
+ "appearanceRange": "A",
+ "biosRange": "A",
+ "functionalityRange": "A",
+ "type": "WorkbenchRate"
+ }
+ ],
+ "manufacturer": "Hewlett-Packard",
+ "model": "HP Compaq dc7900 Small Form Factor",
+ "serialNumber": "CZC901381R",
+ "tags": [
+ {
+ "id": "tagA-secondary",
+ "type": "Tag"
+ }
+ ],
+ "type": "Desktop"
+ },
+ "elapsed": 238,
+ "endTime": "2018-10-15T13:59:37.431309+00:00",
+ "expectedEvents": [
+ "Benchmark",
+ "TestDataStorage",
+ "StressTest"
+ ],
+ "software": "Workbench",
+ "type": "Snapshot",
+ "uuid": "ec23c11b-80b6-42cd-ac5c-73ba7acddbc4",
+ "version": "11.0a6"
+}
diff --git a/ereuse_devicehub/resources/device/definitions.py b/ereuse_devicehub/resources/device/definitions.py
index e888c988..b0224bc3 100644
--- a/ereuse_devicehub/resources/device/definitions.py
+++ b/ereuse_devicehub/resources/device/definitions.py
@@ -14,7 +14,8 @@ class DeviceDef(Resource):
AUTH = False # We manage this at each view
def __init__(self, app,
- import_name=__name__, static_folder=None,
+ import_name=__name__,
+ static_folder='static',
static_url_path=None,
template_folder='templates',
url_prefix=None,
@@ -30,6 +31,12 @@ class ComputerDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Computer
+ 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 DesktopDef(ComputerDef):
VIEW = None
@@ -50,6 +57,12 @@ class MonitorDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Monitor
+ 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 ComputerMonitorDef(MonitorDef):
VIEW = None
@@ -65,6 +78,12 @@ class MobileDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Mobile
+ 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 SmartphoneDef(MobileDef):
VIEW = None
@@ -85,6 +104,12 @@ class ComponentDef(DeviceDef):
VIEW = None
SCHEMA = schemas.Component
+ 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 GraphicCardDef(ComponentDef):
VIEW = None
diff --git a/ereuse_devicehub/resources/device/static/ereuse-logo.svg b/ereuse_devicehub/resources/device/static/ereuse-logo.svg
new file mode 100644
index 00000000..9c9608ab
--- /dev/null
+++ b/ereuse_devicehub/resources/device/static/ereuse-logo.svg
@@ -0,0 +1,3 @@
+
+
diff --git a/ereuse_devicehub/resources/device/static/photochromic-alone.svg b/ereuse_devicehub/resources/device/static/photochromic-alone.svg
new file mode 100644
index 00000000..95cf4353
--- /dev/null
+++ b/ereuse_devicehub/resources/device/static/photochromic-alone.svg
@@ -0,0 +1,3 @@
+
+
diff --git a/ereuse_devicehub/resources/device/static/photochromic-tag-web.svg b/ereuse_devicehub/resources/device/static/photochromic-tag-web.svg
new file mode 100644
index 00000000..82ffafca
--- /dev/null
+++ b/ereuse_devicehub/resources/device/static/photochromic-tag-web.svg
@@ -0,0 +1,3 @@
+
+
diff --git a/ereuse_devicehub/resources/device/templates/devices/layout.html b/ereuse_devicehub/resources/device/templates/devices/layout.html
index ef1fa6fb..30f89024 100644
--- a/ereuse_devicehub/resources/device/templates/devices/layout.html
+++ b/ereuse_devicehub/resources/device/templates/devices/layout.html
@@ -13,85 +13,205 @@
+
+ This is your {{ device.t }}.
+
+
-
-
-
- |
- Range |
-
-
-
-
-
-
- CPU – {{ device.processor_model }}
- {{ macros.component_type(device.components, 'Processor') }}
-
- |
- |
-
-
-
-
- RAM – {{ device.ram_size // 1000 }} GB
- {{ macros.component_type(device.components, 'RamModule') }}
-
- |
- //range// |
-
-
-
-
- Data Storage – {{ device.data_storage_size // 1000 }} GB
- {{ macros.component_type(device.components, 'SolidStateDrive') }}
- {{ macros.component_type(device.components, 'HardDrive') }}
-
- |
- //range// |
-
-
-
-
- Graphics – {{ device.graphic_card_model }}
- {{ macros.component_type(device.components, 'GraphicCard') }}
-
- |
- //range// |
-
-
-
-
- Network –
- {% if device.network_speeds[0] %}
- Ethernet of {{ device.network_speeds[0] }} Mbps
- {% endif %}
- {% if device.network_speeds[0] and device.network_speeds[1] %}
- +
- {% endif %}
- {% if device.network_speeds[1] %}
- WiFi of {{ device.network_speeds[1] }} Mbps
- {% endif %}
-
- {{ macros.component_type(device.components, 'NetworkAdapter') }}
-
- |
- |
-
-
-
+ You can verify the originality of your device.
+
+ If your device comes with the following tag
+
+
+
+ It means it has been refurbished by an eReuse.org
+ certificated organization.
+
+
+ The tag is special –illuminate it with the torch of
+ your phone for 6 seconds and it will react like in
+ the following image:
+
+
-
-
+
+ These are the specifications
+
+ -
+
+ {% if device.trading %}
+ -
+ {{ device.trading.name }}
+
+ {% endif %}
+ {% if device.physical %}
+ -
+ {{ device.physical.name }}
+
+ {% endif %}
+
+
+ {% if device.physical_possessor %}
+ -
+ Physical possessor:
+ {{ device.physical_possessor.name }},
+ {{ device.physical_possessor.country.value }}
+
+ {% endif %}
+
+
+
+
+
+ |
+ Range |
+
+
+
+ {% if device.processor_model %}
+
+
+
+ CPU – {{ device.processor_model }}
+ {{ macros.component_type(device.components, 'Processor') }}
+
+ |
+ {{ device.rate.processor_range if device.rate }} |
+
+ {% endif %}
+ {% if device.ram_size %}
+
+
+
+ RAM – {{ device.ram_size // 1000 }} GB
+ {{ macros.component_type(device.components, 'RamModule') }}
+
+ |
+ {{ device.rate.ram_range if device.rate }} |
+
+ {% endif %}
+ {% if device.data_storage_size %}
+
+
+
+ Data Storage – {{ device.data_storage_size // 1000 }} GB
+
+ {{ macros.component_type(device.components, 'SolidStateDrive') }}
+ {{ macros.component_type(device.components, 'HardDrive') }}
+
+ |
+ {{ device.rate.data_storage_range if device.rate }} |
+
+ {% endif %}
+ {% if device.graphic_card_model %}
+
+
+
+ Graphics – {{ device.graphic_card_model }}
+ {{ macros.component_type(device.components, 'GraphicCard') }}
+
+ |
+ |
+
+ {% endif %}
+ {% if device.network_speeds %}
+
+
+
+ Network –
+ {% if device.network_speeds[0] %}
+ Ethernet
+ {% if device.network_speeds[0] != None %}
+ max. {{ device.network_speeds[0] }} Mbps
+ {% endif %}
+ {% endif %}
+ {% if device.network_speeds[0] and device.network_speeds[1] %}
+ +
+ {% endif %}
+ {% if device.network_speeds[1] %}
+ WiFi
+ {% if device.network_speeds[1] != None %}
+ max. {{ device.network_speeds[1] }} Mbps
+ {% endif %}
+ {% endif %}
+
+ {{ macros.component_type(device.components, 'NetworkAdapter') }}
+
+ |
+ |
+
+ {% endif %}
+ {% if device.rate %}
+
+
+ Total rate
+ |
+
+ {{ device.rate.rating_range }}
+ |
+
+ {% endif %}
+ {% if device.rate and device.rate.price %}
+
+
+ Algorithm price
+ |
+
+ {{ device.rate.price }}
+ |
+
+ {% endif %}
+ {% if device.price %}
+
+
+ Actual price
+ |
+
+ {{ device.price }}
+ |
+
+ {% endif %}
+
+
+
+ This is the traceability log of your device
+
+ Oldest one.
+
+
+
+ {% for event in device.events %}
+ -
+
+ {{ event.type }}
+
+ —
+ {{ event }}
+
+
+
+ {{ event._date_str }}
+
+
+
+
+ {% endfor %}
+
+
+ Latest one.
+
+
+
+