simplify the algorithm for to manager the confirms flow

This commit is contained in:
Cayo Puigdefabregas 2021-06-07 10:50:08 +02:00
parent 6dc7fb830b
commit 21cdcb5350
3 changed files with 150 additions and 150 deletions

View file

@ -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: real_devices.append(dev)
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
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)

View file

@ -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:
# can todo revoke_pending if ac.user == g.user:
return revoke_pending # can todo revoke_pending
return revoke_pending
else:
# can to do confirm_revoke
return revoke
if ac.type == revoke and ac.user != g.user: if ac.type == confirm:
# can to do confirm_revoke if not first_owner:
return revoke return
if ac.type == confirm and (ac.user == g.user or ac.action.author == g.user): if ac.user == first_owner:
# can to do revoke if first_owner == g.user:
return confirm # can to do revoke
return confirm
if ac.type == confirm and ac.user != g.user: else:
# 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)

View file

@ -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,47 +252,60 @@ 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( 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)
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 def delete_from_trade(lot: Lot, ids: Set[int]):
without_confirms = set() # set of devs without confirms of user2 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: # import pdb; pdb.set_trace()
for dev in devices: devices = set(Device.query.filter(Device.id.in_(ids)).filter(
ac = dev.last_action_trading Device.owner_id.in_(users)))
if ac.type == 'Confirm' and ac.user == g.user:
without_confirms.add(dev)
# we need to mark one revoke for every devs # Now we need to know which devices we need extract of the lot
revoke = Revoke(action=lot.trade, user=g.user, devices=devices) without_confirms = set() # set of devs without confirms of user2
db.session.add(revoke)
if without_confirms: # if the trade need confirmation, then extract all devs than
confirm_revoke = ConfirmRevoke( # have only one confirmation and is from the same user than try to do
action=revoke, # now the revoke action
user=g.user, if lot.trade.confirm:
devices=without_confirms for dev in devices:
) # if have only one confirmation
db.session.add(confirm_revoke) # 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) # we need to mark one revoke for every devs
lot.trade.devices = lot.devices 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