From ab1d268f14f24eb8633df39bd7f7163f1008b9e6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 27 Oct 2020 19:12:46 +0100 Subject: [PATCH 01/10] rebuild the query for more post structured --- ereuse_devicehub/resources/device/definitions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/device/definitions.py b/ereuse_devicehub/resources/device/definitions.py index 47f276e2..7960efad 100644 --- a/ereuse_devicehub/resources/device/definitions.py +++ b/ereuse_devicehub/resources/device/definitions.py @@ -27,11 +27,13 @@ class DeviceDef(Resource): url_prefix, subdomain, url_defaults, root_path, cli_commands) device_merge = DeviceMergeView.as_view('merge-devices', definition=self, auth=app.auth) + if self.AUTH: device_merge = app.auth.requires_auth(device_merge) - self.add_url_rule('/<{}:{}>/merge/'.format(self.ID_CONVERTER.value, self.ID_NAME), - view_func=device_merge, - methods={'POST'}) + + path = '/<{value}:dev1_id>/merge/<{value}:dev2_id>'.format(value=self.ID_CONVERTER.value) + + self.add_url_rule(path, view_func=device_merge, methods={'POST'}) class ComputerDef(DeviceDef): From 19279acaeb5da113be0391a831261bd49f700045 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 27 Oct 2020 19:13:31 +0100 Subject: [PATCH 02/10] clean view of merge --- ereuse_devicehub/resources/device/views.py | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py index 8f16b12d..5eb45eb1 100644 --- a/ereuse_devicehub/resources/device/views.py +++ b/ereuse_devicehub/resources/device/views.py @@ -170,35 +170,29 @@ class DeviceView(View): class DeviceMergeView(View): """View for merging two devices - Ex. ``device//merge/id=X``. + Ex. ``device//merge/``. """ - class FindArgs(MarshmallowSchema): - id = fields.Integer() + def post(self, dev1_id: int, dev2_id: int): + device = self.merge_devices(dev1_id, dev2_id) - def get_merge_id(self) -> uuid.UUID: - args = self.QUERY_PARSER.parse(self.find_args, request, locations=('querystring',)) - return args['id'] - - def post(self, id: uuid.UUID): - device = Device.query.filter_by(id=id).one() - with_device = Device.query.filter_by(id=self.get_merge_id()).one() - self.merge_devices(device, with_device) - - db.session().final_flush() ret = self.schema.jsonify(device) ret.status_code = 201 db.session.commit() return ret - def merge_devices(self, base_device, with_device): - """Merge the current device with `with_device` by - adding all `with_device` actions under the current device. + @auth.Auth.requires_auth + def merge_devices(self, dev1_id, dev2_id): + """Merge the current device with `with_device` (dev2_id) by + adding all `with_device` actions under the current device, (dev1_id). This operation is highly costly as it forces refreshing many models in session. """ + # base_device = Device.query.filter_by(id=dev1_id, owner_id=g.user.id).one() + base_device = Device.query.filter_by(id=dev1_id).one() + with_device = Device.query.filter_by(id=dev2_id).one() snapshots = sorted( filterfalse(lambda x: not isinstance(x, actions.Snapshot), (base_device.actions + with_device.actions))) workbench_snapshots = [s for s in snapshots if @@ -222,14 +216,20 @@ class DeviceMergeView(View): base_device.actions_multiple.add(action) # Keeping the components of latest SnapshotWorkbench - base_device.components = latest_snapshotworkbench_device.components + # base_device.components = latest_snapshotworkbench_device.components + base_device.components = with_device.components # Properties from latest Snapshot - base_device.type = latest_snapshot_device.type - base_device.hid = latest_snapshot_device.hid - base_device.manufacturer = latest_snapshot_device.manufacturer - base_device.model = latest_snapshot_device.model - base_device.chassis = latest_snapshot_device.chassis + + base_device.type = with_device.type + base_device.hid = with_device.hid + base_device.manufacturer = with_device.manufacturer + base_device.model = with_device.model + base_device.chassis = with_device.chassis + + db.session().add(base_device) + db.session().final_flush() + return base_device class ManufacturerView(View): From 889ee84f6aedc59df1001dbfe48b56360562bdbc Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 27 Oct 2020 19:14:23 +0100 Subject: [PATCH 03/10] base of test merge --- tests/test_merge.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/test_merge.py diff --git a/tests/test_merge.py b/tests/test_merge.py new file mode 100644 index 00000000..d7be984f --- /dev/null +++ b/tests/test_merge.py @@ -0,0 +1,31 @@ +import datetime +from uuid import UUID +from flask import g + +import pytest +from ereuse_devicehub.client import Client, UserClient +from ereuse_devicehub.devicehub import Devicehub +from ereuse_devicehub.resources.action import models as m +from ereuse_devicehub.resources.device import models as d +from tests import conftest +from tests.conftest import file as import_snap + + +@pytest.mark.mvp +def test_simple_merge(app: Devicehub, user: UserClient): + snapshot1, _ = user.post(import_snap('basic.snapshot'), res=m.Snapshot) + snapshot2, _ = user.post(import_snap('real-eee-1001pxd.snapshot.12'), res=m.Snapshot) + pc1_id = snapshot1['device']['id'] + pc2_id = snapshot2['device']['id'] + + # import pdb; pdb.set_trace() + with app.app_context(): + pc1_1 = d.Device.query.filter_by(id=snapshot1['device']['id']).one() + pc2_1 = d.Device.query.filter_by(id=snapshot2['device']['id']).one() + + result, _ = user.post({'id': 1}, uri='/devices/%d/merge/%d' % (pc1_id, pc2_id), status=201) + + pc1_2 = d.Device.query.filter_by(id=snapshot1['device']['id']).one() + pc2_2 = d.Device.query.filter_by(id=snapshot2['device']['id']).one() + + From 0106728e4f16f5e0ea30debed27f6a4307829570 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 28 Oct 2020 13:29:45 +0100 Subject: [PATCH 04/10] complet test for basic manual merge --- tests/test_merge.py | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/test_merge.py b/tests/test_merge.py index d7be984f..39cce912 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -13,19 +13,37 @@ from tests.conftest import file as import_snap @pytest.mark.mvp def test_simple_merge(app: Devicehub, user: UserClient): - snapshot1, _ = user.post(import_snap('basic.snapshot'), res=m.Snapshot) - snapshot2, _ = user.post(import_snap('real-eee-1001pxd.snapshot.12'), res=m.Snapshot) + snapshot1, _ = user.post(import_snap('real-custom.snapshot.11'), res=m.Snapshot) + snapshot2, _ = user.post(import_snap('real-hp.snapshot.11'), res=m.Snapshot) pc1_id = snapshot1['device']['id'] pc2_id = snapshot2['device']['id'] - # import pdb; pdb.set_trace() with app.app_context(): - pc1_1 = d.Device.query.filter_by(id=snapshot1['device']['id']).one() - pc2_1 = d.Device.query.filter_by(id=snapshot2['device']['id']).one() - - result, _ = user.post({'id': 1}, uri='/devices/%d/merge/%d' % (pc1_id, pc2_id), status=201) + pc1 = d.Device.query.filter_by(id=pc1_id).one() + pc2 = d.Device.query.filter_by(id=pc2_id).one() + n_actions1 = len(pc1.actions) + n_actions2 = len(pc2.actions) + action1 = pc1.actions[0] + action2 = pc2.actions[0] + assert not action2 in pc1.actions - pc1_2 = d.Device.query.filter_by(id=snapshot1['device']['id']).one() - pc2_2 = d.Device.query.filter_by(id=snapshot2['device']['id']).one() + components1 = [com for com in pc1.components] + components2 = [com for com in pc2.components] + components1_excluded = [com for com in pc1.components if not com in components2] + assert pc1.hid != pc2.hid + uri = '/devices/%d/merge/%d' % (pc1_id, pc2_id) + result, _ = user.post({'id': 1}, uri=uri, status=201) + + assert pc1.hid == pc2.hid + assert action1 in pc1.actions + assert action2 in pc1.actions + assert len(pc1.actions) == n_actions1 + n_actions2 + assert set(pc2.components) == set() + + for com in components2: + assert com in pc1.components + + for com in components1_excluded: + assert not com in pc1.components From fe3f038218c27241189e6fb3dbd89d610683660c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 28 Oct 2020 13:30:22 +0100 Subject: [PATCH 05/10] refactoring and fixing some problems of manual merge --- ereuse_devicehub/resources/device/views.py | 73 +++++++++++++--------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py index 5eb45eb1..8ea09d7e 100644 --- a/ereuse_devicehub/resources/device/views.py +++ b/ereuse_devicehub/resources/device/views.py @@ -6,10 +6,13 @@ import marshmallow from flask import g, current_app as app, render_template, request, Response from flask.json import jsonify from flask_sqlalchemy import Pagination +from sqlalchemy.util import OrderedSet from marshmallow import fields, fields as f, validate as v, Schema as MarshmallowSchema from teal import query +from teal.db import ResourceNotFound from teal.cache import cache from teal.resource import View +from teal.marshmallow import ValidationError from ereuse_devicehub import auth from ereuse_devicehub.db import db @@ -183,7 +186,7 @@ class DeviceMergeView(View): return ret @auth.Auth.requires_auth - def merge_devices(self, dev1_id, dev2_id): + def merge_devices(self, dev1_id: int, dev2_id: int) -> Device: """Merge the current device with `with_device` (dev2_id) by adding all `with_device` actions under the current device, (dev1_id). @@ -191,45 +194,57 @@ class DeviceMergeView(View): many models in session. """ # base_device = Device.query.filter_by(id=dev1_id, owner_id=g.user.id).one() - base_device = Device.query.filter_by(id=dev1_id).one() - with_device = Device.query.filter_by(id=dev2_id).one() - snapshots = sorted( - filterfalse(lambda x: not isinstance(x, actions.Snapshot), (base_device.actions + with_device.actions))) - workbench_snapshots = [s for s in snapshots if - s.software == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid)] - latest_snapshot_device = [d for d in (base_device, with_device) if d.id == snapshots[-1].device.id][0] - latest_snapshotworkbench_device = \ - [d for d in (base_device, with_device) if d.id == workbench_snapshots[-1].device.id][0] - # Adding actions of with_device - with_actions_one = [a for a in with_device.actions if isinstance(a, actions.ActionWithOneDevice)] - with_actions_multiple = [a for a in with_device.actions if isinstance(a, actions.ActionWithMultipleDevices)] + self.base_device = Device.query.filter_by(id=dev1_id).one() + self.with_device = Device.query.filter_by(id=dev2_id).one() + if not self.base_device.type == self.with_device.type: + # Validation than we are speaking of the same kind of devices + raise ValidationError('The devices is not the same type.') + + # Adding actions of self.with_device + with_actions_one = [a for a in self.with_device.actions + if isinstance(a, actions.ActionWithOneDevice)] + with_actions_multiple = [a for a in self.with_device.actions + if isinstance(a, actions.ActionWithMultipleDevices)] + + # Moving the tags from `with_device` to `base_device` + # Union of tags the device had plus the (potentially) new ones + self.base_device.tags |= self.with_device.tags + self.with_device.tags.clear() # We don't want to add the transient dummy tags + # db.session.add(self.with_device) + + # Moving the actions from `with_device` to `base_device` for action in with_actions_one: if action.parent: - action.parent = base_device + action.parent = self.base_device else: - base_device.actions_one.add(action) + self.base_device.actions_one.add(action) for action in with_actions_multiple: if action.parent: - action.parent = base_device + action.parent = self.base_device else: - base_device.actions_multiple.add(action) + self.base_device.actions_multiple.add(action) - # Keeping the components of latest SnapshotWorkbench - # base_device.components = latest_snapshotworkbench_device.components - base_device.components = with_device.components + # Keeping the components of with_device + components = OrderedSet(c for c in self.with_device.components) + self.base_device.components = components - # Properties from latest Snapshot + # Properties from with_device + self.merge() - base_device.type = with_device.type - base_device.hid = with_device.hid - base_device.manufacturer = with_device.manufacturer - base_device.model = with_device.model - base_device.chassis = with_device.chassis - - db.session().add(base_device) + db.session().add(self.base_device) db.session().final_flush() - return base_device + return self.base_device + + def merge(self): + """Copies the physical properties of the base_device to the with_device. + This method mutates base_device. + """ + for field_name, value in self.with_device.physical_properties.items(): + if value is not None: + setattr(self.base_device, field_name, value) + + self.base_device.hid = self.with_device.hid class ManufacturerView(View): From 3af8880bcd97c36804299797ef391e254318d13a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 28 Oct 2020 21:57:24 +0100 Subject: [PATCH 06/10] fixed endpoints of basic test --- tests/test_basic.py | 106 ++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index fe3dd1da..dc60cc19 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -30,76 +30,76 @@ def test_api_docs(client: Client): assert set(docs['paths'].keys()) == { '/actions/', '/apidocs', - '/batteries/{id}/merge/', - '/bikes/{id}/merge/', - '/cameras/{id}/merge/', - '/cellphones/{id}/merge/', - '/components/{id}/merge/', - '/computer-accessories/{id}/merge/', - '/computer-monitors/{id}/merge/', - '/computers/{id}/merge/', - '/cookings/{id}/merge/', - '/data-storages/{id}/merge/', - '/dehumidifiers/{id}/merge/', + '/batteries/{dev1_id}/merge/{dev2_id}', + '/bikes/{dev1_id}/merge/{dev2_id}', + '/cameras/{dev1_id}/merge/{dev2_id}', + '/cellphones/{dev1_id}/merge/{dev2_id}', + '/components/{dev1_id}/merge/{dev2_id}', + '/computer-accessories/{dev1_id}/merge/{dev2_id}', + '/computer-monitors/{dev1_id}/merge/{dev2_id}', + '/computers/{dev1_id}/merge/{dev2_id}', + '/cookings/{dev1_id}/merge/{dev2_id}', + '/data-storages/{dev1_id}/merge/{dev2_id}', + '/dehumidifiers/{dev1_id}/merge/{dev2_id}', '/deliverynotes/', - '/desktops/{id}/merge/', + '/desktops/{dev1_id}/merge/{dev2_id}', '/devices/', '/devices/static/{filename}', - '/devices/{id}/merge/', - '/displays/{id}/merge/', - '/diy-and-gardenings/{id}/merge/', + '/devices/{dev1_id}/merge/{dev2_id}', + '/displays/{dev1_id}/merge/{dev2_id}', + '/diy-and-gardenings/{dev1_id}/merge/{dev2_id}', '/documents/devices/', '/documents/erasures/', '/documents/lots/', '/documents/static/{filename}', '/documents/stock/', - '/drills/{id}/merge/', - '/graphic-cards/{id}/merge/', - '/hard-drives/{id}/merge/', - '/homes/{id}/merge/', - '/hubs/{id}/merge/', - '/keyboards/{id}/merge/', - '/label-printers/{id}/merge/', - '/laptops/{id}/merge/', + '/drills/{dev1_id}/merge/{dev2_id}', + '/graphic-cards/{dev1_id}/merge/{dev2_id}', + '/hard-drives/{dev1_id}/merge/{dev2_id}', + '/homes/{dev1_id}/merge/{dev2_id}', + '/hubs/{dev1_id}/merge/{dev2_id}', + '/keyboards/{dev1_id}/merge/{dev2_id}', + '/label-printers/{dev1_id}/merge/{dev2_id}', + '/laptops/{dev1_id}/merge/{dev2_id}', '/lots/', '/lots/{id}/children', '/lots/{id}/devices', '/manufacturers/', - '/memory-card-readers/{id}/merge/', - '/mice/{id}/merge/', - '/microphones/{id}/merge/', - '/mixers/{id}/merge/', - '/mobiles/{id}/merge/', - '/monitors/{id}/merge/', - '/motherboards/{id}/merge/', - '/network-adapters/{id}/merge/', - '/networkings/{id}/merge/', - '/pack-of-screwdrivers/{id}/merge/', - '/printers/{id}/merge/', - '/processors/{id}/merge/', + '/memory-card-readers/{dev1_id}/merge/{dev2_id}', + '/mice/{dev1_id}/merge/{dev2_id}', + '/microphones/{dev1_id}/merge/{dev2_id}', + '/mixers/{dev1_id}/merge/{dev2_id}', + '/mobiles/{dev1_id}/merge/{dev2_id}', + '/monitors/{dev1_id}/merge/{dev2_id}', + '/motherboards/{dev1_id}/merge/{dev2_id}', + '/network-adapters/{dev1_id}/merge/{dev2_id}', + '/networkings/{dev1_id}/merge/{dev2_id}', + '/pack-of-screwdrivers/{dev1_id}/merge/{dev2_id}', + '/printers/{dev1_id}/merge/{dev2_id}', + '/processors/{dev1_id}/merge/{dev2_id}', '/proofs/', - '/rackets/{id}/merge/', - '/ram-modules/{id}/merge/', - '/recreations/{id}/merge/', - '/routers/{id}/merge/', - '/sais/{id}/merge/', - '/servers/{id}/merge/', - '/smartphones/{id}/merge/', - '/solid-state-drives/{id}/merge/', - '/sound-cards/{id}/merge/', - '/sounds/{id}/merge/', - '/stairs/{id}/merge/', - '/switches/{id}/merge/', - '/tablets/{id}/merge/', + '/rackets/{dev1_id}/merge/{dev2_id}', + '/ram-modules/{dev1_id}/merge/{dev2_id}', + '/recreations/{dev1_id}/merge/{dev2_id}', + '/routers/{dev1_id}/merge/{dev2_id}', + '/sais/{dev1_id}/merge/{dev2_id}', + '/servers/{dev1_id}/merge/{dev2_id}', + '/smartphones/{dev1_id}/merge/{dev2_id}', + '/solid-state-drives/{dev1_id}/merge/{dev2_id}', + '/sound-cards/{dev1_id}/merge/{dev2_id}', + '/sounds/{dev1_id}/merge/{dev2_id}', + '/stairs/{dev1_id}/merge/{dev2_id}', + '/switches/{dev1_id}/merge/{dev2_id}', + '/tablets/{dev1_id}/merge/{dev2_id}', '/tags/', '/tags/{tag_id}/device/{device_id}', - '/television-sets/{id}/merge/', + '/television-sets/{dev1_id}/merge/{dev2_id}', '/users/', '/users/login/', - '/video-scalers/{id}/merge/', - '/videoconferences/{id}/merge/', - '/videos/{id}/merge/', - '/wireless-access-points/{id}/merge/', + '/video-scalers/{dev1_id}/merge/{dev2_id}', + '/videoconferences/{dev1_id}/merge/{dev2_id}', + '/videos/{dev1_id}/merge/{dev2_id}', + '/wireless-access-points/{dev1_id}/merge/{dev2_id}', '/versions/' } assert docs['info'] == {'title': 'Devicehub', 'version': '0.2'} From 5717743d2f556cef9e58ee940ed15a548dacb62e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 28 Oct 2020 22:15:04 +0100 Subject: [PATCH 07/10] bug for moving tags --- tests/test_merge.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_merge.py b/tests/test_merge.py index 39cce912..bc408f68 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -4,15 +4,18 @@ from flask import g import pytest from ereuse_devicehub.client import Client, UserClient +from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.resources.action import models as m from ereuse_devicehub.resources.device import models as d +from ereuse_devicehub.resources.tag import Tag from tests import conftest from tests.conftest import file as import_snap @pytest.mark.mvp def test_simple_merge(app: Devicehub, user: UserClient): + """ Check if is correct to do a manual merge """ snapshot1, _ = user.post(import_snap('real-custom.snapshot.11'), res=m.Snapshot) snapshot2, _ = user.post(import_snap('real-hp.snapshot.11'), res=m.Snapshot) pc1_id = snapshot1['device']['id'] @@ -27,10 +30,16 @@ def test_simple_merge(app: Devicehub, user: UserClient): action2 = pc2.actions[0] assert not action2 in pc1.actions + tag = Tag(id='foo-bar', owner_id=user.user['id']) + pc2.tags.add(tag) + db.session.add(pc2) + db.session.commit() + components1 = [com for com in pc1.components] components2 = [com for com in pc2.components] components1_excluded = [com for com in pc1.components if not com in components2] assert pc1.hid != pc2.hid + assert not tag in pc1.tags uri = '/devices/%d/merge/%d' % (pc1_id, pc2_id) result, _ = user.post({'id': 1}, uri=uri, status=201) @@ -40,6 +49,8 @@ def test_simple_merge(app: Devicehub, user: UserClient): assert action2 in pc1.actions assert len(pc1.actions) == n_actions1 + n_actions2 assert set(pc2.components) == set() + assert tag in pc1.tags + assert not tag in pc2.tags for com in components2: assert com in pc1.components From 73d9db3a88e4ae9794e355d3a1199cfa8a799a96 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 28 Oct 2020 22:15:28 +0100 Subject: [PATCH 08/10] fixing bug moving tags --- ereuse_devicehub/resources/device/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/device/views.py b/ereuse_devicehub/resources/device/views.py index 8ea09d7e..1542c548 100644 --- a/ereuse_devicehub/resources/device/views.py +++ b/ereuse_devicehub/resources/device/views.py @@ -209,9 +209,9 @@ class DeviceMergeView(View): # Moving the tags from `with_device` to `base_device` # Union of tags the device had plus the (potentially) new ones - self.base_device.tags |= self.with_device.tags + self.base_device.tags.update([x for x in self.with_device.tags]) self.with_device.tags.clear() # We don't want to add the transient dummy tags - # db.session.add(self.with_device) + db.session.add(self.with_device) # Moving the actions from `with_device` to `base_device` for action in with_actions_one: From 86f37d0cf1a10d4823d9228d128650fc75848eed Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 9 Nov 2020 16:32:06 +0100 Subject: [PATCH 09/10] test of merge 2 devices with 2 diferents tags one for device --- tests/test_merge.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/test_merge.py b/tests/test_merge.py index bc408f68..52d3436d 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -58,3 +58,30 @@ def test_simple_merge(app: Devicehub, user: UserClient): for com in components1_excluded: assert not com in pc1.components +@pytest.mark.mvp +def test_merge_two_device_with_differents_tags(app: Devicehub, user: UserClient): + """ Check if is correct to do a manual merge of 2 diferents devices with diferents tags """ + snapshot1, _ = user.post(import_snap('real-custom.snapshot.11'), res=m.Snapshot) + snapshot2, _ = user.post(import_snap('real-hp.snapshot.11'), res=m.Snapshot) + pc1_id = snapshot1['device']['id'] + pc2_id = snapshot2['device']['id'] + + with app.app_context(): + pc1 = d.Device.query.filter_by(id=pc1_id).one() + pc2 = d.Device.query.filter_by(id=pc2_id).one() + + tag1 = Tag(id='fii-bor', owner_id=user.user['id']) + tag2 = Tag(id='foo-bar', owner_id=user.user['id']) + pc1.tags.add(tag1) + pc2.tags.add(tag2) + db.session.add(pc1) + db.session.add(pc2) + db.session.commit() + + uri = '/devices/%d/merge/%d' % (pc1_id, pc2_id) + result, _ = user.post({'id': 1}, uri=uri, status=201) + + assert pc1.hid == pc2.hid + assert tag1 in pc1.tags + assert tag2 in pc1.tags + From b6f2dedaeb20c3896babad9b86ed92a6dffb335e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 16 Nov 2020 20:37:35 +0100 Subject: [PATCH 10/10] adding changelog --- ereuse_devicehub/__init__.py | 2 +- ereuse_devicehub/resources/CHANGELOG.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 ereuse_devicehub/resources/CHANGELOG.md diff --git a/ereuse_devicehub/__init__.py b/ereuse_devicehub/__init__.py index a346d164..944f81a7 100644 --- a/ereuse_devicehub/__init__.py +++ b/ereuse_devicehub/__init__.py @@ -1 +1 @@ -__version__ = "1.0b" +__version__ = "1.0.1-beta" diff --git a/ereuse_devicehub/resources/CHANGELOG.md b/ereuse_devicehub/resources/CHANGELOG.md new file mode 100644 index 00000000..3f423a22 --- /dev/null +++ b/ereuse_devicehub/resources/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [1.0.1-beta] - 2020-11-16 +- [fixed] #80 manual merged from website