simplify the algorithm for to manager the confirms flow
This commit is contained in:
parent
6dc7fb830b
commit
21cdcb5350
|
@ -7,7 +7,7 @@ from teal.marshmallow import ValidationError
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
from ereuse_devicehub.resources.action.models import Trade, Confirm, ConfirmRevoke, Revoke
|
from ereuse_devicehub.resources.action.models import Trade, Confirm, ConfirmRevoke, Revoke
|
||||||
from ereuse_devicehub.resources.user.models import User
|
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():
|
class TradeView():
|
||||||
|
@ -172,41 +172,16 @@ class ConfirmView(ConfirmMixin):
|
||||||
# import pdb; pdb.set_trace()
|
# import pdb; pdb.set_trace()
|
||||||
real_devices = []
|
real_devices = []
|
||||||
for dev in data['devices']:
|
for dev in data['devices']:
|
||||||
actions = copy.copy(dev.actions)
|
ac = dev.last_action_trading
|
||||||
actions.reverse()
|
if ac.type == Confirm.t and not ac.user == g.user:
|
||||||
for ac in actions:
|
|
||||||
if ac == data['action']:
|
|
||||||
# If device have the last action the action Trade
|
|
||||||
real_devices.append(dev)
|
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
|
|
||||||
|
|
||||||
data['devices'] = OrderedSet(real_devices)
|
data['devices'] = OrderedSet(real_devices)
|
||||||
|
|
||||||
# Change the owner for every devices
|
# Change the owner for every devices
|
||||||
for dev in data['devices']:
|
for dev in data['devices']:
|
||||||
dev.owner = data['action'].user_to
|
user_to = data['action'].user_to
|
||||||
if hasattr(dev, 'components'):
|
dev.change_owner(user_to)
|
||||||
for c in dev.components:
|
|
||||||
c.owner = data['action'].user_to
|
|
||||||
|
|
||||||
|
|
||||||
class RevokeView(ConfirmMixin):
|
class RevokeView(ConfirmMixin):
|
||||||
|
@ -228,49 +203,48 @@ class RevokeView(ConfirmMixin):
|
||||||
self.validate(a)
|
self.validate(a)
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
"""If there are one device than have one confirmation,
|
"""All devices need to have the status of DoubleConfirmation."""
|
||||||
then remove the list this device of the list of devices of this action
|
|
||||||
"""
|
|
||||||
### check ###
|
### check ###
|
||||||
devs_confirm = []
|
|
||||||
if not data['devices']:
|
if not data['devices']:
|
||||||
raise ValidationError('Devices not exist.')
|
raise ValidationError('Devices not exist.')
|
||||||
|
|
||||||
for dev in data['devices']:
|
for dev in data['devices']:
|
||||||
if dev.last_action_trading.type == 'Confirm':
|
if not dev.trading == 'TradeConfirmed':
|
||||||
devs_confirm.append(dev)
|
txt = 'Some of devices do not have enough to confirm for to do a revoke'
|
||||||
|
ValidationError(txt)
|
||||||
if not len(data['devices']) == len(devs_confirm):
|
|
||||||
txt = "Some of this devices can't be reboked"
|
|
||||||
raise ValidationError(txt)
|
|
||||||
### End check ###
|
### End check ###
|
||||||
|
|
||||||
|
ids = {d.id for d in data['devices']}
|
||||||
lot = data['action'].lot
|
lot = data['action'].lot
|
||||||
devices = set(data['devices'])
|
# import pdb; pdb.set_trace()
|
||||||
without_confirms = set() # set of devs without confirms of user2
|
self.model = delete_from_trade(lot, ids)
|
||||||
|
|
||||||
if g.user == lot.trade.author:
|
# devices = set(data['devices'])
|
||||||
for dev in devices:
|
# without_confirms = set() # set of devs without confirms of user2
|
||||||
ac = dev.last_action_trading
|
|
||||||
if ac.type == 'Confirm' and ac.user == g.user:
|
|
||||||
without_confirms.add(dev)
|
|
||||||
|
|
||||||
# we need to mark one revoke for every devs
|
# if g.user == lot.trade.author:
|
||||||
revoke = Revoke(action=lot.trade, user=g.user, devices=devices)
|
# for dev in devices:
|
||||||
db.session.add(revoke)
|
# ac = dev.last_action_trading
|
||||||
|
# if ac.type == 'Confirm' and ac.user == g.user:
|
||||||
|
# without_confirms.add(dev)
|
||||||
|
|
||||||
if without_confirms:
|
# # we need to mark one revoke for every devs
|
||||||
confirm_revoke = ConfirmRevoke(
|
# revoke = Revoke(action=lot.trade, user=g.user, devices=devices)
|
||||||
action=revoke,
|
# db.session.add(revoke)
|
||||||
user=g.user,
|
|
||||||
devices=without_confirms
|
|
||||||
)
|
|
||||||
db.session.add(confirm_revoke)
|
|
||||||
|
|
||||||
lot.devices.difference_update(without_confirms)
|
# if without_confirms:
|
||||||
lot.trade.devices = lot.devices
|
# 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):
|
class ConfirmRevokeView(ConfirmMixin):
|
||||||
|
@ -287,38 +261,18 @@ class ConfirmRevokeView(ConfirmMixin):
|
||||||
Model = ConfirmRevoke
|
Model = ConfirmRevoke
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
"""If there are one device than have one confirmation,
|
"""All devices need to have the status of revoke."""
|
||||||
then remove the list this device of the list of devices of this action
|
|
||||||
"""
|
if not data['action'].type == 'Revoke':
|
||||||
real_devices = []
|
txt = 'Error: this action is not a revoke action'
|
||||||
|
ValidationError(txt)
|
||||||
|
|
||||||
for dev in data['devices']:
|
for dev in data['devices']:
|
||||||
actions = copy.copy(dev.actions)
|
if not dev.trading == 'Revoke':
|
||||||
actions.reverse()
|
txt = 'Some of devices do not have revoke to confirm'
|
||||||
for ac in actions:
|
ValidationError(txt)
|
||||||
if ac == data['action']:
|
|
||||||
# If device have the last action the action for confirm
|
|
||||||
real_devices.append(dev)
|
|
||||||
break
|
|
||||||
|
|
||||||
if ac.t == 'Revoke' and not ac.user == g.user:
|
devices = OrderedSet(data['devices'])
|
||||||
# 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)
|
|
||||||
data['devices'] = devices
|
data['devices'] = devices
|
||||||
|
|
||||||
# Change the owner for every devices
|
# Change the owner for every devices
|
||||||
|
@ -326,10 +280,6 @@ class ConfirmRevokeView(ConfirmMixin):
|
||||||
|
|
||||||
trade = data['action'].action
|
trade = data['action'].action
|
||||||
for dev in devices:
|
for dev in devices:
|
||||||
# TODO @cayop if it's possible the both users insert devices into a lot, then there are problems
|
dev.reset_owner()
|
||||||
dev.owner = trade.author
|
|
||||||
if hasattr(dev, 'components'):
|
|
||||||
for c in dev.components:
|
|
||||||
c.owner = trade.author
|
|
||||||
|
|
||||||
trade.lot.devices.difference_update(devices)
|
trade.lot.devices.difference_update(devices)
|
||||||
|
|
|
@ -266,8 +266,10 @@ 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"""
|
||||||
|
|
||||||
trade = 'Trade'
|
# trade = 'Trade'
|
||||||
confirm = 'Confirm'
|
confirm = 'Confirm'
|
||||||
|
need_confirm = 'NeedConfirmation'
|
||||||
|
double_confirm = 'TradeConfirmed'
|
||||||
revoke = 'Revoke'
|
revoke = 'Revoke'
|
||||||
revoke_pending = 'RevokePending'
|
revoke_pending = 'RevokePending'
|
||||||
confirm_revoke = 'ConfirmRevoke'
|
confirm_revoke = 'ConfirmRevoke'
|
||||||
|
@ -298,26 +300,37 @@ class Device(Thing):
|
||||||
## RevokeConfirmation => RevokeConfirmed
|
## RevokeConfirmation => RevokeConfirmed
|
||||||
|
|
||||||
ac = self.last_action_trading
|
ac = self.last_action_trading
|
||||||
|
if not ac:
|
||||||
|
return
|
||||||
|
|
||||||
|
first_owner = self.which_user_put_this_device_in_trace()
|
||||||
|
|
||||||
if ac.type == confirm_revoke:
|
if ac.type == confirm_revoke:
|
||||||
# can to do revoke_confirmed
|
# can to do revoke_confirmed
|
||||||
return confirm_revoke
|
return confirm_revoke
|
||||||
|
|
||||||
if ac.type == revoke and ac.user == g.user:
|
if ac.type == revoke:
|
||||||
|
if ac.user == g.user:
|
||||||
# can todo revoke_pending
|
# can todo revoke_pending
|
||||||
return revoke_pending
|
return revoke_pending
|
||||||
|
else:
|
||||||
if ac.type == revoke and ac.user != g.user:
|
|
||||||
# can to do confirm_revoke
|
# can to do confirm_revoke
|
||||||
return revoke
|
return revoke
|
||||||
|
|
||||||
if ac.type == confirm and (ac.user == g.user or ac.action.author == g.user):
|
if ac.type == confirm:
|
||||||
|
if not first_owner:
|
||||||
|
return
|
||||||
|
|
||||||
|
if ac.user == first_owner:
|
||||||
|
if first_owner == g.user:
|
||||||
# can to do revoke
|
# can to do revoke
|
||||||
return confirm
|
return confirm
|
||||||
|
else:
|
||||||
if ac.type == confirm and ac.user != g.user:
|
|
||||||
# can to do confirm
|
# can to do confirm
|
||||||
return trade
|
return need_confirm
|
||||||
|
else:
|
||||||
|
# can to do revoke
|
||||||
|
return double_confirm
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def revoke(self):
|
def revoke(self):
|
||||||
|
@ -421,12 +434,37 @@ class Device(Thing):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# noinspection PyTypeHints
|
# noinspection PyTypeHints
|
||||||
actions = self.actions
|
actions = copy.copy(self.actions)
|
||||||
actions.sort(key=lambda x: x.created)
|
actions.sort(key=lambda x: x.created)
|
||||||
return next(e for e in reversed(actions) if isinstance(e, types))
|
return next(e for e in reversed(actions) if isinstance(e, types))
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
raise LookupError('{!r} does not contain actions of types {}.'.format(self, types))
|
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):
|
def _warning_actions(self, actions):
|
||||||
return sorted(ev for ev in actions if ev.severity >= Severity.Warning)
|
return sorted(ev for ev in actions if ev.severity >= Severity.Warning)
|
||||||
|
|
||||||
|
|
|
@ -230,12 +230,11 @@ class LotDeviceView(LotBaseChildrenView):
|
||||||
return
|
return
|
||||||
|
|
||||||
users = [g.user.id]
|
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
|
# all users involved in the trade action can modify the lot
|
||||||
# trade_users = [lot.trade.user_from.id, lot.trade.user_to.id]
|
trade_users = [lot.trade.user_from.id, lot.trade.user_to.id]
|
||||||
# if g.user in trade_users:
|
if g.user in trade_users:
|
||||||
# users = trade_users
|
users = trade_users
|
||||||
|
|
||||||
devices = set(Device.query.filter(Device.id.in_(ids)).filter(
|
devices = set(Device.query.filter(Device.id.in_(ids)).filter(
|
||||||
Device.owner_id.in_(users)))
|
Device.owner_id.in_(users)))
|
||||||
|
@ -253,40 +252,51 @@ class LotDeviceView(LotBaseChildrenView):
|
||||||
if not ids.issubset({x.id for x in lot.devices}):
|
if not ids.issubset({x.id for x in lot.devices}):
|
||||||
return
|
return
|
||||||
|
|
||||||
users = [g.user.id]
|
|
||||||
# import pdb; pdb.set_trace()
|
|
||||||
if lot.trade:
|
if lot.trade:
|
||||||
# all users involved in the trade action can modify the lot
|
return delete_from_trade(lot, ids)
|
||||||
trade_users = [lot.trade.user_from.id, lot.trade.user_to.id]
|
|
||||||
if g.user in trade_users:
|
|
||||||
users = trade_users
|
|
||||||
|
|
||||||
|
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_(g.user.id)))
|
||||||
|
|
||||||
|
lot.devices.difference_update(devices)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# import pdb; pdb.set_trace()
|
||||||
devices = set(Device.query.filter(Device.id.in_(ids)).filter(
|
devices = set(Device.query.filter(Device.id.in_(ids)).filter(
|
||||||
Device.owner_id.in_(users)))
|
Device.owner_id.in_(users)))
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
# Now we need to know which devices we need extract of the lot
|
# Now we need to know which devices we need extract of the lot
|
||||||
without_confirms = set() # set of devs without confirms of user2
|
without_confirms = set() # set of devs without confirms of user2
|
||||||
|
|
||||||
if g.user == lot.trade.author:
|
# 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:
|
for dev in devices:
|
||||||
ac = dev.last_action_trading
|
# if have only one confirmation
|
||||||
if ac.type == 'Confirm' and ac.user == g.user:
|
# then can be revoked and deleted of the lot
|
||||||
|
if dev.trading == 'NeedConfirmation':
|
||||||
without_confirms.add(dev)
|
without_confirms.add(dev)
|
||||||
|
dev.reset_owner()
|
||||||
|
|
||||||
# we need to mark one revoke for every devs
|
# we need to mark one revoke for every devs
|
||||||
revoke = Revoke(action=lot.trade, user=g.user, devices=devices)
|
revoke = Revoke(action=lot.trade, user=g.user, devices=devices)
|
||||||
db.session.add(revoke)
|
db.session.add(revoke)
|
||||||
|
|
||||||
|
if not lot.trade.confirm:
|
||||||
|
# if the trade is with phantom account
|
||||||
|
without_confirms = devices
|
||||||
|
|
||||||
if without_confirms:
|
if without_confirms:
|
||||||
confirm_revoke = ConfirmRevoke(
|
confirm_revoke = ConfirmRevoke(
|
||||||
action=revoke,
|
action=revoke,
|
||||||
|
@ -297,3 +307,5 @@ class LotDeviceView(LotBaseChildrenView):
|
||||||
|
|
||||||
lot.devices.difference_update(without_confirms)
|
lot.devices.difference_update(without_confirms)
|
||||||
lot.trade.devices = lot.devices
|
lot.trade.devices = lot.devices
|
||||||
|
|
||||||
|
return revoke
|
||||||
|
|
Reference in a new issue