From a21018a2d20e457f0e2b555802322c3715004b51 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 11 Jul 2022 15:36:45 +0200 Subject: [PATCH 01/38] add binding relation --- .pre-commit-config.yaml | 4 ++-- .../versions/3e3a67f62972_placeholder_log.py | 5 +++-- .../versions/aeca9fb50cc6_add_placeholder.py | 5 ++++- ereuse_devicehub/parser/models.py | 1 - ereuse_devicehub/resources/device/models.py | 13 ++++++++++++- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e6bc1402..35bfc9bf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,10 @@ repos: - repo: https://github.com/psf/black - rev: 22.1.0 + rev: 22.6.0 hooks: - id: black - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.10.1 hooks: - id: isort - repo: https://github.com/PyCQA/flake8 diff --git a/ereuse_devicehub/migrations/versions/3e3a67f62972_placeholder_log.py b/ereuse_devicehub/migrations/versions/3e3a67f62972_placeholder_log.py index 1e1de004..f51b3749 100644 --- a/ereuse_devicehub/migrations/versions/3e3a67f62972_placeholder_log.py +++ b/ereuse_devicehub/migrations/versions/3e3a67f62972_placeholder_log.py @@ -49,17 +49,18 @@ def upgrade(): sa.Column('owner_id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint( ['placeholder_id'], - ['placeholder.id'], + [f'{get_inv()}.placeholder.id'], ), sa.ForeignKeyConstraint( ['owner_id'], ['common.user.id'], ), sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}', ) op.execute("CREATE SEQUENCE placeholders_log_seq START 1;") def downgrade(): - op.drop_table('placeholders_log') + op.drop_table('placeholders_log', schema=f'{get_inv()}') op.execute("DROP SEQUENCE placeholders_log_seq;") diff --git a/ereuse_devicehub/migrations/versions/aeca9fb50cc6_add_placeholder.py b/ereuse_devicehub/migrations/versions/aeca9fb50cc6_add_placeholder.py index 9a3b8e25..84137bab 100644 --- a/ereuse_devicehub/migrations/versions/aeca9fb50cc6_add_placeholder.py +++ b/ereuse_devicehub/migrations/versions/aeca9fb50cc6_add_placeholder.py @@ -46,12 +46,15 @@ def upgrade(): sa.Column('pallet', sa.Unicode(), nullable=True), sa.Column('info', citext.CIText(), nullable=True), sa.Column('device_id', sa.BigInteger(), nullable=False), + sa.Column('binding_id', sa.BigInteger(), nullable=True), sa.ForeignKeyConstraint(['device_id'], [f'{get_inv()}.device.id']), + sa.ForeignKeyConstraint(['binding_id'], [f'{get_inv()}.device.id']), sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}', ) op.execute("CREATE SEQUENCE placeholder_seq START 1;") def downgrade(): - op.drop_table('placeholder') + op.drop_table('placeholder', schema=f'{get_inv()}') op.execute("DROP SEQUENCE placeholder_seq;") diff --git a/ereuse_devicehub/parser/models.py b/ereuse_devicehub/parser/models.py index d8b4b62b..69cd574c 100644 --- a/ereuse_devicehub/parser/models.py +++ b/ereuse_devicehub/parser/models.py @@ -49,7 +49,6 @@ class SnapshotsLog(Thing): class PlaceholdersLog(Thing): """A Placeholder log.""" - __table_args__ = {'schema': ''} id = Column(BigInteger, Sequence('placeholders_log_seq'), primary_key=True) source = Column(CIText(), default='', nullable=True) type = Column(CIText(), default='', nullable=True) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 0dd308e4..7d8d570b 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -827,7 +827,6 @@ class DisplayMixin: class Placeholder(Thing): - __table_args__ = {'schema': ''} id = Column(BigInteger, Sequence('placeholder_seq'), primary_key=True) pallet = Column(Unicode(), nullable=True) phid = Column(Unicode(), nullable=False, default=create_phid) @@ -851,6 +850,18 @@ class Placeholder(Thing): ) device_id.comment = "datas of the placeholder" + binding_id = db.Column( + BigInteger, + db.ForeignKey(Device.id), + nullable=True, + ) + binding = db.relationship( + Device, + backref=backref('binding', lazy=True, uselist=False), + primaryjoin=device_id == Device.id, + ) + binding_id.comment = "binding placeholder with workbench device" + class Computer(Device): """A chassis with components inside that can be processed From e3ca632177f016d1ba43d9845814aa2f01fc1868 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 12 Jul 2022 11:23:55 +0200 Subject: [PATCH 02/38] add components as placeholder --- ereuse_devicehub/resources/device/models.py | 2 +- ereuse_devicehub/resources/device/sync.py | 37 ++++++++++++--------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 7d8d570b..0703359d 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -858,7 +858,7 @@ class Placeholder(Thing): binding = db.relationship( Device, backref=backref('binding', lazy=True, uselist=False), - primaryjoin=device_id == Device.id, + primaryjoin=binding_id == Device.id, ) binding_id.comment = "binding placeholder with workbench device" diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index dedaf499..ecf5690e 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -1,3 +1,4 @@ +import copy import difflib from contextlib import suppress from itertools import groupby @@ -234,6 +235,7 @@ class Sync: else: # Device is new and tags are not linked to a device device.tags.clear() # We don't want to add the transient dummy tags db.session.add(device) + self.create_placeholder(device) db_device = device db_device.tags |= ( tags # Union of tags the device had plus the (potentially) new ones @@ -278,22 +280,25 @@ class Sync: if hasattr(device, 'system_uuid') and device.system_uuid: db_device.system_uuid = device.system_uuid - if device.placeholder and db_device.placeholder: - db_device.placeholder.pallet = device.placeholder.pallet - db_device.placeholder.info = device.placeholder.info - db_device.placeholder.id_device_supplier = ( - device.placeholder.id_device_supplier - ) - db_device.sku = device.sku - db_device.image = device.image - db_device.brand = device.brand - db_device.generation = device.generation - db_device.variant = device.variant - db_device.version = device.version - db_device.width = device.width - db_device.height = device.height - db_device.depth = device.depth - db_device.weight = device.weight + @staticmethod + def create_placeholder(device: Device): + """If the device is new, we need create automaticaly a new placeholder""" + # import pdb; pdb.set_trace() + dict_device = copy.copy(device.__dict__) + dict_device.pop('_sa_instance_state') + dev_placeholder = device.__class__(**dict_device) + for c in device.components: + c_dict = copy.copy(c.__dict__) + c_dict.pop('_sa_instance_state') + c_placeholder = c.__class__(**c_dict) + c_placeholder.parent = dev_placeholder + component_placeholder = Placeholder(device=c_placeholder, binding=c) + db.session.add(c_placeholder) + db.session.add(component_placeholder) + + placeholder = Placeholder(device=dev_placeholder, binding=device) + db.session.add(dev_placeholder) + db.session.add(placeholder) @staticmethod def add_remove(device: Computer, components: Set[Component]) -> OrderedSet: From 2c6f83106881080e4cd79b92966ce5d3059948a7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 13 Jul 2022 11:23:18 +0200 Subject: [PATCH 03/38] add a placeholder when arrive a snapshot --- ereuse_devicehub/resources/device/sync.py | 15 +++++++-- tests/test_snapshot.py | 39 ++++++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index ecf5690e..df02d451 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -88,6 +88,7 @@ class Sync: # We only want to perform Add/Remove to not new components actions = self.add_remove(db_device, not_new_components) db_device.components = db_components + self.create_placeholder(db_device) return db_device, actions def execute_register_component( @@ -235,7 +236,6 @@ class Sync: else: # Device is new and tags are not linked to a device device.tags.clear() # We don't want to add the transient dummy tags db.session.add(device) - self.create_placeholder(device) db_device = device db_device.tags |= ( tags # Union of tags the device had plus the (potentially) new ones @@ -283,15 +283,26 @@ class Sync: @staticmethod def create_placeholder(device: Device): """If the device is new, we need create automaticaly a new placeholder""" - # import pdb; pdb.set_trace() + if device.binding: + return dict_device = copy.copy(device.__dict__) dict_device.pop('_sa_instance_state') + dict_device.pop('id', None) + dict_device.pop('devicehub_id', None) + dict_device.pop('actions_multiple', None) + dict_device.pop('actions_one', None) + dict_device.pop('components', None) dev_placeholder = device.__class__(**dict_device) for c in device.components: c_dict = copy.copy(c.__dict__) c_dict.pop('_sa_instance_state') + c_dict.pop('id', None) + c_dict.pop('devicehub_id', None) + c_dict.pop('actions_multiple', None) + c_dict.pop('actions_one', None) c_placeholder = c.__class__(**c_dict) c_placeholder.parent = dev_placeholder + c.parent = device component_placeholder = Placeholder(device=c_placeholder, binding=c) db.session.add(c_placeholder) db.session.add(component_placeholder) diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index a3183533..a6738711 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -1311,5 +1311,42 @@ def test_snapshot_check_tests_lite(user: UserClient): bodyLite, res = user.post(snapshot_lite, uri="/api/inventory/") assert res.status_code == 201 - SnapshotsLog.query.all() + assert SnapshotsLog.query.count() == 1 + m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one() + + +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_placeholder(user: UserClient): + """This check the structure of one placeholder generated automatically by a snapshot""" + snapshot_lite = file_json( + 'test_lite/2022-4-13-19-5_user@dhub.com_b27dbf43-b88a-4505-ae27-10de5a95919e.json' + ) + + bodyLite, res = user.post(snapshot_lite, uri="/api/inventory/") + assert res.status_code == 201 dev = m.Device.query.filter_by(devicehub_id=bodyLite['dhid']).one() + assert dev.placeholder is None + assert dev.binding.phid == '12' + assert len(dev.binding.device.components) == 11 + assert len(dev.components) == 11 + assert dev.binding.device.placeholder == dev.binding + assert dev.components != dev.binding.device.components + assert dev.binding.device.actions == [] + + +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_placeholder_actions(user: UserClient): + """This test the actions of a placeholder of one snapshot""" + s = yaml2json('erase-sectors.snapshot') + snap1, _ = user.post(s, res=Snapshot) + + dev = m.Device.query.filter_by(id=snap1['device']['id']).one() + assert dev.placeholder is None + assert dev.binding.phid == '4' + assert len(dev.binding.device.components) == 3 + assert len(dev.components) == 3 + assert dev.binding.device.placeholder == dev.binding + assert dev.components != dev.binding.device.components + assert dev.binding.device.actions == [] + assert len(dev.components[0].actions) == 3 + assert len(dev.binding.device.components[0].actions) == 0 From 1fa6e7512c913e358f1e8e4bdae52aadc85a2f26 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 15 Jul 2022 13:11:04 +0200 Subject: [PATCH 04/38] fix tag automatic only for placeholder --- ereuse_devicehub/resources/device/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 0703359d..3a946b1f 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1481,7 +1481,7 @@ def create_code_tag(mapper, connection, device): """ from ereuse_devicehub.resources.tag.model import Tag - if isinstance(device, Computer): + if isinstance(device, Computer) and not device.placeholder: tag = Tag(device_id=device.id, id=device.devicehub_id) db.session.add(tag) From 03fbfcb73b1b4b37fc72ec7ec7b56feffcc0f25b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 15 Jul 2022 16:47:00 +0200 Subject: [PATCH 05/38] add device placeholder only in the list of devices --- ereuse_devicehub/inventory/forms.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index 65d2b5c3..b00d8181 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -136,9 +136,13 @@ class FilterForm(FlaskForm): if self.lot_id: self.lot = self.lots.filter(Lot.id == self.lot_id).one() device_ids = (d.id for d in self.lot.devices) - self.devices = Device.query.filter(Device.id.in_(device_ids)) + self.devices = Device.query.filter(Device.id.in_(device_ids)).filter( + Device.binding == None + ) else: - self.devices = Device.query.filter(Device.owner_id == g.user.id) + self.devices = Device.query.filter(Device.owner_id == g.user.id).filter( + Device.binding == None + ) if self.only_unassigned: self.devices = self.devices.filter_by(lots=None) From 2b5ff4cb2f11651333fc1c539685e3d6a8219dfb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 15 Jul 2022 16:47:39 +0200 Subject: [PATCH 06/38] add placeholder details in detail of device --- ereuse_devicehub/inventory/views.py | 1 + ereuse_devicehub/templates/inventory/device_detail.html | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index 52a1a04a..d45b93ec 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -143,6 +143,7 @@ class DeviceDetailView(GenericMixin): self.context.update( { 'device': device, + 'placeholder': device.binding or device.placeholder, 'page_title': 'Device {}'.format(device.devicehub_id), } ) diff --git a/ereuse_devicehub/templates/inventory/device_detail.html b/ereuse_devicehub/templates/inventory/device_detail.html index 2da9cd31..bf3e8185 100644 --- a/ereuse_devicehub/templates/inventory/device_detail.html +++ b/ereuse_devicehub/templates/inventory/device_detail.html @@ -23,9 +23,15 @@
diff --git a/ereuse_devicehub/templates/inventory/unbinding.html b/ereuse_devicehub/templates/inventory/unbinding.html new file mode 100644 index 00000000..457b4a74 --- /dev/null +++ b/ereuse_devicehub/templates/inventory/unbinding.html @@ -0,0 +1,185 @@ +{% extends "ereuse_devicehub/base_site.html" %} +{% block main %} + +
+

{{ title }}

+ +
+ +
+
+
+ +
+
+ +
+
{{ title }}
+

Please check that the information is correct.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Basic DataInfo to be EnteredInfo to be Decoupled
PHID:{{ placeholder.phid or '' }}
Manufacturer:{{ device.manufacturer or '' }}{{ placeholder.device.manufacturer or '' }}
Model:{{ device.model or '' }}{{ placeholder.device.model or '' }}
Serial Number:{{ device.serial_number or '' }}{{ placeholder.device.serial_number or '' }}
Brand:{{ device.brand or '' }}{{ placeholder.device.brand or '' }}
Sku:{{ device.sku or '' }}{{ placeholder.device.sku or '' }}
Generation:{{ device.generation or '' }}{{ placeholder.device.generation or '' }}
Version:{{ device.version or '' }}{{ placeholder.device.version or '' }}
Weight:{{ device.weight or '' }}{{ placeholder.device.weight or '' }}
Width:{{ device.width or '' }}{{ placeholder.device.width or '' }}
Height:{{ device.height or '' }}{{ placeholder.device.height or '' }}
Depth:{{ device.depth or '' }}{{ placeholder.device.depth or '' }}
Color:{{ device.color or '' }}{{ placeholder.device.color or '' }}
Production date:{{ device.production_date or '' }}{{ placeholder.device.production_date or '' }}
Variant:{{ device.variant or '' }}{{ placeholder.device.variant or '' }}
+ +
+ + {% if placeholder.device.components or device.components %} +

Components

+ + + + + + + + + + + + + +
Info to be EnteredInfo to be Decoupled
+ {% for c in device.components %} + * {{ c.verbose_name }}
+ {% endfor %} +
+ {% for c in placeholder.device.components %} + * {{ c.verbose_name }}
+ {% endfor %} +
+ {% endif %} + +
+ + {% if placeholder.device.manual_actions or device.manual_actions %} +

Actions

+ + + + + + + + + + + + + +
Info to be EnteredInfo to be Decoupled
+ {% for a in device.manual_actions %} + * {{ a.t }}
+ {% endfor %} +
+ {% for a in placeholder.device.manual_actions %} + * {{ a.t }}
+ {% endfor %} +
+ {% endif %} + +
+
+ Cancel + +
+
+ +
+ +
+ +
+ +
+
+
+
+{% endblock main %} From 9c2d52a7f700d74f63e90cfec6d377c0f3a6bf5f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Aug 2022 12:41:31 +0200 Subject: [PATCH 32/38] fix cascade delete in placeholder --- ereuse_devicehub/inventory/views.py | 19 ++++++++++++------- ereuse_devicehub/resources/device/models.py | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ereuse_devicehub/inventory/views.py b/ereuse_devicehub/inventory/views.py index a26df083..09253c4f 100644 --- a/ereuse_devicehub/inventory/views.py +++ b/ereuse_devicehub/inventory/views.py @@ -1,5 +1,5 @@ -import csv import copy +import csv import logging import os from distutils.util import strtobool @@ -193,12 +193,14 @@ class BindingView(GenericMixin): if request.method == 'POST': old_placeholder = device.binding + old_device_placeholder = old_placeholder.device if old_placeholder.is_abstract: for plog in PlaceholdersLog.query.filter_by( placeholder_id=old_placeholder.id ): db.session.delete(plog) - db.session.delete(old_placeholder) + db.session.delete(old_device_placeholder) + device.binding = placeholder db.session.commit() next_url = url_for('inventory.device_details', id=dhid) @@ -230,7 +232,9 @@ class UnBindingView(GenericMixin): .one() ) if not placeholder.binding: - next_url = url_for('inventory.device_details', id=placeholder.device.devicehub_id) + next_url = url_for( + 'inventory.device_details', id=placeholder.device.devicehub_id + ) return flask.redirect(next_url) device = placeholder.binding @@ -239,10 +243,10 @@ class UnBindingView(GenericMixin): if request.method == 'POST': self.clone_device(device) - next_url = url_for('inventory.device_details', id=placeholder.device.devicehub_id) - messages.success( - 'Device "{}" unbind successfully!'.format(phid) + next_url = url_for( + 'inventory.device_details', id=placeholder.device.devicehub_id ) + messages.success('Device "{}" unbind successfully!'.format(phid)) return flask.redirect(next_url) self.context.update( @@ -258,7 +262,6 @@ class UnBindingView(GenericMixin): def clone_device(self, device): if device.binding.is_abstract: return - # import pdb; pdb.set_trace() dict_device = copy.copy(device.__dict__) dict_device.pop('_sa_instance_state') @@ -269,6 +272,8 @@ class UnBindingView(GenericMixin): dict_device.pop('components', None) dict_device.pop('tags', None) dict_device.pop('system_uuid', None) + dict_device.pop('binding', None) + dict_device.pop('placeholder', None) new_device = device.__class__(**dict_device) db.session.add(new_device) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index ae65b0a3..5707fe8b 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -33,6 +33,7 @@ from sqlalchemy_utils import ColorType from stdnum import imei, meid from teal.db import ( CASCADE_DEL, + CASCADE_OWN, POLYMORPHIC_ID, POLYMORPHIC_ON, URL, @@ -883,7 +884,7 @@ class Placeholder(Thing): ) device = db.relationship( Device, - backref=backref('placeholder', lazy=True, uselist=False), + backref=backref('placeholder', lazy=True, cascade="all, delete-orphan", uselist=False), primaryjoin=device_id == Device.id, ) device_id.comment = "datas of the placeholder" From 080fc039ecea3bd1712cd58d52b5a9d364f683d5 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Aug 2022 13:14:02 +0200 Subject: [PATCH 33/38] drop cascade own --- ereuse_devicehub/resources/device/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 5707fe8b..3b27b327 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -33,7 +33,6 @@ from sqlalchemy_utils import ColorType from stdnum import imei, meid from teal.db import ( CASCADE_DEL, - CASCADE_OWN, POLYMORPHIC_ID, POLYMORPHIC_ON, URL, From 83519219c751fc4208b023a8d1b70ee7f9510133 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Aug 2022 16:31:27 +0200 Subject: [PATCH 34/38] switch order of migration --- ...ceholder.py => 2b90b41a556a_add_owner_to_placeholder.py} | 4 ++-- ..._placeholders.py => d7ea9a3b2da1_create_placeholders.py} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename ereuse_devicehub/migrations/versions/{d7ea9a3b2da1_add_owner_to_placeholder.py => 2b90b41a556a_add_owner_to_placeholder.py} (97%) rename ereuse_devicehub/migrations/versions/{2b90b41a556a_create_placeholders.py => d7ea9a3b2da1_create_placeholders.py} (97%) diff --git a/ereuse_devicehub/migrations/versions/d7ea9a3b2da1_add_owner_to_placeholder.py b/ereuse_devicehub/migrations/versions/2b90b41a556a_add_owner_to_placeholder.py similarity index 97% rename from ereuse_devicehub/migrations/versions/d7ea9a3b2da1_add_owner_to_placeholder.py rename to ereuse_devicehub/migrations/versions/2b90b41a556a_add_owner_to_placeholder.py index fca1d0c0..c8a80e5a 100644 --- a/ereuse_devicehub/migrations/versions/d7ea9a3b2da1_add_owner_to_placeholder.py +++ b/ereuse_devicehub/migrations/versions/2b90b41a556a_add_owner_to_placeholder.py @@ -10,8 +10,8 @@ from alembic import context, op from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. -revision = 'd7ea9a3b2da1' -down_revision = '2b90b41a556a' +revision = '2b90b41a556a' +down_revision = '3e3a67f62972' branch_labels = None depends_on = None diff --git a/ereuse_devicehub/migrations/versions/2b90b41a556a_create_placeholders.py b/ereuse_devicehub/migrations/versions/d7ea9a3b2da1_create_placeholders.py similarity index 97% rename from ereuse_devicehub/migrations/versions/2b90b41a556a_create_placeholders.py rename to ereuse_devicehub/migrations/versions/d7ea9a3b2da1_create_placeholders.py index 8c4915dc..9e4a9dbe 100644 --- a/ereuse_devicehub/migrations/versions/2b90b41a556a_create_placeholders.py +++ b/ereuse_devicehub/migrations/versions/d7ea9a3b2da1_create_placeholders.py @@ -32,8 +32,8 @@ from ereuse_devicehub.resources.device.models import Computer, Device, Placehold from ereuse_devicehub.resources.lot.models import LotDevice # revision identifiers, used by Alembic. -revision = '2b90b41a556a' -down_revision = '3e3a67f62972' +revision = 'd7ea9a3b2da1' +down_revision = '2b90b41a556a' branch_labels = None depends_on = None @@ -76,7 +76,7 @@ def clone_device(device): new_c = clone_device(c) new_c.parent = new_device - placeholder = Placeholder(device=new_device, binding=device) + placeholder = Placeholder(device=new_device, binding=device, is_abstract=True, owner_id=device.owner_id) db.session.add(placeholder) tags = [x for x in device.tags] From 829266a80893557fe0900d2cb0ef01c2a78dffdb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Aug 2022 17:44:36 +0200 Subject: [PATCH 35/38] fix excess of line --- ereuse_devicehub/inventory/forms.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index cd91deb8..f795ecf0 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -137,11 +137,11 @@ class FilterForm(FlaskForm): self.lot = self.lots.filter(Lot.id == self.lot_id).one() device_ids = (d.id for d in self.lot.devices) self.devices = Device.query.filter(Device.id.in_(device_ids)).filter( - Device.binding == None + Device.binding==None ) else: self.devices = Device.query.filter(Device.owner_id == g.user.id).filter( - Device.binding == None + Device.binding==None ) if self.only_unassigned: self.devices = self.devices.filter_by(lots=None) @@ -1643,7 +1643,8 @@ class BindingForm(FlaskForm): return False if self.placeholder.binding: - txt = "This placeholder have a binding with other device. Before you need to do an unbinding with this other device." + txt = "This placeholder have a binding with other device. " + txt += "Before you need to do an unbinding with this other device." self.phid.errors = [txt] return False From 23ef1e2bae75869a836d26f7c1a97bd7acf3236c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Aug 2022 18:01:28 +0200 Subject: [PATCH 36/38] fix test basic --- tests/test_basic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_basic.py b/tests/test_basic.py index 6b890ea3..39b2ca25 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -75,6 +75,8 @@ def test_api_docs(client: Client): '/inventory/upload-placeholder/', '/inventory/lot/{lot_id}/upload-placeholder/', '/inventory/placeholder-logs/', + '/inventory/unbinding/{phid}/', + '/inventory/binding/{dhid}/{phid}/', '/labels/', '/labels/add/', '/labels/print', From beb687b9677e6aa406f937f02a74d8f3f1b960e2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 3 Aug 2022 16:00:25 +0200 Subject: [PATCH 37/38] add binding and unbinding tests --- ereuse_devicehub/inventory/forms.py | 4 +- tests/test_render_2_0.py | 190 +++++++++++++++++++++++++++- 2 files changed, 191 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/inventory/forms.py b/ereuse_devicehub/inventory/forms.py index f795ecf0..969df88c 100644 --- a/ereuse_devicehub/inventory/forms.py +++ b/ereuse_devicehub/inventory/forms.py @@ -137,11 +137,11 @@ class FilterForm(FlaskForm): self.lot = self.lots.filter(Lot.id == self.lot_id).one() device_ids = (d.id for d in self.lot.devices) self.devices = Device.query.filter(Device.id.in_(device_ids)).filter( - Device.binding==None + Device.binding == None ) else: self.devices = Device.query.filter(Device.owner_id == g.user.id).filter( - Device.binding==None + Device.binding == None ) if self.only_unassigned: self.devices = self.devices.filter_by(lots=None) diff --git a/tests/test_render_2_0.py b/tests/test_render_2_0.py index 2dc17883..49c151ab 100644 --- a/tests/test_render_2_0.py +++ b/tests/test_render_2_0.py @@ -14,7 +14,7 @@ from ereuse_devicehub.client import UserClient, UserClientFlask from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.resources.action.models import Snapshot -from ereuse_devicehub.resources.device.models import Device +from ereuse_devicehub.resources.device.models import Device, Placeholder from ereuse_devicehub.resources.lot.models import Lot from ereuse_devicehub.resources.user.models import User from tests import conftest @@ -2006,3 +2006,191 @@ def test_add_new_placeholder_from_lot(user3: UserClientFlask): assert dev.hid == 'laptop-samsung-lc27t55-aaaab' assert dev.placeholder.phid == 'ace' assert len(lot.devices) == 1 + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_manual_binding(user3: UserClientFlask): + # create placeholder manual + uri = '/inventory/device/add/' + + user3.get(uri) + data = { + 'csrf_token': generate_csrf(), + 'type': "Laptop", + 'phid': 'sid', + 'serial_number': "AAAAB", + 'model': "LC27T55", + 'manufacturer': "Samsung", + 'generation': 1, + 'weight': 0.1, + 'height': 0.1, + 'depth': 0.1, + 'id_device_supplier': "b2", + } + user3.post(uri, data=data) + dev = Device.query.one() + assert dev.hid == 'laptop-samsung-lc27t55-aaaab' + assert dev.placeholder.phid == 'sid' + assert dev.placeholder.is_abstract is False + + # add device from wb + snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + dev_wb = snap.device + uri = '/inventory/device/' + user3.get(uri) + + assert dev_wb.binding.is_abstract is True + assert dev_wb.hid == 'laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b' + assert dev_wb.binding.phid == '11' + old_placeholder = dev_wb.binding + + # page binding + dhid = dev_wb.devicehub_id + uri = f'/inventory/binding/{dhid}/sid/' + body, status = user3.get(uri) + assert status == '200 OK' + assert 'sid' in body + assert 'Confirm' in body + + # action binding + body, status = user3.post(uri, data={}) + assert status == '200 OK' + assert f"Device "{dhid}" bind successfully with sid!" in body + + # check new structure + assert dev_wb.binding.phid == 'sid' + assert dev_wb.binding.device == dev + assert Placeholder.query.filter_by(id=old_placeholder.id).first() is None + assert Device.query.filter_by(id=old_placeholder.device.id).first() is None + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_edit_and_binding(user3: UserClientFlask): + uri = '/inventory/device/add/' + user3.get(uri) + + data = { + 'csrf_token': generate_csrf(), + 'type': "Laptop", + 'serial_number': "AAAAB", + 'model': "LC27T55", + 'manufacturer': "Samsung", + 'generation': 1, + 'weight': 0.1, + 'height': 0.1, + 'depth': 0.1, + 'id_device_supplier': "b2", + } + user3.post(uri, data=data) + + snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + dev_wb = snap.device + uri = '/inventory/device/' + user3.get(uri) + + uri = '/inventory/device/edit/{}/'.format(dev_wb.binding.device.devicehub_id) + body, status = user3.get(uri) + assert status == '200 OK' + assert "Edit Device" in body + + data = { + 'csrf_token': generate_csrf(), + 'type': "Laptop", + 'serial_number': "AAAAC", + 'model': "LC27T56", + 'manufacturer': "Samsung", + 'generation': 1, + 'weight': 0.1, + 'height': 0.1, + 'depth': 0.1, + 'id_device_supplier': "a2", + } + assert dev_wb.binding.is_abstract is True + user3.post(uri, data=data) + assert dev_wb.binding.is_abstract is False + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_unbinding(user3: UserClientFlask): + # create placeholder manual + uri = '/inventory/device/add/' + + user3.get(uri) + data = { + 'csrf_token': generate_csrf(), + 'type': "Laptop", + 'phid': 'sid', + 'serial_number': "AAAAB", + 'model': "LC27T55", + 'manufacturer': "Samsung", + 'generation': 1, + 'weight': 0.1, + 'height': 0.1, + 'depth': 0.1, + 'id_device_supplier': "b2", + } + user3.post(uri, data=data) + dev = Device.query.one() + + # add device from wb + snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + dev_wb = snap.device + uri = '/inventory/device/' + user3.get(uri) + + old_placeholder = dev_wb.binding + + # page binding + dhid = dev_wb.devicehub_id + uri = f'/inventory/binding/{dhid}/sid/' + user3.get(uri) + + # action binding + assert dev.placeholder.binding is None + user3.post(uri, data={}) + assert dev.placeholder.binding == dev_wb + + # action unbinding + uri = '/inventory/unbinding/sid/' + body, status = user3.post(uri, data={}) + assert status == '200 OK' + assert 'Device "sid" unbind successfully!' in body + + # check new structure + + assert dev.placeholder.binding is None + assert dev_wb.binding.phid == '2' + assert old_placeholder.device.model == dev_wb.binding.device.model + assert old_placeholder.device != dev_wb.binding.device + assert Placeholder.query.filter_by(id=old_placeholder.id).first() is None + assert Device.query.filter_by(id=old_placeholder.device.id).first() is None + assert Placeholder.query.filter_by(id=dev_wb.binding.id).first() + assert Device.query.filter_by(id=dev_wb.binding.device.id).first() + assert Device.query.filter_by(id=dev.id).first() + assert Placeholder.query.filter_by(id=dev.placeholder.id).first() + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_unbindingnot_used(user3: UserClientFlask): + # add device from wb + snap = create_device(user3, 'real-eee-1001pxd.snapshot.12.json') + dev_wb = snap.device + uri = '/inventory/device/' + user3.get(uri) + + old_placeholder = dev_wb.binding + + # action unbinding + uri = '/inventory/unbinding/{}/'.format(dev_wb.binding.phid) + body, status = user3.post(uri, data={}) + assert status == '200 OK' + + # check new structure + assert dev_wb.binding == old_placeholder + assert Placeholder.query.filter_by(id=old_placeholder.id).first() + assert Device.query.filter_by(id=old_placeholder.device.id).first() + assert Device.query.filter_by(id=dev_wb.id).first() From 08d7012bd9282b09a0c074f8dc9e883a98639262 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 3 Aug 2022 16:03:09 +0200 Subject: [PATCH 38/38] CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a306f99f..658141b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ml). ## testing - [added] #312 Placeholder: new, edit, update. (manually and with excel). +- [added] #316 Placeholder: binding/unbinding. (manually). - [fixed] #313 Bump numpy from 1.21.6 to 1.22.0. - [fixed] #314 bugs create placeholder from lot. - [fixed] #317 bugs about exports placeholders.