resolve conflict

This commit is contained in:
Cayo Puigdefabregas 2021-04-29 17:04:25 +02:00
commit b2bd820d50
9 changed files with 83 additions and 214 deletions

View File

@ -6,10 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
ml).
## master
[1.0.4-beta]
[1.0.5-beta]
## testing
[1.0.5-beta]
[1.0.6-beta]
## [1.0.6-beta]
## [1.0.5-beta]
- [addend] #124 adding endpoint for extract the internal stats of use

View File

@ -1 +1 @@
__version__ = "1.0.5-beta"
__version__ = "1.0.6-beta"

View File

@ -80,16 +80,6 @@ def upgrade():
schema=f'{get_inv()}'
)
op.create_table('trade_note',
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('trade_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ),
sa.ForeignKeyConstraint(['trade_id'], [f'{get_inv()}.trade.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)
# ## User
op.add_column('user', sa.Column('active', sa.Boolean(), default=True, nullable=True),
schema='common')
@ -104,7 +94,6 @@ def upgrade():
def downgrade():
op.drop_table('confirm', schema=f'{get_inv()}')
op.drop_table('trade_note', schema=f'{get_inv()}')
op.drop_table('trade', schema=f'{get_inv()}')
op.create_table('trade',
sa.Column('shipping_date', sa.TIMESTAMP(timezone=True), nullable=True,

View File

@ -264,11 +264,6 @@ class CancelTradeDef(ActionDef):
SCHEMA = schemas.CancelTrade
class TradeNoteDef(ActionDef):
VIEW = None
SCHEMA = schemas.TradeNote
class ToDisposeProductDef(ActionDef):
VIEW = None
SCHEMA = schemas.ToDisposeProduct

View File

@ -1433,18 +1433,6 @@ class CancelReservation(Organize):
"""The act of cancelling a reservation."""
class TradeNote(JoinedTableMixin, ActionWithMultipleDevices):
"""Note add to one trade"""
trade_id = db.Column(UUID(as_uuid=True),
db.ForeignKey('trade.id'),
nullable=False)
trade = db.relationship('Trade',
backref=backref('notes',
uselist=True,
lazy=True),
primaryjoin='TradeNote.trade_id == Trade.id')
class Confirm(JoinedTableMixin, ActionWithMultipleDevices):
"""Users confirm the offer and change it to trade"""
revoke = Column(Boolean, default=False, nullable=False)

View File

@ -457,11 +457,6 @@ class CancelReservation(Organize):
__doc__ = m.CancelReservation.__doc__
class TradeNote(ActionWithMultipleDevices):
__doc__ = m.TradeNote.__doc__
trade = NestedOn('Trade', only_query='id')
class Confirm(ActionWithMultipleDevices):
__doc__ = m.Confirm.__doc__
revoke = Boolean(required=False, description="""If you want revoke an other confirmation""")

View File

@ -8,6 +8,7 @@ from distutils.version import StrictVersion
from uuid import UUID
from flask import current_app as app, request, g
from flask.wrappers import Response
from sqlalchemy.util import OrderedSet
from teal.marshmallow import ValidationError
from teal.resource import View
@ -225,24 +226,23 @@ class ActionView(View):
# defs
resource_def = app.resources[json['type']]
if json['type'] == Snapshot.t:
tmp_snapshots = app.config['TMP_SNAPSHOTS']
path_snapshot = save_json(json, tmp_snapshots, g.user.email)
json.pop('debug', None)
a = resource_def.schema.load(json)
response = self.snapshot(a, resource_def)
move_json(tmp_snapshots, path_snapshot, g.user.email)
return response
snapshot = SnapshotView(json, resource_def, self.schema)
return snapshot.post()
if json['type'] == VisualTest.t:
pass
# TODO JN add compute rate with new visual test and old components device
if json['type'] == InitTransfer.t:
return self.transfer_ownership()
# import pdb; pdb.set_trace()
if json['type'] == Trade.t:
offer = OfferView(json, resource_def, self.schema)
return offer.post()
a = resource_def.schema.load(json)
Model = db.Model._decl_class_registry.data[json['type']]()
action = Model(**a)
if json['type'] == Trade.t:
return self.offer(action)
db.session.add(action)
db.session().final_flush()
ret = self.schema.jsonify(action)
@ -255,7 +255,12 @@ class ActionView(View):
action = Action.query.filter_by(id=id).one()
return self.schema.jsonify(action)
def snapshot(self, snapshot_json: dict, resource_def):
def transfer_ownership(self):
"""Perform a InitTransfer action to change author_id of device"""
pass
class SnapshotView():
"""Performs a Snapshot.
See `Snapshot` section in docs for more info.
@ -264,13 +269,28 @@ class ActionView(View):
# model object, when we flush them to the db we will flush
# snapshot, and we want to wait to flush snapshot at the end
device = snapshot_json.pop('device') # type: Computer
def __init__(self, snapshot_json: dict, resource_def, schema):
self.schema = schema
self.snapshot_json = snapshot_json
self.resource_def = resource_def
self.tmp_snapshots = app.config['TMP_SNAPSHOTS']
self.path_snapshot = save_json(snapshot_json, self.tmp_snapshots, g.user.email)
snapshot_json.pop('debug', None)
self.snapshot_json = resource_def.schema.load(snapshot_json)
self.response = self.build()
move_json(self.tmp_snapshots, self.path_snapshot, g.user.email)
def post(self):
return self.response
def build(self):
device = self.snapshot_json.pop('device') # type: Computer
components = None
if snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid):
components = snapshot_json.pop('components', None) # type: List[Component]
if self.snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid):
components = self.snapshot_json.pop('components', None) # type: List[Component]
if isinstance(device, Computer) and device.hid:
device.add_mac_to_hid(components_snap=components)
snapshot = Snapshot(**snapshot_json)
snapshot = Snapshot(**self.snapshot_json)
# Remove new actions from devices so they don't interfere with sync
actions_device = set(e for e in device.actions_one)
@ -282,7 +302,7 @@ class ActionView(View):
assert not device.actions_one
assert all(not c.actions_one for c in components) if components else True
db_device, remove_actions = resource_def.sync.run(device, components)
db_device, remove_actions = self.resource_def.sync.run(device, components)
del device # Do not use device anymore
snapshot.device = db_device
@ -324,33 +344,37 @@ class ActionView(View):
db.session.commit()
return ret
def transfer_ownership(self):
"""Perform a InitTransfer action to change author_id of device"""
pass
def offer(self, offer: Trade):
self.create_first_confirmation(offer)
self.create_phantom_account(offer)
db.session.add(offer)
self.create_automatic_trade(offer)
class OfferView():
"""Handler for manager the offer/trade action register from post"""
def __init__(self, data, resource_def, schema):
self.schema = schema
a = resource_def.schema.load(data)
self.offer = Trade(**a)
self.create_first_confirmation()
self.create_phantom_account()
db.session.add(self.offer)
self.create_automatic_trade()
def post(self):
db.session().final_flush()
ret = self.schema.jsonify(offer)
ret = self.schema.jsonify(self.offer)
ret.status_code = 201
db.session.commit()
return ret
def create_first_confirmation(self, offer: Trade) -> None:
def create_first_confirmation(self) -> None:
"""Do the first confirmation for the user than do the action"""
# check than the user than want to do the action is one of the users
# involved in the action
assert g.user.id in [offer.user_from_id, offer.user_to_id]
assert g.user.id in [self.offer.user_from_id, self.offer.user_to_id]
confirm = Confirm(user=g.user, action=offer, devices=offer.devices)
confirm = Confirm(user=g.user, action=self.offer, devices=self.offer.devices)
db.session.add(confirm)
def create_phantom_account(self, offer) -> None:
def create_phantom_account(self) -> None:
"""
If exist both users not to do nothing
If exist from but not to:
@ -360,50 +384,49 @@ class ActionView(View):
The same if exist to but not from
"""
if offer.user_from_id and offer.user_to_id:
if self.offer.user_from_id and self.offer.user_to_id:
return
if offer.user_from_id and not offer.user_to_id:
assert g.user.id == offer.user_from_id
email = "{}_{}@dhub.com".format(str(offer.user_from_id), offer.code)
if self.offer.user_from_id and not self.offer.user_to_id:
assert g.user.id == self.offer.user_from_id
email = "{}_{}@dhub.com".format(str(self.offer.user_from_id), self.offer.code)
users = User.query.filter_by(email=email)
if users.first():
user = users.first()
offer.user_to = user
self.offer.user_to = user
return
user = User(email=email, password='', active=False, phantom=True)
db.session.add(user)
offer.user_to = user
self.offer.user_to = user
if not offer.user_from_id and offer.user_to_id:
email = "{}_{}@dhub.com".format(str(offer.user_to_id), offer.code)
if not self.offer.user_from_id and self.offer.user_to_id:
email = "{}_{}@dhub.com".format(str(self.offer.user_to_id), self.offer.code)
users = User.query.filter_by(email=email)
if users.first():
user = users.first()
offer.user_from = user
self.offer.user_from = user
return
user = User(email=email, password='', active=False, phantom=True)
db.session.add(user)
offer.user_from = user
self.offer.user_from = user
def create_automatic_trade(self, offer: Trade) -> None:
def create_automatic_trade(self) -> None:
# not do nothing if it's neccesary confirmation explicity
if offer.confirm:
if self.offer.confirm:
return
# Change the owner for every devices
for dev in offer.devices:
dev.owner = offer.user_to
for dev in self.offer.devices:
dev.owner = self.offer.user_to
if hasattr(dev, 'components'):
for c in dev.components:
c.owner = offer.user_to
c.owner = self.offer.user_to
# Create a new Confirmation for the user who does not perform the action
user = offer.user_from
if g.user == offer.user_from:
user = offer.user_to
confirm = Confirm(user=user, action=offer, devices=offer.devices)
user = self.offer.user_from
if g.user == self.offer.user_from:
user = self.offer.user_to
confirm = Confirm(user=user, action=self.offer, devices=self.offer.devices)
db.session.add(confirm)

View File

@ -15,7 +15,6 @@ from ereuse_devicehub.query import things_response
from ereuse_devicehub.resources.deliverynote.models import Deliverynote
from ereuse_devicehub.resources.device.models import Device, Computer
from ereuse_devicehub.resources.lot.models import Lot, Path
from ereuse_devicehub.resources.action.models import TradeNote
class LotFormat(Enum):
@ -225,32 +224,11 @@ class LotDeviceView(LotBaseChildrenView):
id = ma.fields.List(ma.fields.Integer())
def _post(self, lot: Lot, ids: Set[int]):
if lot.trade:
lot_device_ids = [d.id for d in lot.devices]
new_device_ids = {d for d in ids if not d in lot_device_ids}
devices = set(Device.query.filter(Device.id.in_(new_device_ids)).all())
txt = 'Adding new device in lot of trade {}'.format(lot.trade.id)
note = TradeNote(description=txt,
devices=devices,
trade=lot.trade)
db.session.add(note)
lot.devices.update(Device.query.filter(Device.id.in_(ids)))
if lot.trade:
lot.trade.devices = lot.devices
def _delete(self, lot: Lot, ids: Set[int]):
if lot.trade:
devices = set(Device.query.filter(Device.id.in_(ids)).all())
txt = 'Removing device from lot of trade {}'.format(lot.trade.id)
note = TradeNote(description=txt,
devices=devices,
trade=lot.trade)
db.session.add(note)
lot.devices.difference_update(Device.query.filter(Device.id.in_(ids)))
if lot.trade:
lot.trade.devices = lot.devices

View File

@ -987,50 +987,6 @@ def test_offer_without_devices(user: UserClient):
# no there are transfer of devices
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_automatic_tradenote(user: UserClient, user2: UserClient):
"""Check than there are one note when one device is insert in one trade lot"""
lot, _ = user.post({'name': 'MyLot'}, res=Lot)
request_post = {
'type': 'Trade',
'devices': [],
'userFrom': user.email,
'userTo': user2.email,
'price': 10,
'date': "2020-12-01T02:00:00+00:00",
'documentID': '1',
'lot': lot['id'],
'confirm': True,
}
user.post(res=models.Action, data=request_post)
trade = models.Trade.query.one()
assert trade.notes == []
snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
device = Device.query.filter_by(id=snapshot['device']['id']).one()
# add one device
lot, _ = user.post({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=[('id', device.id)])
assert len(trade.notes) == 1
assert trade.notes[0].devices[0] == device
# remove one device
lot, _ = user.delete({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=[('id', device.id)],
status=200)
assert len(trade.notes) == 2
assert trade.notes[0].devices[0] == device
assert trade.notes[0].devices[0] == trade.notes[1].devices[0]
assert trade.devices == OrderedSet()
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.auth_app_context.__name__)
def test_price_custom():
@ -1082,63 +1038,6 @@ def test_erase_physical():
db.session.commit()
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_endpoint_tradenote(user: UserClient, user2: UserClient):
"""Check the normal creation and visualization of one trade note"""
lot, _ = user.post({'name': 'MyLot'}, res=Lot)
request_post = {
'type': 'Trade',
'devices': [],
'userFrom': user.email,
'userTo': user2.email,
'price': 10,
'date': "2020-12-01T02:00:00+00:00",
'documentID': '1',
'lot': lot['id'],
'confirm': True,
}
user.post(res=models.Action, data=request_post)
trade = models.Trade.query.one()
snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot)
device = Device.query.filter_by(id=snapshot['device']['id']).one()
# add one device
lot, _ = user.post({},
res=Lot,
item='{}/devices'.format(lot['id']),
query=[('id', device.id)])
txt = 'Text of Note'
request_post = {
'type': 'TradeNote',
'description': txt,
'devices': [device.id],
'trade': trade.id,
}
tradeNote, _ = user.post(res=models.Action, data=request_post)
assert tradeNote['devices'][0]['id'] == device.id
assert tradeNote['description'] == txt
assert tradeNote['author']['email'] == user.email
txt2 = 'Text of Note2'
request_post2 = {
'type': 'TradeNote',
'description': txt2,
'devices': [device.id],
'trade': trade.id,
}
tradeNote2, _ = user.post(res=models.Action, data=request_post2)
assert tradeNote2['description'] == txt2
tradeNote3, _ = user.get(res=models.Action, item=tradeNote2['id'])
assert tradeNote3['id'] == tradeNote2['id']
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_endpoint_confirm(user: UserClient, user2: UserClient):