confirm Revoke, confirm and revoke documents actions

This commit is contained in:
Cayo Puigdefabregas 2021-06-28 16:06:07 +02:00
parent 8a797f079b
commit c8b0c56bbb
6 changed files with 147 additions and 200 deletions

View File

@ -280,7 +280,9 @@ class RevokeDocumentDef(ActionDef):
SCHEMA = schemas.RevokeDocument SCHEMA = schemas.RevokeDocument
class ConfirmRevokeDocumentDef(ActionDef):
VIEW = None
SCHEMA = schemas.ConfirmRevokeDocument
class CancelTradeDef(ActionDef): class CancelTradeDef(ActionDef):

View File

@ -1447,6 +1447,7 @@ class Reserve(Organize):
class CancelReservation(Organize): class CancelReservation(Organize):
"""The act of cancelling a reservation.""" """The act of cancelling a reservation."""
class ConfirmDocument(JoinedTableMixin, ActionWithMultipleTradeDocuments): class ConfirmDocument(JoinedTableMixin, ActionWithMultipleTradeDocuments):
"""Users confirm the one action trade this confirmation it's link to trade """Users confirm the one action trade this confirmation it's link to trade
and the document that confirm and the document that confirm
@ -1480,6 +1481,10 @@ class RevokeDocument(ConfirmDocument):
pass pass
class ConfirmRevokeDocument(ConfirmDocument):
pass
class Confirm(JoinedTableMixin, ActionWithMultipleDevices): class Confirm(JoinedTableMixin, ActionWithMultipleDevices):
"""Users confirm the one action trade this confirmation it's link to trade """Users confirm the one action trade this confirmation it's link to trade
and the devices that confirm and the devices that confirm

View File

@ -480,60 +480,6 @@ class Confirm(ActionWithMultipleDevices):
raise ValidationError(txt) raise ValidationError(txt)
class ConfirmDocument(ActionWithMultipleDocuments):
__doc__ = m.Confirm.__doc__
action = NestedOn('Action', only_query='id')
@validates_schema
def validate_revoke(self, data: dict):
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):
"""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(ActionWithMultipleDevices): class Revoke(ActionWithMultipleDevices):
__doc__ = m.Revoke.__doc__ __doc__ = m.Revoke.__doc__
action = NestedOn('Action', only_query='id') action = NestedOn('Action', only_query='id')
@ -584,51 +530,107 @@ class Revoke(ActionWithMultipleDevices):
raise ValidationError(txt) raise ValidationError(txt)
class RevokeDocument(ActionWithMultipleDocuments): class ConfirmDocument(ActionWithMultipleDocuments):
__doc__ = m.RevokeDocument.__doc__ __doc__ = m.Confirm.__doc__
action = NestedOn('Action', only_query='id') action = NestedOn('Action', only_query='id')
@validates_schema @validates_schema
def validate_revoke(self, data: dict): def validate_documents(self, data):
for doc in data.get('documents', []): """If there are one device than have one confirmation,
# if document not exist in the Trade, then this query is wrong then remove the list this device of the list of devices of this action
if not doc in data['action'].documents: """
txt = "Document {} not exist in the trade".format(doc.file_name) # import pdb; pdb.set_trace()
if data['documents'] == OrderedSet():
return
documents = []
for doc in data['documents']:
if not doc.lot.trade:
return
data['action'] = doc.lot.trade
if not doc.actions:
continue
ac = doc.actions[-1]
if ac.t == 'ConfirmDocument' and not ac.user == g.user:
# If document is confirmed but is not for g.user, then need confirm
documents.append(doc)
if not documents:
txt = 'No there are documents to confirm'
raise ValidationError(txt) raise ValidationError(txt)
class RevokeDocument(ActionWithMultipleDocuments):
__doc__ = m.RevokeDocument.__doc__
action = NestedOn('Action', only_query='id')
@validates_schema @validates_schema
def validate_documents(self, data): def validate_documents(self, data):
"""Check if there are or no one before confirmation, """Check if there are or no one before confirmation,
This is not checked in the view becouse the list of documents is inmutable This is not checked in the view becouse the list of documents is inmutable
""" """
import pdb; pdb.set_trace() if data['documents'] == OrderedSet():
if not data['documents'] == OrderedSet():
return return
documents = [] documents = []
for doc in data['documents']: for doc in data['documents']:
actions = copy.copy(doc.actions) if not doc.lot.trade:
actions.reverse() return
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: data['action'] = doc.lot.trade
# this doc is confirmation jet
break
if ac.t == Confirm.t and ac.user == g.user: if not doc.actions:
continue
ac = doc.actions[-1]
if ac.t == 'ConfirmDocument' and ac.user == g.user:
documents.append(doc) documents.append(doc)
break
if not documents: if not documents:
txt = 'No there are documents to revoke' txt = 'No there are documents to revoke'
raise ValidationError(txt) raise ValidationError(txt)
class ConfirmRevokeDocument(ActionWithMultipleDocuments):
__doc__ = m.ConfirmRevoke.__doc__
action = NestedOn('Action', only_query='id')
@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 data['documents'] == OrderedSet():
return
documents = []
for doc in data['documents']:
if not doc.lot.trade:
return
if not doc.actions:
continue
ac = doc.actions[-1]
if ac.t == 'RevokeDocument' and not ac.user == g.user:
# If document is revoke before you can Confirm now
# and revoke is an action of one other user
data['action'] = ac
documents.append(doc)
if not documents:
txt = 'No there are documents with revoke for confirm'
raise ValidationError(txt)
class ConfirmRevoke(ActionWithMultipleDevices): class ConfirmRevoke(ActionWithMultipleDevices):
__doc__ = m.ConfirmRevoke.__doc__ __doc__ = m.ConfirmRevoke.__doc__
action = NestedOn('Action', only_query='id') action = NestedOn('Action', only_query='id')
@ -689,60 +691,6 @@ class ConfirmRevoke(ActionWithMultipleDevices):
raise ValidationError(txt) raise ValidationError(txt)
class ConfirmRevokeDocument(ActionWithMultipleDocuments):
__doc__ = m.ConfirmRevoke.__doc__
action = NestedOn('Action', only_query='id')
@validates_schema
def validate_revoke(self, data: dict):
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): class Trade(ActionWithMultipleDevices):
__doc__ = m.Trade.__doc__ __doc__ = m.Trade.__doc__
date = DateTime(data_key='date', required=False) date = DateTime(data_key='date', required=False)

View File

@ -1,12 +1,11 @@
import copy
from flask import g from flask import g
from sqlalchemy.util import OrderedSet from sqlalchemy.util import OrderedSet
from teal.marshmallow import ValidationError 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, from ereuse_devicehub.resources.action.models import (Trade, Confirm, ConfirmRevoke,
Revoke, RevokeDocument, ConfirmDocument) Revoke, RevokeDocument, ConfirmDocument,
ConfirmRevokeDocument)
from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.user.models import User
from ereuse_devicehub.resources.lot.views import delete_from_trade from ereuse_devicehub.resources.lot.views import delete_from_trade
@ -307,28 +306,22 @@ class ConfirmDocumentView(ConfirmDocumentMixin):
request_confirm = { request_confirm = {
'type': 'Confirm', 'type': 'Confirm',
'action': trade.id, 'action': trade.id,
'devices': [device_id] 'documents': [document_id],
} }
""" """
Model = Confirm Model = ConfirmDocument
def validate(self, data): def validate(self, data):
"""If there are one device than have one confirmation, """If there are one device than have one confirmation,
then remove the list this device of the list of devices of this action then remove the list this device of the list of devices of this action
""" """
real_devices = [] for doc in data['documents']:
for dev in data['devices']: ac = doc.trading
ac = dev.last_action_trading if not doc.trading in ['Confirm', 'Need Confirmation']:
if ac.type == Confirm.t and not ac.user == g.user: txt = 'Some of documents do not have enough to confirm for to do a Doble Confirmation'
real_devices.append(dev) ValidationError(txt)
### End check ###
data['devices'] = OrderedSet(real_devices)
# Change the owner for every devices
for dev in data['devices']:
user_to = data['action'].user_to
dev.change_owner(user_to)
class RevokeDocumentView(ConfirmDocumentMixin): class RevokeDocumentView(ConfirmDocumentMixin):
@ -337,18 +330,13 @@ class RevokeDocumentView(ConfirmDocumentMixin):
request_revoke = { request_revoke = {
'type': 'Revoke', 'type': 'Revoke',
'action': trade.id, 'action': trade.id,
'devices': [device_id], 'documents': [document_id],
} }
""" """
Model = RevokeDocument Model = RevokeDocument
def __init__(self, data, resource_def, schema):
self.schema = schema
a = resource_def.schema.load(data)
self.validate(a)
def validate(self, data): def validate(self, data):
"""All devices need to have the status of DoubleConfirmation.""" """All devices need to have the status of DoubleConfirmation."""
@ -357,7 +345,7 @@ class RevokeDocumentView(ConfirmDocumentMixin):
raise ValidationError('Documents not exist.') raise ValidationError('Documents not exist.')
for doc in data['documents']: for doc in data['documents']:
if not doc.trading == 'Confirmed': if not doc.trading in ['Document Confirmed', 'Confirm']:
txt = 'Some of documents do not have enough to confirm for to do a revoke' txt = 'Some of documents do not have enough to confirm for to do a revoke'
ValidationError(txt) ValidationError(txt)
### End check ### ### End check ###
@ -369,33 +357,21 @@ class ConfirmRevokeDocumentView(ConfirmDocumentMixin):
request_confirm_revoke = { request_confirm_revoke = {
'type': 'ConfirmRevoke', 'type': 'ConfirmRevoke',
'action': action_revoke.id, 'action': action_revoke.id,
'devices': [device_id] 'documents': [document_id],
} }
""" """
Model = ConfirmRevoke Model = ConfirmRevokeDocument
def validate(self, data): def validate(self, data):
"""All devices need to have the status of revoke.""" """All devices need to have the status of revoke."""
if not data['action'].type == 'Revoke': if not data['action'].type == 'RevokeDocument':
txt = 'Error: this action is not a revoke action' txt = 'Error: this action is not a revoke action'
ValidationError(txt) ValidationError(txt)
for dev in data['devices']: for doc in data['documents']:
if not dev.trading == 'Revoke': if not doc.trading == 'Revoke':
txt = 'Some of devices do not have revoke to confirm' txt = 'Some of documents do not have revoke to confirm'
ValidationError(txt) ValidationError(txt)
devices = OrderedSet(data['devices'])
data['devices'] = devices
# Change the owner for every devices
# data['action'] == 'Revoke'
trade = data['action'].action
for dev in devices:
dev.reset_owner()
trade.lot.devices.difference_update(devices)

View File

@ -202,6 +202,19 @@ class ActionView(View):
confirm_revoke = trade_view.ConfirmRevokeView(json, resource_def, self.schema) confirm_revoke = trade_view.ConfirmRevokeView(json, resource_def, self.schema)
return confirm_revoke.post() return confirm_revoke.post()
if json['type'] == 'RevokeDocument':
revoke = trade_view.RevokeDocumentView(json, resource_def, self.schema)
return revoke.post()
if json['type'] == 'ConfirmDocument':
confirm = trade_view.ConfirmDocumentView(json, resource_def, self.schema)
return confirm.post()
if json['type'] == 'ConfirmRevokeDocument':
confirm_revoke = trade_view.ConfirmRevokeDocumentView(json, resource_def, self.schema)
return confirm_revoke.post()
# import pdb; pdb.set_trace()
a = resource_def.schema.load(json) a = resource_def.schema.load(json)
Model = db.Model._decl_class_registry.data[json['type']]() Model = db.Model._decl_class_registry.data[json['type']]()
action = Model(**a) action = Model(**a)

View File

@ -94,38 +94,41 @@ class TradeDocument(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"""
# import pdb; pdb.set_trace() confirm = 'Confirm'
confirm = 'ConfirmDocument' need_confirm = 'Need Confirmation'
to_confirm = 'To Confirm' double_confirm = 'Document Confirmed'
revoke = 'Revoke' revoke = 'Revoke'
revoke_pending = 'Revoke Pending'
confirm_revoke = 'Document Revoked'
if not self.actions: if not self.actions:
return return
actions = copy.copy(self.actions) ac = self.actions[-1]
actions = list(reversed(actions))
ac = actions[0]
if ac.type == revoke: if ac.type == 'ConfirmRevokeDocument':
# can to do revoke_confirmed
return confirm_revoke
if ac.type == 'RevokeDocument':
if ac.user == g.user:
# can todo revoke_pending
return revoke_pending
else:
# can to do confirm_revoke
return revoke return revoke
if ac.type == confirm: if ac.type == 'ConfirmDocument':
if ac.user == self.owner: if ac.user == self.owner:
return to_confirm if self.owner == g.user:
return 'Confirmed' # can to do revoke
return confirm
def last_action_of(self, *types): else:
"""Gets the last action of the given types. # can to do confirm
return need_confirm
:raise LookupError: Device has not an action of the given type. else:
""" # can to do revoke
try: return double_confirm
# noinspection PyTypeHints
actions = 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 _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)