resolve conflict
This commit is contained in:
commit
b2bd820d50
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "1.0.5-beta"
|
||||
__version__ = "1.0.6-beta"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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""")
|
||||
|
|
|
@ -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,22 +255,42 @@ class ActionView(View):
|
|||
action = Action.query.filter_by(id=id).one()
|
||||
return self.schema.jsonify(action)
|
||||
|
||||
def snapshot(self, snapshot_json: dict, resource_def):
|
||||
"""Performs a Snapshot.
|
||||
def transfer_ownership(self):
|
||||
"""Perform a InitTransfer action to change author_id of device"""
|
||||
pass
|
||||
|
||||
|
||||
See `Snapshot` section in docs for more info.
|
||||
"""
|
||||
# Note that if we set the device / components into the snapshot
|
||||
# model object, when we flush them to the db we will flush
|
||||
# snapshot, and we want to wait to flush snapshot at the end
|
||||
class SnapshotView():
|
||||
"""Performs a Snapshot.
|
||||
|
||||
device = snapshot_json.pop('device') # type: Computer
|
||||
See `Snapshot` section in docs for more info.
|
||||
"""
|
||||
# Note that if we set the device / components into the snapshot
|
||||
# model object, when we flush them to the db we will flush
|
||||
# snapshot, and we want to wait to flush snapshot at the end
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
Reference in a new issue