diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index b0569caf..4054b624 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -7,7 +7,7 @@ from teal.marshmallow import ValidationError from ereuse_devicehub.db import db from ereuse_devicehub.resources.action.models import Trade, Confirm, ConfirmRevoke, Revoke from ereuse_devicehub.resources.user.models import User -from ereuse_devicehub.resources.lot.models import Lot +from ereuse_devicehub.resources.lot.views import delete_from_trade class TradeView(): @@ -172,41 +172,16 @@ class ConfirmView(ConfirmMixin): # import pdb; pdb.set_trace() real_devices = [] for dev in data['devices']: - actions = copy.copy(dev.actions) - actions.reverse() - for ac in actions: - if ac == data['action']: - # If device have the last action the action Trade - real_devices.append(dev) - break - - if ac.t == Confirm.t and not ac.user == g.user: - # If device is confirmed we don't need confirmed again - real_devices.append(dev) - break - - if ac.t == 'Revoke' and not ac.user == g.user: - # If device 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 device is confirmed we don't need confirmed again - break + 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']: - dev.owner = data['action'].user_to - if hasattr(dev, 'components'): - for c in dev.components: - c.owner = data['action'].user_to + user_to = data['action'].user_to + dev.change_owner(user_to) class RevokeView(ConfirmMixin): @@ -228,49 +203,48 @@ class RevokeView(ConfirmMixin): self.validate(a) 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 - """ + """All devices need to have the status of DoubleConfirmation.""" + ### check ### - devs_confirm = [] if not data['devices']: raise ValidationError('Devices not exist.') for dev in data['devices']: - if dev.last_action_trading.type == 'Confirm': - devs_confirm.append(dev) - - if not len(data['devices']) == len(devs_confirm): - txt = "Some of this devices can't be reboked" - raise ValidationError(txt) + if not dev.trading == 'TradeConfirmed': + txt = 'Some of devices do not have enough to confirm for to do a revoke' + ValidationError(txt) ### End check ### + ids = {d.id for d in data['devices']} lot = data['action'].lot - devices = set(data['devices']) - without_confirms = set() # set of devs without confirms of user2 + # import pdb; pdb.set_trace() + self.model = delete_from_trade(lot, ids) - if g.user == lot.trade.author: - for dev in devices: - ac = dev.last_action_trading - if ac.type == 'Confirm' and ac.user == g.user: - without_confirms.add(dev) + # devices = set(data['devices']) + # without_confirms = set() # set of devs without confirms of user2 - # we need to mark one revoke for every devs - revoke = Revoke(action=lot.trade, user=g.user, devices=devices) - db.session.add(revoke) + # if g.user == lot.trade.author: + # for dev in devices: + # ac = dev.last_action_trading + # if ac.type == 'Confirm' and ac.user == g.user: + # without_confirms.add(dev) - if without_confirms: - confirm_revoke = ConfirmRevoke( - action=revoke, - user=g.user, - devices=without_confirms - ) - db.session.add(confirm_revoke) + # # we need to mark one revoke for every devs + # revoke = Revoke(action=lot.trade, user=g.user, devices=devices) + # db.session.add(revoke) - lot.devices.difference_update(without_confirms) - lot.trade.devices = lot.devices + # if without_confirms: + # confirm_revoke = ConfirmRevoke( + # action=revoke, + # user=g.user, + # devices=without_confirms + # ) + # db.session.add(confirm_revoke) - self.model = revoke + # lot.devices.difference_update(without_confirms) + # lot.trade.devices = lot.devices + + # self.model = revoke class ConfirmRevokeView(ConfirmMixin): @@ -287,38 +261,18 @@ class ConfirmRevokeView(ConfirmMixin): Model = ConfirmRevoke 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 = [] + """All devices need to have the status of revoke.""" + + if not data['action'].type == 'Revoke': + txt = 'Error: this action is not a revoke action' + ValidationError(txt) + for dev in data['devices']: - actions = copy.copy(dev.actions) - actions.reverse() - for ac in actions: - if ac == data['action']: - # If device have the last action the action for confirm - real_devices.append(dev) - break + if not dev.trading == 'Revoke': + txt = 'Some of devices do not have revoke to confirm' + ValidationError(txt) - if ac.t == 'Revoke' and not ac.user == g.user: - # If device is revoke before you can Confirm now - # and revoke is an action of one other user - real_devices.append(dev) - break - - if ac.t == ConfirmRevoke.t and ac.user == g.user: - # If device 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 - - devices = OrderedSet(real_devices) + devices = OrderedSet(data['devices']) data['devices'] = devices # Change the owner for every devices @@ -326,10 +280,6 @@ class ConfirmRevokeView(ConfirmMixin): trade = data['action'].action for dev in devices: - # TODO @cayop if it's possible the both users insert devices into a lot, then there are problems - dev.owner = trade.author - if hasattr(dev, 'components'): - for c in dev.components: - c.owner = trade.author + dev.reset_owner() trade.lot.devices.difference_update(devices) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 852ed4ca..61363ed8 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -266,8 +266,10 @@ 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""" - trade = 'Trade' + # trade = 'Trade' confirm = 'Confirm' + need_confirm = 'NeedConfirmation' + double_confirm = 'TradeConfirmed' revoke = 'Revoke' revoke_pending = 'RevokePending' confirm_revoke = 'ConfirmRevoke' @@ -298,26 +300,37 @@ class Device(Thing): ## RevokeConfirmation => RevokeConfirmed ac = self.last_action_trading + if not ac: + return + + first_owner = self.which_user_put_this_device_in_trace() if ac.type == confirm_revoke: # can to do revoke_confirmed return confirm_revoke - if ac.type == revoke and ac.user == g.user: - # can todo revoke_pending - return revoke_pending + if ac.type == revoke: + if ac.user == g.user: + # can todo revoke_pending + return revoke_pending + else: + # can to do confirm_revoke + return revoke - if ac.type == revoke and ac.user != g.user: - # can to do confirm_revoke - return revoke + if ac.type == confirm: + if not first_owner: + return - if ac.type == confirm and (ac.user == g.user or ac.action.author == g.user): - # can to do revoke - return confirm - - if ac.type == confirm and ac.user != g.user: - # can to do confirm - return trade + if ac.user == first_owner: + if first_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 @property def revoke(self): @@ -421,12 +434,37 @@ class Device(Thing): """ try: # noinspection PyTypeHints - actions = self.actions + actions = copy.copy(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)) + def which_user_put_this_device_in_trace(self): + """which is the user than put this device in this trade""" + actions = copy.copy(self.actions) + actions.sort(key=lambda x: x.created) + actions.reverse() + last_ac = None + # search the automatic Confirm + for ac in actions: + if ac.type == 'Trade': + return last_ac.user + if ac.type == 'Confirm': + last_ac = ac + + def change_owner(self, new_user): + """util for change the owner one device""" + self.owner = new_user + if hasattr(self, 'components'): + for c in self.components: + c.owner = new_user + + def reset_owner(self): + """Change the owner with the user put the device into the trade""" + user = self.which_user_put_this_device_in_trace() + self.change_owner(user) + def _warning_actions(self, actions): return sorted(ev for ev in actions if ev.severity >= Severity.Warning) diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 16e27bbe..c75291dc 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -230,12 +230,11 @@ class LotDeviceView(LotBaseChildrenView): return users = [g.user.id] - # Not for the moment - # if lot.trade: + if lot.trade: # all users involved in the trade action can modify the lot - # trade_users = [lot.trade.user_from.id, lot.trade.user_to.id] - # if g.user in trade_users: - # users = trade_users + trade_users = [lot.trade.user_from.id, lot.trade.user_to.id] + if g.user in trade_users: + users = trade_users devices = set(Device.query.filter(Device.id.in_(ids)).filter( Device.owner_id.in_(users))) @@ -253,47 +252,60 @@ class LotDeviceView(LotBaseChildrenView): if not ids.issubset({x.id for x in lot.devices}): return - users = [g.user.id] - # import pdb; pdb.set_trace() if lot.trade: - # all users involved in the trade action can modify the lot - trade_users = [lot.trade.user_from.id, lot.trade.user_to.id] - if g.user in trade_users: - users = trade_users + return delete_from_trade(lot, ids) + if not g.user in lot.owner: + txt = 'This is not your trade' + raise ma.ValidationError(txt) devices = set(Device.query.filter(Device.id.in_(ids)).filter( - Device.owner_id.in_(users))) + Device.owner_id.in_(g.user.id))) - if not lot.trade: - lot.devices.difference_update(devices) - return - - # if is a trade - if not g.user in [lot.trade.user_from, lot.trade.user_to]: - # theoretically this case is impossible - return + lot.devices.difference_update(devices) - # Now we need to know which devices we need extract of the lot - without_confirms = set() # set of devs without confirms of user2 +def delete_from_trade(lot: Lot, ids: Set[int]): + users = [lot.trade.user_from.id, lot.trade.user_to.id] + if not g.user.id in users: + # theoretically this case is impossible + txt = 'This is not your trade' + raise ma.ValidationError(txt) - if g.user == lot.trade.author: - for dev in devices: - ac = dev.last_action_trading - if ac.type == 'Confirm' and ac.user == g.user: - without_confirms.add(dev) + # import pdb; pdb.set_trace() + devices = set(Device.query.filter(Device.id.in_(ids)).filter( + Device.owner_id.in_(users))) - # we need to mark one revoke for every devs - revoke = Revoke(action=lot.trade, user=g.user, devices=devices) - db.session.add(revoke) + # Now we need to know which devices we need extract of the lot + without_confirms = set() # set of devs without confirms of user2 - if without_confirms: - confirm_revoke = ConfirmRevoke( - action=revoke, - user=g.user, - devices=without_confirms - ) - db.session.add(confirm_revoke) + # if the trade need confirmation, then extract all devs than + # have only one confirmation and is from the same user than try to do + # now the revoke action + if lot.trade.confirm: + for dev in devices: + # if have only one confirmation + # then can be revoked and deleted of the lot + if dev.trading == 'NeedConfirmation': + without_confirms.add(dev) + dev.reset_owner() - lot.devices.difference_update(without_confirms) - lot.trade.devices = lot.devices + # we need to mark one revoke for every devs + revoke = Revoke(action=lot.trade, user=g.user, devices=devices) + db.session.add(revoke) + + if not lot.trade.confirm: + # if the trade is with phantom account + without_confirms = devices + + if without_confirms: + confirm_revoke = ConfirmRevoke( + action=revoke, + user=g.user, + devices=without_confirms + ) + db.session.add(confirm_revoke) + + lot.devices.difference_update(without_confirms) + lot.trade.devices = lot.devices + + return revoke