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.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
ac = dev.last_action_trading
if ac.type == Confirm.t and not ac.user == g.user:
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)
# 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)

View File

@ -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:
if ac.type == revoke:
if ac.user == g.user:
# can todo revoke_pending
return revoke_pending
if ac.type == revoke and ac.user != g.user:
else:
# can to do confirm_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
return confirm
if ac.type == confirm and ac.user != g.user:
else:
# can to do confirm
return trade
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)

View File

@ -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,40 +252,51 @@ 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_(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(
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
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:
ac = dev.last_action_trading
if ac.type == 'Confirm' and ac.user == g.user:
# 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()
# 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,
@ -297,3 +307,5 @@ class LotDeviceView(LotBaseChildrenView):
lot.devices.difference_update(without_confirms)
lot.trade.devices = lot.devices
return revoke