diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index b4577260..e2741841 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -42,6 +42,7 @@ from ereuse_devicehub.parser.models import PlaceholdersLog, SnapshotsLog from ereuse_devicehub.parser.parser import ParseSnapshotLsHw from ereuse_devicehub.parser.schemas import Snapshot_lite 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.views.snapshot import ( SnapshotMixin, @@ -856,6 +857,12 @@ class ActionFormMixin(FlaskForm): self.populate_obj(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() self.devices.data = devices @@ -1212,7 +1219,6 @@ class TradeForm(ActionFormMixin): or email_to == email_from or g.user.email not in [email_from, email_to] ): - errors = ["If you want confirm, you need a correct email"] self.user_to.errors = errors self.user_from.errors = errors @@ -1918,7 +1924,6 @@ class UploadPlaceholderForm(FlaskForm): return True def save(self, commit=True): - for device, placeholder_log in self.placeholders: db.session.add(device) db.session.add(placeholder_log) @@ -1947,7 +1952,6 @@ class EditPlaceholderForm(FlaskForm): return True def save(self, commit=True): - for device in self.placeholders: db.session.add(device) diff --git a/ereuse_devicehub/modules/dpp/migrations/versions/8334535d56fa_add_digital_passport_dpp.py b/ereuse_devicehub/modules/dpp/migrations/versions/8334535d56fa_add_digital_passport_dpp.py index 97cfe6ba..2dc18860 100644 --- a/ereuse_devicehub/modules/dpp/migrations/versions/8334535d56fa_add_digital_passport_dpp.py +++ b/ereuse_devicehub/modules/dpp/migrations/versions/8334535d56fa_add_digital_passport_dpp.py @@ -45,13 +45,14 @@ def upgrade(): sa.Column('type', sa.Unicode(), nullable=False), sa.Column('documentId', 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('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.ForeignKeyConstraint( - ['snapshot_id'], - [f'{get_inv()}.snapshot.id'], + ['action_id'], + [f'{get_inv()}.action.id'], ), sa.ForeignKeyConstraint( ['device_id'], diff --git a/ereuse_devicehub/modules/dpp/models.py b/ereuse_devicehub/modules/dpp/models.py index 038abcfc..2d2fc303 100644 --- a/ereuse_devicehub/modules/dpp/models.py +++ b/ereuse_devicehub/modules/dpp/models.py @@ -6,7 +6,7 @@ from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import backref, relationship 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.models import STR_SM_SIZE, Thing from ereuse_devicehub.resources.user.models import User @@ -17,6 +17,7 @@ PROOF_ENUM = { 'IssueDPP': 'IssueDPP', 'proof_of_recycling': 'proof_of_recycling', 'Erase': 'Erase', + 'EWaste': 'EWaste', } _sorted_proofs = {'order_by': lambda: Proof.created, 'collection_class': SortedSet} @@ -30,6 +31,7 @@ class Proof(Thing): documentId.comment = "is the uuid of snapshot" documentSignature = Column(CIText(), nullable=True) documentSignature.comment = "is the snapshot.json_hw with the signature of the user" + normalizeDoc = Column(CIText(), nullable=True) timestamp = Column(BigInteger, nullable=False) type = Column(Unicode(STR_SM_SIZE), nullable=False) @@ -52,12 +54,12 @@ class Proof(Thing): primaryjoin=Device.id == device_id, ) - snapshot_id = Column(UUID(as_uuid=True), ForeignKey(Snapshot.id), nullable=True) - snapshot = relationship( - Snapshot, + action_id = Column(UUID(as_uuid=True), ForeignKey(Action.id), nullable=True) + action = relationship( + Action, backref=backref('proofs', lazy=True), collection_class=OrderedSet, - primaryjoin=Snapshot.id == snapshot_id, + primaryjoin=Action.id == action_id, ) diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 9f83ad1d..4deb17c6 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -216,6 +216,11 @@ class ReadyDef(ActionDef): SCHEMA = schemas.Ready +class EWasteDef(ActionDef): + VIEW = None + SCHEMA = schemas.EWaste + + class RecyclingDef(ActionDef): VIEW = None SCHEMA = schemas.Recycling diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index d4505da8..35daaa34 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -493,9 +493,7 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): return self.parent.phid() return '' - def register_proof(self): - """This method is used for register a proof of erasure en dlt.""" - + def connect_api(self): if 'dpp' not in app.blueprints.keys() or not self.snapshot: return @@ -504,21 +502,25 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): 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") + 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 - docSig = self.snapshot.phid_dpp - docHash = docSig + docHash = self.snapshot.phid_dpp 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'] + dh_instance = app.config.get('ID_FEDERATED', 'dh1') + + api = self.connect_api() + if not api: + return + result = api.generate_proof( deviceCHID, docHashAlgorithm, @@ -527,16 +529,21 @@ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): 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 if result['Status'] == StatusCode.Success.value: - timestamp = ( - result.get('Data', {}).get('data', {}).get('timestamp', time.time()) - ) + timestamp = result.get('Data', {}).get('data', {}).get('timestamp') + if not timestamp: + return + d = { "type": PROOF_ENUM['Erase'], "device": self.device, - "snapshot": self.snapshot, + "action": self.snapshot, "timestamp": timestamp, "issuer_id": g.user.id, } @@ -874,7 +881,6 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice): return hdds def get_new_device(self): - if not self.device: return '' @@ -983,7 +989,7 @@ class BenchmarkDataStorage(Benchmark): write_speed = Column(Float(decimal_return_scale=2), nullable=False) 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 ) @@ -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): """The device has been selected for preparation. diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 4760edf6..12063755 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -523,6 +523,10 @@ class Ready(ActionWithMultipleDevicesCheckingOwner): __doc__ = m.Ready.__doc__ +class EWaste(ActionWithMultipleDevicesCheckingOwner): + __doc__ = m.EWaste.__doc__ + + class ActionStatus(Action): rol_user = NestedOn(s_user.User, dump_only=True, exclude=('token',)) devices = NestedOn( diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 6e37f628..31b22042 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -4,7 +4,6 @@ import json import logging import os import pathlib -import time import uuid from contextlib import suppress from fractions import Fraction @@ -484,7 +483,8 @@ class Device(Thing): """The trading state, or None if no Trade action has ever been performed to this device. This extract the posibilities for to do. 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'): return @@ -939,7 +939,7 @@ class Device(Thing): } return types.get(self.type, '') - def register_dlt(self): + def connect_api(self): if 'dpp' not in app.blueprints.keys() or not self.hid: return @@ -951,20 +951,43 @@ class Device(Thing): if not token_dlt or not api_dlt: 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) + 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.resources.enums import StatusCode if result['Status'] == StatusCode.Success.value: - timestamp = ( - result.get('Data', {}).get('data', {}).get('timestamp', time.time()) - ) + timestamp = result.get('Data', {}).get('data', {}).get('timestamp') + + if not timestamp: + return + + snapshot = [x for x in self.actions if x.t == 'Snapshot'] + if not snapshot: + return + d = { "type": PROOF_ENUM['Register'], "device": self, - "snapshot": [x for x in self.actions if x.t == 'Snapshot'][0], + "actions": snapshot[0], "timestamp": timestamp, "issuer_id": g.user.id, } @@ -978,15 +1001,6 @@ class Device(Thing): if isinstance(c, DataStorage): 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): self.user_trusts = False i = 0 @@ -1302,6 +1316,14 @@ class Placeholder(Thing): return docs.union(self.binding.documents) 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): """A chassis with components inside that can be processed diff --git a/ereuse_devicehub/templates/inventory/device_detail.html b/ereuse_devicehub/templates/inventory/device_detail.html index dc55da09..66783b3b 100644 --- a/ereuse_devicehub/templates/inventory/device_detail.html +++ b/ereuse_devicehub/templates/inventory/device_detail.html @@ -390,10 +390,9 @@ {% endif %} - {% if placeholder.binding %}
Proofs
- {% for proof in placeholder.binding.proofs %} + {% for proof in placeholder.proofs %}
@@ -436,7 +435,6 @@ {% endfor %} {% endfor %}
- {% endif %}
diff --git a/ereuse_devicehub/templates/inventory/device_list.html b/ereuse_devicehub/templates/inventory/device_list.html index 344e9f66..f5452f1e 100644 --- a/ereuse_devicehub/templates/inventory/device_list.html +++ b/ereuse_devicehub/templates/inventory/device_list.html @@ -226,6 +226,12 @@ Ready +
  • + + + E-Waste + +