From c8b0c56bbb64dd628868e33e6a3bf4adcb3df040 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 28 Jun 2021 16:06:07 +0200 Subject: [PATCH] confirm Revoke, confirm and revoke documents actions --- ereuse_devicehub/resources/action/__init__.py | 4 +- ereuse_devicehub/resources/action/models.py | 5 + ereuse_devicehub/resources/action/schemas.py | 210 +++++++----------- .../resources/action/views/trade.py | 60 ++--- .../resources/action/views/views.py | 13 ++ .../resources/tradedocument/models.py | 55 ++--- 6 files changed, 147 insertions(+), 200 deletions(-) diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index ef19f907..5e581cd5 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -280,7 +280,9 @@ class RevokeDocumentDef(ActionDef): SCHEMA = schemas.RevokeDocument - +class ConfirmRevokeDocumentDef(ActionDef): + VIEW = None + SCHEMA = schemas.ConfirmRevokeDocument class CancelTradeDef(ActionDef): diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index debe4a55..d8bcb3ce 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1447,6 +1447,7 @@ class Reserve(Organize): class CancelReservation(Organize): """The act of cancelling a reservation.""" + class ConfirmDocument(JoinedTableMixin, ActionWithMultipleTradeDocuments): """Users confirm the one action trade this confirmation it's link to trade and the document that confirm @@ -1480,6 +1481,10 @@ class RevokeDocument(ConfirmDocument): pass +class ConfirmRevokeDocument(ConfirmDocument): + pass + + class Confirm(JoinedTableMixin, ActionWithMultipleDevices): """Users confirm the one action trade this confirmation it's link to trade and the devices that confirm diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 89ca4c07..a0a3a45f 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -480,60 +480,6 @@ class Confirm(ActionWithMultipleDevices): raise ValidationError(txt) -class ConfirmDocument(ActionWithMultipleDocuments): - __doc__ = m.Confirm.__doc__ - action = NestedOn('Action', only_query='id') - - @validates_schema - def validate_revoke(self, data: dict): - for doc in data.get('documents', []): - # if document not exist in the Trade, then this query is wrong - if not doc in data['action'].documents: - txt = "Document {} not exist in the trade".format(doc.file_name) - raise ValidationError(txt) - - @validates_schema - def validate_docs(self, data): - """If there are one device than have one confirmation, - then remove the list this device of the list of devices of this action - """ - if not data['devices'] == OrderedSet(): - return - - documents = [] - for doc in data['documents']: - actions = copy.copy(doc.actions) - actions.reverse() - for ac in actions: - if ac == data['action']: - # If document have the last action the action Trade - documents.append(doc) - break - - if ac.t == Confirm.t and not ac.user == g.user: - # If document is confirmed but is not for g.user, then need confirm - documents.append(doc) - break - - if ac.t == 'Revoke' and not ac.user == g.user: - # If document is revoke before from other user - # it's not possible confirm now - break - - if ac.t == 'ConfirmRevoke' and ac.user == g.user: - # if the last action is a ConfirmRevoke this mean than not there are - # other confirmation from the real owner of the trade - break - - if ac.t == Confirm.t and ac.user == g.user: - # If dodument is confirmed we don't need confirmed again - break - - if not documents: - txt = 'No there are documents to confirm' - raise ValidationError(txt) - - class Revoke(ActionWithMultipleDevices): __doc__ = m.Revoke.__doc__ action = NestedOn('Action', only_query='id') @@ -584,17 +530,43 @@ class Revoke(ActionWithMultipleDevices): raise ValidationError(txt) -class RevokeDocument(ActionWithMultipleDocuments): - __doc__ = m.RevokeDocument.__doc__ +class ConfirmDocument(ActionWithMultipleDocuments): + __doc__ = m.Confirm.__doc__ action = NestedOn('Action', only_query='id') @validates_schema - def validate_revoke(self, data: dict): - for doc in data.get('documents', []): - # if document not exist in the Trade, then this query is wrong - if not doc in data['action'].documents: - txt = "Document {} not exist in the trade".format(doc.file_name) - raise ValidationError(txt) + def validate_documents(self, data): + """If there are one device than have one confirmation, + then remove the list this device of the list of devices of this action + """ + # import pdb; pdb.set_trace() + if data['documents'] == OrderedSet(): + return + + documents = [] + for doc in data['documents']: + if not doc.lot.trade: + return + + data['action'] = doc.lot.trade + + if not doc.actions: + continue + + ac = doc.actions[-1] + + if ac.t == 'ConfirmDocument' and not ac.user == g.user: + # If document is confirmed but is not for g.user, then need confirm + documents.append(doc) + + if not documents: + txt = 'No there are documents to confirm' + raise ValidationError(txt) + + +class RevokeDocument(ActionWithMultipleDocuments): + __doc__ = m.RevokeDocument.__doc__ + action = NestedOn('Action', only_query='id') @validates_schema def validate_documents(self, data): @@ -602,33 +574,63 @@ class RevokeDocument(ActionWithMultipleDocuments): This is not checked in the view becouse the list of documents is inmutable """ - import pdb; pdb.set_trace() - if not data['documents'] == OrderedSet(): + if data['documents'] == OrderedSet(): return documents = [] for doc in data['documents']: - actions = copy.copy(doc.actions) - actions.reverse() - for ac in actions: - if ac == data['action']: - # data['action'] is a Trade action, if this is the first action - # to find mean that this document don't have a confirmation - break + if not doc.lot.trade: + return - if ac.t == 'Revoke' and ac.user == g.user: - # this doc is confirmation jet - break + data['action'] = doc.lot.trade - if ac.t == Confirm.t and ac.user == g.user: - documents.append(doc) - break + if not doc.actions: + continue + + ac = doc.actions[-1] + + if ac.t == 'ConfirmDocument' and ac.user == g.user: + documents.append(doc) if not documents: txt = 'No there are documents to revoke' raise ValidationError(txt) +class ConfirmRevokeDocument(ActionWithMultipleDocuments): + __doc__ = m.ConfirmRevoke.__doc__ + action = NestedOn('Action', only_query='id') + + @validates_schema + def validate_documents(self, data): + """Check if there are or no one before confirmation, + This is not checked in the view becouse the list of documents is inmutable + + """ + if data['documents'] == OrderedSet(): + return + + documents = [] + for doc in data['documents']: + if not doc.lot.trade: + return + + if not doc.actions: + continue + + ac = doc.actions[-1] + + if ac.t == 'RevokeDocument' and not ac.user == g.user: + # If document is revoke before you can Confirm now + # and revoke is an action of one other user + data['action'] = ac + documents.append(doc) + + if not documents: + txt = 'No there are documents with revoke for confirm' + raise ValidationError(txt) + + class ConfirmRevoke(ActionWithMultipleDevices): __doc__ = m.ConfirmRevoke.__doc__ action = NestedOn('Action', only_query='id') @@ -689,60 +691,6 @@ class ConfirmRevoke(ActionWithMultipleDevices): raise ValidationError(txt) -class ConfirmRevokeDocument(ActionWithMultipleDocuments): - __doc__ = m.ConfirmRevoke.__doc__ - action = NestedOn('Action', only_query='id') - - @validates_schema - def validate_revoke(self, data: dict): - for doc in data.get('documents', []): - # if document not exist in the Trade, then this query is wrong - if not doc in data['action'].documents: - txt = "Document {} not exist in the trade".format(doc.file_name) - raise ValidationError(txt) - - @validates_schema - def validate_docs(self, data): - """Check if there are or no one before confirmation, - This is not checked in the view becouse the list of documents is inmutable - - """ - if not data['devices'] == OrderedSet(): - return - - documents = [] - for doc in data['documents']: - actions = copy.copy(doc.actions) - actions.reverse() - for ac in actions: - if ac == data['action']: - # If document have the last action the action for confirm - documents.append(doc) - break - - if ac.t == 'Revoke' and not ac.user == g.user: - # If document is revoke before you can Confirm now - # and revoke is an action of one other user - documents.append(doc) - break - - if ac.t == ConfirmRevoke.t and ac.user == g.user: - # If document is confirmed we don't need confirmed again - break - - if ac.t == Confirm.t: - # if onwer of trade confirm again before than this user Confirm the - # revoke, then is not possible confirm the revoke - # - # If g.user confirm the trade before do a ConfirmRevoke - # then g.user can not to do the ConfirmRevoke more - break - - if not documents: - txt = 'No there are documents with revoke for confirm' - raise ValidationError(txt) - - class Trade(ActionWithMultipleDevices): __doc__ = m.Trade.__doc__ date = DateTime(data_key='date', required=False) diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 6e9d71f5..5779127a 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -1,12 +1,11 @@ -import copy - from flask import g from sqlalchemy.util import OrderedSet from teal.marshmallow import ValidationError from ereuse_devicehub.db import db from ereuse_devicehub.resources.action.models import (Trade, Confirm, ConfirmRevoke, - Revoke, RevokeDocument, ConfirmDocument) + Revoke, RevokeDocument, ConfirmDocument, + ConfirmRevokeDocument) from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.lot.views import delete_from_trade @@ -307,28 +306,22 @@ class ConfirmDocumentView(ConfirmDocumentMixin): request_confirm = { 'type': 'Confirm', 'action': trade.id, - 'devices': [device_id] + 'documents': [document_id], } """ - Model = Confirm + Model = ConfirmDocument def validate(self, data): """If there are one device than have one confirmation, then remove the list this device of the list of devices of this action """ - real_devices = [] - for dev in data['devices']: - ac = dev.last_action_trading - if ac.type == Confirm.t and not ac.user == g.user: - real_devices.append(dev) - - data['devices'] = OrderedSet(real_devices) - - # Change the owner for every devices - for dev in data['devices']: - user_to = data['action'].user_to - dev.change_owner(user_to) + for doc in data['documents']: + ac = doc.trading + if not doc.trading in ['Confirm', 'Need Confirmation']: + txt = 'Some of documents do not have enough to confirm for to do a Doble Confirmation' + ValidationError(txt) + ### End check ### class RevokeDocumentView(ConfirmDocumentMixin): @@ -337,18 +330,13 @@ class RevokeDocumentView(ConfirmDocumentMixin): request_revoke = { 'type': 'Revoke', 'action': trade.id, - 'devices': [device_id], + 'documents': [document_id], } """ Model = RevokeDocument - def __init__(self, data, resource_def, schema): - self.schema = schema - a = resource_def.schema.load(data) - self.validate(a) - def validate(self, data): """All devices need to have the status of DoubleConfirmation.""" @@ -357,7 +345,7 @@ class RevokeDocumentView(ConfirmDocumentMixin): raise ValidationError('Documents not exist.') for doc in data['documents']: - if not doc.trading == 'Confirmed': + if not doc.trading in ['Document Confirmed', 'Confirm']: txt = 'Some of documents do not have enough to confirm for to do a revoke' ValidationError(txt) ### End check ### @@ -369,33 +357,21 @@ class ConfirmRevokeDocumentView(ConfirmDocumentMixin): request_confirm_revoke = { 'type': 'ConfirmRevoke', 'action': action_revoke.id, - 'devices': [device_id] + 'documents': [document_id], } """ - Model = ConfirmRevoke + Model = ConfirmRevokeDocument def validate(self, data): """All devices need to have the status of revoke.""" - if not data['action'].type == 'Revoke': + if not data['action'].type == 'RevokeDocument': txt = 'Error: this action is not a revoke action' ValidationError(txt) - for dev in data['devices']: - if not dev.trading == 'Revoke': - txt = 'Some of devices do not have revoke to confirm' + for doc in data['documents']: + if not doc.trading == 'Revoke': + txt = 'Some of documents do not have revoke to confirm' ValidationError(txt) - - devices = OrderedSet(data['devices']) - data['devices'] = devices - - # Change the owner for every devices - # data['action'] == 'Revoke' - - trade = data['action'].action - for dev in devices: - dev.reset_owner() - - trade.lot.devices.difference_update(devices) diff --git a/ereuse_devicehub/resources/action/views/views.py b/ereuse_devicehub/resources/action/views/views.py index 8cb324ff..fbb15ea6 100644 --- a/ereuse_devicehub/resources/action/views/views.py +++ b/ereuse_devicehub/resources/action/views/views.py @@ -202,6 +202,19 @@ class ActionView(View): confirm_revoke = trade_view.ConfirmRevokeView(json, resource_def, self.schema) return confirm_revoke.post() + if json['type'] == 'RevokeDocument': + revoke = trade_view.RevokeDocumentView(json, resource_def, self.schema) + return revoke.post() + + if json['type'] == 'ConfirmDocument': + confirm = trade_view.ConfirmDocumentView(json, resource_def, self.schema) + return confirm.post() + + if json['type'] == 'ConfirmRevokeDocument': + confirm_revoke = trade_view.ConfirmRevokeDocumentView(json, resource_def, self.schema) + return confirm_revoke.post() + + # import pdb; pdb.set_trace() a = resource_def.schema.load(json) Model = db.Model._decl_class_registry.data[json['type']]() action = Model(**a) diff --git a/ereuse_devicehub/resources/tradedocument/models.py b/ereuse_devicehub/resources/tradedocument/models.py index b38e7374..9c743244 100644 --- a/ereuse_devicehub/resources/tradedocument/models.py +++ b/ereuse_devicehub/resources/tradedocument/models.py @@ -94,38 +94,41 @@ class TradeDocument(Thing): """The trading state, or None if no Trade action has ever been performed to this device. This extract the posibilities for to do""" - # import pdb; pdb.set_trace() - confirm = 'ConfirmDocument' - to_confirm = 'To Confirm' + confirm = 'Confirm' + need_confirm = 'Need Confirmation' + double_confirm = 'Document Confirmed' revoke = 'Revoke' - + revoke_pending = 'Revoke Pending' + confirm_revoke = 'Document Revoked' + if not self.actions: - return + return - actions = copy.copy(self.actions) - actions = list(reversed(actions)) - ac = actions[0] + ac = self.actions[-1] - if ac.type == revoke: - return revoke + if ac.type == 'ConfirmRevokeDocument': + # can to do revoke_confirmed + return confirm_revoke - if ac.type == confirm: + if ac.type == 'RevokeDocument': + if ac.user == g.user: + # can todo revoke_pending + return revoke_pending + else: + # can to do confirm_revoke + return revoke + + if ac.type == 'ConfirmDocument': if ac.user == self.owner: - return to_confirm - return 'Confirmed' - - def last_action_of(self, *types): - """Gets the last action of the given types. - - :raise LookupError: Device has not an action of the given type. - """ - try: - # noinspection PyTypeHints - actions = self.actions - actions.sort(key=lambda x: x.created) - return next(e for e in reversed(actions) if isinstance(e, types)) - except StopIteration: - raise LookupError('{!r} does not contain actions of types {}.'.format(self, types)) + if self.owner == g.user: + # can to do revoke + return confirm + else: + # can to do confirm + return need_confirm + else: + # can to do revoke + return double_confirm def _warning_actions(self, actions): return sorted(ev for ev in actions if ev.severity >= Severity.Warning)