diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index fb33cfea..3c99c3ef 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -16,6 +16,7 @@ from ereuse_devicehub.resources import enums from ereuse_devicehub.resources.action import models as m from ereuse_devicehub.resources.agent import schemas as s_agent from ereuse_devicehub.resources.device import schemas as s_device +from ereuse_devicehub.resources.tradedocument import schemas as s_document from ereuse_devicehub.resources.enums import AppearanceRange, BiosAccessRange, FunctionalityRange, \ PhysicalErasureMethod, R_POSITIVE, RatingRange, \ Severity, SnapshotSoftware, TestDataStorageLength @@ -67,6 +68,14 @@ class ActionWithMultipleDevices(Action): collection_class=OrderedSet) +class ActionWithMultipleTradeDocuments(ActionWithMultipleDevices): + documents = NestedOn(s_document.TradeDocument, + many=True, + required=False, + only_query='id', + collection_class=OrderedSet) + + class Add(ActionWithOneDevice): __doc__ = m.Add.__doc__ @@ -457,7 +466,7 @@ class CancelReservation(Organize): __doc__ = m.CancelReservation.__doc__ -class Confirm(ActionWithMultipleDevices): +class Confirm(ActionWithMultipleTradeDocuments): __doc__ = m.Confirm.__doc__ action = NestedOn('Action', only_query='id') @@ -469,8 +478,55 @@ class Confirm(ActionWithMultipleDevices): txt = "Device {} not exist in the trade".format(dev.devicehub_id) raise ValidationError(txt) + 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) -class Revoke(ActionWithMultipleDevices): + @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(ActionWithMultipleTradeDocuments): __doc__ = m.Revoke.__doc__ action = NestedOn('Action', only_query='id') @@ -482,20 +538,103 @@ class Revoke(ActionWithMultipleDevices): txt = "Device {} not exist in the trade".format(dev.devicehub_id) raise ValidationError(txt) + 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) -class ConfirmRevoke(ActionWithMultipleDevices): + @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 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']: + # 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 ac.t == 'Revoke' and ac.user == g.user: + # this doc is confirmation jet + break + + if ac.t == Confirm.t and ac.user == g.user: + documents.append(doc) + break + + if not documents: + txt = 'No there are documents to revoke' + raise ValidationError(txt) + + +class ConfirmRevoke(ActionWithMultipleTradeDocuments): __doc__ = m.ConfirmRevoke.__doc__ action = NestedOn('Action', only_query='id') @validates_schema def validate_revoke(self, data: dict): - # import pdb; pdb.set_trace() for dev in data['devices']: # if device not exist in the Trade, then this query is wrong if not dev in data['action'].devices: - txt = "Device {} not exist in the revoke action".format(dev.devicehub_id) + txt = "Device {} not exist in the trade".format(dev.devicehub_id) raise ValidationError(txt) + 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__ diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 8b22de17..522b323d 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -27,7 +27,6 @@ class TradeView(): """ def __init__(self, data, resource_def, schema): - # import pdb; pdb.set_trace() self.schema = schema a = resource_def.schema.load(data) self.trade = Trade(**a) @@ -49,28 +48,34 @@ class TradeView(): # if the confirmation is mandatory, do automatic confirmation only for # owner of the lot if self.trade.confirm: - confirm_devs = Confirm(user=g.user, - action=self.trade, - devices=self.trade.devices) + if self.trade.devices: + confirm_devs = Confirm(user=g.user, + action=self.trade, + devices=self.trade.devices) + db.session.add(confirm_devs) - confirm_docs = Confirm(user=g.user, - action=self.trade, - documents=self.trade.documents) - db.session.add(confirm_devs, confirm_docs) + if self.trade.documents: + confirm_docs = Confirm(user=g.user, + action=self.trade, + documents=self.trade.documents) + db.session.add(confirm_docs) return # check than the user than want to do the action is one of the users # involved in the action assert g.user.id in [self.trade.user_from_id, self.trade.user_to_id] - confirm_from = Confirm(user=self.trade.user_from, - action=self.trade, - devices=self.trade.devices) - confirm_to = Confirm(user=self.trade.user_to, - action=self.trade, - devices=self.trade.devices) - db.session.add(confirm_from) - db.session.add(confirm_to) + if self.trade.user_from == g.user or self.trade.user_from.phantom: + confirm_from = Confirm(user=self.trade.user_from, + action=self.trade, + devices=self.trade.devices) + db.session.add(confirm_from) + + if self.trade.user_to == g.user or self.trade.user_to.phantom: + confirm_to = Confirm(user=self.trade.user_to, + action=self.trade, + devices=self.trade.devices) + db.session.add(confirm_to) def create_phantom_account(self) -> None: """ @@ -141,7 +146,7 @@ class ConfirmMixin(): self.schema = schema a = resource_def.schema.load(data) self.validate(a) - if not a['devices']: + if not a['devices'] and not a['documents']: raise ValidationError('Devices not exist.') self.model = self.Model(**a) @@ -169,7 +174,6 @@ class ConfirmView(ConfirmMixin): """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() real_devices = [] for dev in data['devices']: actions = copy.copy(dev.actions) @@ -181,7 +185,7 @@ class ConfirmView(ConfirmMixin): break if ac.t == Confirm.t and not ac.user == g.user: - # If device is confirmed we don't need confirmed again + # If device is confirmed but is not for g.user, then need confirm real_devices.append(dev) break diff --git a/ereuse_devicehub/resources/tradedocument/views.py b/ereuse_devicehub/resources/tradedocument/views.py index e85db306..054f29cd 100644 --- a/ereuse_devicehub/resources/tradedocument/views.py +++ b/ereuse_devicehub/resources/tradedocument/views.py @@ -6,6 +6,7 @@ from teal.resource import View from ereuse_devicehub.db import db from ereuse_devicehub.resources.tradedocument.models import TradeDocument +from ereuse_devicehub.resources.action.models import Confirm, Revoke from ereuse_devicehub.resources.hash_reports import insert_hash @@ -52,6 +53,14 @@ class TradeDocumentView(View): insert_hash(bfile) doc = TradeDocument(**data) + trade = doc.lot.trade + if trade: + trade.documents.add(doc) + confirm = Confirm(action=trade, + user=g.user, + devices=set(), + documents={doc}) + db.session.add(confirm) db.session.add(doc) db.session().final_flush() ret = self.schema.jsonify(doc)