From 39dc489cb3c132774a4f38a91a7c3f9a4d0a0eb5 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 22 Apr 2021 13:04:38 +0200 Subject: [PATCH 1/5] clean ActionView with more classes --- ereuse_devicehub/resources/action/views.py | 73 +++++++++++++--------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index e71cddce..286b13f2 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -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 @@ -15,6 +16,8 @@ from teal.db import ResourceNotFound from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response +from ereuse_devicehub.resources.action.schemas import Action as s_Action +from ereuse_devicehub.resources.action.schemas import Trade as s_Trade from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, InitTransfer, Live, Allocate, Deallocate, Trade, Confirm) @@ -251,11 +254,12 @@ class ActionView(View): # TODO JN add compute rate with new visual test and old components device if json['type'] == InitTransfer.t: return self.transfer_ownership() + if json['type'] == Trade.t: + offer = OfferView(json) + 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) @@ -340,30 +344,37 @@ class ActionView(View): 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): + a = s_Trade().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 = s_Action().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, trade=offer, devices=offer.devices) + confirm = Confirm(user=g.user, trade=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: @@ -373,49 +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, trade=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, trade=self.offer, devices=self.offer.devices) db.session.add(confirm) From e2fbe87c6ae5f2f2a56ce6e2611cf551a9912c13 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 22 Apr 2021 13:40:45 +0200 Subject: [PATCH 2/5] clean actionView of Snapshot section put in other class --- ereuse_devicehub/resources/action/views.py | 72 +++++++++++++--------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 286b13f2..56d5882f 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -16,8 +16,6 @@ from teal.db import ResourceNotFound from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response -from ereuse_devicehub.resources.action.schemas import Action as s_Action -from ereuse_devicehub.resources.action.schemas import Trade as s_Trade from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, InitTransfer, Live, Allocate, Deallocate, Trade, Confirm) @@ -242,21 +240,20 @@ 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() + if json['type'] == Trade.t: - offer = OfferView(json) + 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) @@ -272,22 +269,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) @@ -299,7 +316,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 @@ -341,16 +358,13 @@ class ActionView(View): db.session.commit() return ret - def transfer_ownership(self): - """Perform a InitTransfer action to change author_id of device""" - pass - class OfferView(): """Handler for manager the offer/trade action register from post""" - def __init__(self, data): - a = s_Trade().load(data) + 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() @@ -359,7 +373,7 @@ class OfferView(): def post(self): db.session().final_flush() - ret = s_Action().jsonify(self.offer) + ret = self.schema.jsonify(self.offer) ret.status_code = 201 db.session.commit() return ret From faf45e118b43f9fcea30f8c353db2ba9bd3a1413 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 27 Apr 2021 21:33:38 +0200 Subject: [PATCH 3/5] upgrade version to 1.0.6b --- CHANGELOG.md | 6 ++++-- ereuse_devicehub/__init__.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c3a696..3213330a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/ereuse_devicehub/__init__.py b/ereuse_devicehub/__init__.py index 53f0b176..eeacf9dd 100644 --- a/ereuse_devicehub/__init__.py +++ b/ereuse_devicehub/__init__.py @@ -1 +1 @@ -__version__ = "1.0.5-beta" +__version__ = "1.0.6-beta" From 76271ce4303cfd4a908eddb38328524dcdcd142b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 29 Apr 2021 11:25:17 +0200 Subject: [PATCH 4/5] drop tradeNotes --- .../51439cf24be8_change_trade_action.py | 13 +---------- ereuse_devicehub/resources/action/models.py | 12 ---------- ereuse_devicehub/resources/lot/views.py | 22 ------------------- 3 files changed, 1 insertion(+), 46 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/51439cf24be8_change_trade_action.py b/ereuse_devicehub/migrations/versions/51439cf24be8_change_trade_action.py index 8578968b..b5939e2d 100644 --- a/ereuse_devicehub/migrations/versions/51439cf24be8_change_trade_action.py +++ b/ereuse_devicehub/migrations/versions/51439cf24be8_change_trade_action.py @@ -14,7 +14,7 @@ import citext # revision identifiers, used by Alembic. revision = '51439cf24be8' -down_revision = '8cb91ad1cc40' +down_revision = '8d34480c82c4' branch_labels = None depends_on = None @@ -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, diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index cc3cc3fc..855e8fc8 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -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""" user_id = db.Column(UUID(as_uuid=True), diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index ade50e07..7f057fd3 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -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 From e4b1fc0eece5343f434fc872cd4e9d122ca7ffcb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 29 Apr 2021 11:48:53 +0200 Subject: [PATCH 5/5] drop test tradenotes --- tests/test_action.py | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index 3914430e..0c560189 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -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_note_to_trade(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():