This commit is contained in:
Cayo Puigdefabregas 2023-08-22 10:41:48 +02:00
parent 33fc69013f
commit 0fb4fa5ba6
9 changed files with 161 additions and 47 deletions

View file

@ -42,6 +42,7 @@ from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog
from ereuse_devicehub.parser.parser import ParseSnapshotLsHw from ereuse_devicehub.parser.parser import ParseSnapshotLsHw
from ereuse_devicehub.parser.schemas import Snapshot_lite from ereuse_devicehub.parser.schemas import Snapshot_lite
from ereuse_devicehub.resources.action.models import Snapshot, Trade from ereuse_devicehub.resources.action.models import Snapshot, Trade
from ereuse_devicehub.resources.action.schemas import EWaste as EWasteSchema
from ereuse_devicehub.resources.action.schemas import Snapshot as SnapshotSchema from ereuse_devicehub.resources.action.schemas import Snapshot as SnapshotSchema
from ereuse_devicehub.resources.action.views.snapshot import ( from ereuse_devicehub.resources.action.views.snapshot import (
SnapshotMixin, SnapshotMixin,
@ -856,6 +857,12 @@ class ActionFormMixin(FlaskForm):
self.populate_obj(self.instance) self.populate_obj(self.instance)
db.session.add(self.instance) db.session.add(self.instance)
if self.instance.type == 'EWaste':
ewaste = EWasteSchema().dump(self.instance)
doc = "{}".format(ewaste)
self.instance.register_proof(doc)
db.session.commit() db.session.commit()
self.devices.data = devices self.devices.data = devices
@ -1212,7 +1219,6 @@ class TradeForm(ActionFormMixin):
or email_to == email_from or email_to == email_from
or g.user.email not in [email_from, email_to] or g.user.email not in [email_from, email_to]
): ):
errors = ["If you want confirm, you need a correct email"] errors = ["If you want confirm, you need a correct email"]
self.user_to.errors = errors self.user_to.errors = errors
self.user_from.errors = errors self.user_from.errors = errors
@ -1918,7 +1924,6 @@ class UploadPlaceholderForm(FlaskForm):
return True return True
def save(self, commit=True): def save(self, commit=True):
for device, placeholder_log in self.placeholders: for device, placeholder_log in self.placeholders:
db.session.add(device) db.session.add(device)
db.session.add(placeholder_log) db.session.add(placeholder_log)
@ -1947,7 +1952,6 @@ class EditPlaceholderForm(FlaskForm):
return True return True
def save(self, commit=True): def save(self, commit=True):
for device in self.placeholders: for device in self.placeholders:
db.session.add(device) db.session.add(device)

View file

@ -45,13 +45,14 @@ def upgrade():
sa.Column('type', sa.Unicode(), nullable=False), sa.Column('type', sa.Unicode(), nullable=False),
sa.Column('documentId', citext.CIText(), nullable=True), sa.Column('documentId', citext.CIText(), nullable=True),
sa.Column('documentSignature', citext.CIText(), nullable=True), sa.Column('documentSignature', citext.CIText(), nullable=True),
sa.Column('normalizeDoc', citext.CIText(), nullable=True),
sa.Column('timestamp', sa.BigInteger(), nullable=False), sa.Column('timestamp', sa.BigInteger(), nullable=False),
sa.Column('device_id', sa.BigInteger(), nullable=False), sa.Column('device_id', sa.BigInteger(), nullable=False),
sa.Column('snapshot_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('action_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('issuer_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('issuer_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
['snapshot_id'], ['action_id'],
[f'{get_inv()}.snapshot.id'], [f'{get_inv()}.action.id'],
), ),
sa.ForeignKeyConstraint( sa.ForeignKeyConstraint(
['device_id'], ['device_id'],

View file

@ -6,7 +6,7 @@ from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import backref, relationship from sqlalchemy.orm import backref, relationship
from sqlalchemy.util import OrderedSet from sqlalchemy.util import OrderedSet
from ereuse_devicehub.resources.action.models import Snapshot from ereuse_devicehub.resources.action.models import Action, Snapshot
from ereuse_devicehub.resources.device.models import Device from ereuse_devicehub.resources.device.models import Device
from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing
from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.user.models import User
@ -17,6 +17,7 @@ PROOF_ENUM = {
'IssueDPP': 'IssueDPP', 'IssueDPP': 'IssueDPP',
'proof_of_recycling': 'proof_of_recycling', 'proof_of_recycling': 'proof_of_recycling',
'Erase': 'Erase', 'Erase': 'Erase',
'EWaste': 'EWaste',
} }
_sorted_proofs = {'order_by': lambda: Proof.created, 'collection_class': SortedSet} _sorted_proofs = {'order_by': lambda: Proof.created, 'collection_class': SortedSet}
@ -30,6 +31,7 @@ class Proof(Thing):
documentId.comment = "is the uuid of snapshot" documentId.comment = "is the uuid of snapshot"
documentSignature = Column(CIText(), nullable=True) documentSignature = Column(CIText(), nullable=True)
documentSignature.comment = "is the snapshot.json_hw with the signature of the user" documentSignature.comment = "is the snapshot.json_hw with the signature of the user"
normalizeDoc = Column(CIText(), nullable=True)
timestamp = Column(BigInteger, nullable=False) timestamp = Column(BigInteger, nullable=False)
type = Column(Unicode(STR_SM_SIZE), nullable=False) type = Column(Unicode(STR_SM_SIZE), nullable=False)
@ -52,12 +54,12 @@ class Proof(Thing):
primaryjoin=Device.id == device_id, primaryjoin=Device.id == device_id,
) )
snapshot_id = Column(UUID(as_uuid=True), ForeignKey(Snapshot.id), nullable=True) action_id = Column(UUID(as_uuid=True), ForeignKey(Action.id), nullable=True)
snapshot = relationship( action = relationship(
Snapshot, Action,
backref=backref('proofs', lazy=True), backref=backref('proofs', lazy=True),
collection_class=OrderedSet, collection_class=OrderedSet,
primaryjoin=Snapshot.id == snapshot_id, primaryjoin=Action.id == action_id,
) )

View file

@ -216,6 +216,11 @@ class ReadyDef(ActionDef):
SCHEMA = schemas.Ready SCHEMA = schemas.Ready
class EWasteDef(ActionDef):
VIEW = None
SCHEMA = schemas.EWaste
class RecyclingDef(ActionDef): class RecyclingDef(ActionDef):
VIEW = None VIEW = None
SCHEMA = schemas.Recycling SCHEMA = schemas.Recycling

View file

@ -493,9 +493,7 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice):
return self.parent.phid() return self.parent.phid()
return '' return ''
def register_proof(self): def connect_api(self):
"""This method is used for register a proof of erasure en dlt."""
if 'dpp' not in app.blueprints.keys() or not self.snapshot: if 'dpp' not in app.blueprints.keys() or not self.snapshot:
return return
@ -504,21 +502,25 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice):
token_dlt = session.get('token_dlt') token_dlt = session.get('token_dlt')
api_dlt = app.config.get('API_DLT') api_dlt = app.config.get('API_DLT')
dh_instance = app.config.get('ID_FEDERATED', 'dh1')
if not token_dlt or not api_dlt: if not token_dlt or not api_dlt:
return return
api = API(api_dlt, token_dlt, "ethereum") return API(api_dlt, token_dlt, "ethereum")
from ereuse_devicehub.modules.dpp.models import PROOF_ENUM, Proof def register_proof(self):
"""This method is used for register a proof of erasure en dlt."""
from ereuse_devicehub.modules.dpp.models import PROOF_ENUM
deviceCHID = self.device.chid deviceCHID = self.device.chid
docSig = self.snapshot.phid_dpp docHash = self.snapshot.phid_dpp
docHash = docSig
docHashAlgorithm = 'sha3_256' docHashAlgorithm = 'sha3_256'
docID = "{}".format(self.snapshot.uuid or '')
issuerID = "{dh}:{user}".format(dh=dh_instance, user=g.user.id)
proof_type = PROOF_ENUM['Erase'] proof_type = PROOF_ENUM['Erase']
dh_instance = app.config.get('ID_FEDERATED', 'dh1')
api = self.connect_api()
if not api:
return
result = api.generate_proof( result = api.generate_proof(
deviceCHID, deviceCHID,
docHashAlgorithm, docHashAlgorithm,
@ -527,16 +529,21 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice):
dh_instance, dh_instance,
) )
self.register_erase_proof(result)
def register_erase_proof(self, result):
from ereuse_devicehub.modules.dpp.models import PROOF_ENUM, Proof
from ereuse_devicehub.resources.enums import StatusCode from ereuse_devicehub.resources.enums import StatusCode
if result['Status'] == StatusCode.Success.value: if result['Status'] == StatusCode.Success.value:
timestamp = ( timestamp = result.get('Data', {}).get('data', {}).get('timestamp')
result.get('Data', {}).get('data', {}).get('timestamp', time.time()) if not timestamp:
) return
d = { d = {
"type": PROOF_ENUM['Erase'], "type": PROOF_ENUM['Erase'],
"device": self.device, "device": self.device,
"snapshot": self.snapshot, "action": self.snapshot,
"timestamp": timestamp, "timestamp": timestamp,
"issuer_id": g.user.id, "issuer_id": g.user.id,
} }
@ -874,7 +881,6 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice):
return hdds return hdds
def get_new_device(self): def get_new_device(self):
if not self.device: if not self.device:
return '' return ''
@ -983,7 +989,7 @@ class BenchmarkDataStorage(Benchmark):
write_speed = Column(Float(decimal_return_scale=2), nullable=False) write_speed = Column(Float(decimal_return_scale=2), nullable=False)
def __str__(self) -> str: def __str__(self) -> str:
return 'Read: {0:.2f} MB/s, write: {0:.2f} MB/s'.format( return 'Read: {0:.2f} MB/s, write: {0:.2f} MB/s'.format( # noqa: F523
self.read_speed, self.write_speed self.read_speed, self.write_speed
) )
@ -1711,6 +1717,72 @@ class Ready(ActionWithMultipleDevices):
""" """
class EWaste(ActionWithMultipleDevices):
"""The device is declared as e-waste, this device is not allow use more.
Any people can declared as e-waste one device.
"""
def register_proof(self, doc):
"""This method is used for register a proof of erasure en dlt."""
if 'dpp' not in app.blueprints.keys():
return
if not session.get('token_dlt'):
return
if not doc:
return
self.doc = doc
token_dlt = session.get('token_dlt')
api_dlt = app.config.get('API_DLT')
dh_instance = app.config.get('ID_FEDERATED', 'dh1')
if not token_dlt or not api_dlt:
return
api = API(api_dlt, token_dlt, "ethereum")
from ereuse_devicehub.modules.dpp.models import PROOF_ENUM, Proof
from ereuse_devicehub.resources.enums import StatusCode
for device in self.devices:
deviceCHID = device.chid
docHash = self.generateDocSig()
docHashAlgorithm = 'sha3_256'
proof_type = PROOF_ENUM['EWaste']
result = api.generate_proof(
deviceCHID,
docHashAlgorithm,
docHash,
proof_type,
dh_instance,
)
if result['Status'] == StatusCode.Success.value:
timestamp = result.get('Data', {}).get('data', {}).get('timestamp')
if not timestamp:
return
d = {
"type": PROOF_ENUM['EWaste'],
"device": device,
"action": self,
"timestamp": timestamp,
"issuer_id": g.user.id,
"normalizeDoc": self.doc,
}
proof = Proof(**d)
db.session.add(proof)
def generateDocSig(self):
if not self.doc:
return
return hashlib.sha3_256(self.doc.encode('utf-8')).hexdigest()
class ToPrepare(ActionWithMultipleDevices): class ToPrepare(ActionWithMultipleDevices):
"""The device has been selected for preparation. """The device has been selected for preparation.

View file

@ -523,6 +523,10 @@ class Ready(ActionWithMultipleDevicesCheckingOwner):
__doc__ = m.Ready.__doc__ __doc__ = m.Ready.__doc__
class EWaste(ActionWithMultipleDevicesCheckingOwner):
__doc__ = m.EWaste.__doc__
class ActionStatus(Action): class ActionStatus(Action):
rol_user = NestedOn(s_user.User, dump_only=True, exclude=('token',)) rol_user = NestedOn(s_user.User, dump_only=True, exclude=('token',))
devices = NestedOn( devices = NestedOn(

View file

@ -4,7 +4,6 @@ import json
import logging import logging
import os import os
import pathlib import pathlib
import time
import uuid import uuid
from contextlib import suppress from contextlib import suppress
from fractions import Fraction from fractions import Fraction
@ -484,7 +483,8 @@ class Device(Thing):
"""The trading state, or None if no Trade action has """The trading state, or None if no Trade action has
ever been performed to this device. This extract the posibilities for to do. ever been performed to this device. This extract the posibilities for to do.
This method is performed for show in the web. This method is performed for show in the web.
If you need to do one simple and generic response you can put simple=True for that.""" If you need to do one simple and generic response you can put simple=True for that.
"""
if not hasattr(lot, 'trade'): if not hasattr(lot, 'trade'):
return return
@ -939,7 +939,7 @@ class Device(Thing):
} }
return types.get(self.type, '') return types.get(self.type, '')
def register_dlt(self): def connect_api(self):
if 'dpp' not in app.blueprints.keys() or not self.hid: if 'dpp' not in app.blueprints.keys() or not self.hid:
return return
@ -951,20 +951,43 @@ class Device(Thing):
if not token_dlt or not api_dlt: if not token_dlt or not api_dlt:
return return
api = API(api_dlt, token_dlt, "ethereum") return API(api_dlt, token_dlt, "ethereum")
def register_dlt(self):
api = self.connect_api()
if not api:
return
result = api.register_device(self.chid) result = api.register_device(self.chid)
self.register_proof(result)
if app.config.get('ID_FEDERATED'):
api.add_service(
self.chid,
'DeviceHub',
app.config.get('ID_FEDERATED'),
'Inventory service',
'Inv',
)
def register_proof(self, result):
from ereuse_devicehub.modules.dpp.models import PROOF_ENUM, Proof from ereuse_devicehub.modules.dpp.models import PROOF_ENUM, Proof
from ereuse_devicehub.resources.enums import StatusCode from ereuse_devicehub.resources.enums import StatusCode
if result['Status'] == StatusCode.Success.value: if result['Status'] == StatusCode.Success.value:
timestamp = ( timestamp = result.get('Data', {}).get('data', {}).get('timestamp')
result.get('Data', {}).get('data', {}).get('timestamp', time.time())
) if not timestamp:
return
snapshot = [x for x in self.actions if x.t == 'Snapshot']
if not snapshot:
return
d = { d = {
"type": PROOF_ENUM['Register'], "type": PROOF_ENUM['Register'],
"device": self, "device": self,
"snapshot": [x for x in self.actions if x.t == 'Snapshot'][0], "actions": snapshot[0],
"timestamp": timestamp, "timestamp": timestamp,
"issuer_id": g.user.id, "issuer_id": g.user.id,
} }
@ -978,15 +1001,6 @@ class Device(Thing):
if isinstance(c, DataStorage): if isinstance(c, DataStorage):
c.register_dlt() c.register_dlt()
if app.config.get('ID_FEDERATED'):
api.add_service(
self.chid,
'DeviceHub',
app.config.get('ID_FEDERATED'),
'Inventory service',
'Inv',
)
def unreliable(self): def unreliable(self):
self.user_trusts = False self.user_trusts = False
i = 0 i = 0
@ -1302,6 +1316,14 @@ class Placeholder(Thing):
return docs.union(self.binding.documents) return docs.union(self.binding.documents)
return docs return docs
@property
def proofs(self):
proofs = [p for p in self.device.proofs]
if self.binding:
proofs.extend([p for p in self.binding.proofs])
proofs.sort(key=lambda x: x.created, reverse=True)
return proofs
class Computer(Device): class Computer(Device):
"""A chassis with components inside that can be processed """A chassis with components inside that can be processed

View file

@ -390,10 +390,9 @@
</div> </div>
{% endif %} {% endif %}
{% if placeholder.binding %}
<div class="tab-pane fade profile-overview" id="proofs"> <div class="tab-pane fade profile-overview" id="proofs">
<h5 class="card-title">Proofs</h5> <h5 class="card-title">Proofs</h5>
{% for proof in placeholder.binding.proofs %} {% for proof in placeholder.proofs %}
<div class="list-group col-12"> <div class="list-group col-12">
<div class="list-group-item d-flex justify-content-between align-items-center"> <div class="list-group-item d-flex justify-content-between align-items-center">
<div class="row"> <div class="row">
@ -436,7 +435,6 @@
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
</div> </div>
{% endif %}
</div> </div>
</div> </div>

View file

@ -226,6 +226,12 @@
Ready Ready
</a> </a>
</li> </li>
<li>
<a href="javascript:newAction('EWaste')" class="dropdown-item">
<i class="bi bi-trash-fill"></i>
E-Waste
</a>
</li>
</ul> </ul>
</div> </div>