From ab1d268f14f24eb8633df39bd7f7163f1008b9e6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 27 Oct 2020 19:12:46 +0100 Subject: [PATCH 01/72] 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/72] 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/72] 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/72] 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/72] 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/72] 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/72] 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/72] 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/72] 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 8acca4d2cf407b36e4d2269aa222e50707521651 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 16 Nov 2020 20:32:28 +0100 Subject: [PATCH 10/72] definition rent endpoint --- ereuse_devicehub/config.py | 4 ++- ereuse_devicehub/resources/action/__init__.py | 5 --- ereuse_devicehub/resources/rent/__init__.py | 0 .../resources/rent/definitions.py | 34 +++++++++++++++++++ ereuse_devicehub/resources/rent/model.py | 0 ereuse_devicehub/resources/rent/views.py | 0 6 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 ereuse_devicehub/resources/rent/__init__.py create mode 100644 ereuse_devicehub/resources/rent/definitions.py create mode 100644 ereuse_devicehub/resources/rent/model.py create mode 100644 ereuse_devicehub/resources/rent/views.py diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index f7ff436f..7c28f5fd 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -14,6 +14,7 @@ from ereuse_devicehub.resources.device import definitions from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.enums import PriceSoftware from ereuse_devicehub.resources.versions import versions +from ereuse_devicehub.resources.rent import definitions as rent_def class DevicehubConfig(Config): @@ -27,7 +28,8 @@ class DevicehubConfig(Config): import_resource(proof), import_resource(documents), import_resource(inventory), - import_resource(versions)), + import_resource(versions), + import_resource(rent_def)), ) PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str] DB_USER = config('DB_USER', 'dhub') diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 19a87f2c..59f49b46 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -228,11 +228,6 @@ class DonateDef(ActionDef): SCHEMA = schemas.Donate -class RentDef(ActionDef): - VIEW = None - SCHEMA = schemas.Rent - - class MakeAvailable(ActionDef): VIEW = None SCHEMA = schemas.MakeAvailable diff --git a/ereuse_devicehub/resources/rent/__init__.py b/ereuse_devicehub/resources/rent/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ereuse_devicehub/resources/rent/definitions.py b/ereuse_devicehub/resources/rent/definitions.py new file mode 100644 index 00000000..8f2ee535 --- /dev/null +++ b/ereuse_devicehub/resources/rent/definitions.py @@ -0,0 +1,34 @@ +from typing import Callable, Iterable, Tuple +from flask import g +from flask.json import jsonify +from ereuse_devicehub.resources import action as act +from ereuse_devicehub.resources.action.models import Rent +from ereuse_devicehub.resources.device.models import Device +from teal.resource import Converters, Resource, View +from ereuse_devicehub import auth +from ereuse_devicehub.query import things_response + + +class RentingView(View): + @auth.Auth.requires_auth + def get(self, id): + return super().get(id) + + @auth.Auth.requires_auth + def post(self): + """ Create one rent """ + return jsonify('ok') + + def find(self, args: dict): + rents = Rent.query.filter() \ + .order_by(Rent.created.desc()) \ + .paginate(per_page=200) + return things_response( + self.schema.dump(rents.items, many=True, nested=0), + rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num + ) + + +class RentDef(Resource): + VIEW = RentingView + SCHEMA = act.schemas.Rent diff --git a/ereuse_devicehub/resources/rent/model.py b/ereuse_devicehub/resources/rent/model.py new file mode 100644 index 00000000..e69de29b diff --git a/ereuse_devicehub/resources/rent/views.py b/ereuse_devicehub/resources/rent/views.py new file mode 100644 index 00000000..e69de29b From b6f2dedaeb20c3896babad9b86ed92a6dffb335e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 16 Nov 2020 20:37:35 +0100 Subject: [PATCH 11/72] 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 From 820e253a12661b25aab8574217ade5bdd9a610ae Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 17 Nov 2020 13:19:50 +0100 Subject: [PATCH 12/72] new version of rent as asigned --- ereuse_devicehub/resources/action/models.py | 8 +++++ ereuse_devicehub/resources/action/schemas.py | 8 +++++ .../resources/rent/definitions.py | 34 +++---------------- ereuse_devicehub/resources/rent/model.py | 0 ereuse_devicehub/resources/rent/views.py | 30 ++++++++++++++++ 5 files changed, 50 insertions(+), 30 deletions(-) delete mode 100644 ereuse_devicehub/resources/rent/model.py diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index a0d38e14..e75964bf 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1472,6 +1472,14 @@ class MigrateFrom(Migrate): pass +class Assigned(JoinedTableMixin, ActionWithMultipleDevices): + """The act of assigned one list of devices to one person of the system or not + """ + assigned = Column(CIText(), default='', nullable=True) + assigned.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ + n_beneficiaries = Column(Numeric(precision=4), check_range('n_beneficiaries', 0), nullable=False) + + # Listeners # Listeners validate values and keep relationships synced diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 99234a7a..48ae5970 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -457,3 +457,11 @@ class MigrateFrom(Migrate): class Transferred(ActionWithMultipleDevices): __doc__ = m.Transferred.__doc__ + +class Assigned(ActionWithMultipleDevices): + __doc__ = m.Assigned.__doc__ + shipping_date = DateTime(data_key='shippingDate') + invoice_number = SanitizedStr(validate=Length(max=STR_SIZE), data_key='invoiceNumber') + price = NestedOn(Price) + to = NestedOn(s_agent.Agent, only_query='id', required=True, comment=m.Trade.to_comment) + confirms = NestedOn(Organize) diff --git a/ereuse_devicehub/resources/rent/definitions.py b/ereuse_devicehub/resources/rent/definitions.py index 8f2ee535..e87e0f72 100644 --- a/ereuse_devicehub/resources/rent/definitions.py +++ b/ereuse_devicehub/resources/rent/definitions.py @@ -1,34 +1,8 @@ -from typing import Callable, Iterable, Tuple -from flask import g -from flask.json import jsonify -from ereuse_devicehub.resources import action as act -from ereuse_devicehub.resources.action.models import Rent -from ereuse_devicehub.resources.device.models import Device -from teal.resource import Converters, Resource, View -from ereuse_devicehub import auth -from ereuse_devicehub.query import things_response - - -class RentingView(View): - @auth.Auth.requires_auth - def get(self, id): - return super().get(id) - - @auth.Auth.requires_auth - def post(self): - """ Create one rent """ - return jsonify('ok') - - def find(self, args: dict): - rents = Rent.query.filter() \ - .order_by(Rent.created.desc()) \ - .paginate(per_page=200) - return things_response( - self.schema.dump(rents.items, many=True, nested=0), - rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num - ) +from ereuse_devicehub.resources.action import schemas +from teal.resource import Resource +from ereuse_devicehub.resources.rent.views import RentingView class RentDef(Resource): VIEW = RentingView - SCHEMA = act.schemas.Rent + SCHEMA = schemas.Assigned diff --git a/ereuse_devicehub/resources/rent/model.py b/ereuse_devicehub/resources/rent/model.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ereuse_devicehub/resources/rent/views.py b/ereuse_devicehub/resources/rent/views.py index e69de29b..0b5659d6 100644 --- a/ereuse_devicehub/resources/rent/views.py +++ b/ereuse_devicehub/resources/rent/views.py @@ -0,0 +1,30 @@ +# from typing import Callable, Iterable, Tuple +# from flask import g +# from flask.json import jsonify +from teal.resource import View + +from ereuse_devicehub import auth +from ereuse_devicehub.query import things_response +from ereuse_devicehub.resources.action.models import Assigned + +class RentingView(View): + @auth.Auth.requires_auth + def get(self, id): + return super().get(id) + + @auth.Auth.requires_auth + def post(self): + """ Create one rent """ + return super().get(id) + # return jsonify('ok') + + def find(self, args: dict): + rents = Assigned.query.filter() \ + .order_by(Assigned.created.desc()) \ + .paginate(per_page=200) + return things_response( + self.schema.dump(rents.items, many=True, nested=0), + rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num + ) + + From e0b338b4146aa86a91c8604205bbe4872a6752a0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 17 Nov 2020 13:36:26 +0100 Subject: [PATCH 13/72] add migration file for assigned action --- .../e93aec8fc41f_added_assigned_action.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py new file mode 100644 index 00000000..7caec6c0 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -0,0 +1,41 @@ +"""Added Assigned action + +Revision ID: e93aec8fc41f +Revises: b9b0ee7d9dca +Create Date: 2020-11-17 13:22:56.790956 + +""" +from alembic import op +import sqlalchemy as sa +from alembic import context +import sqlalchemy_utils +import citext +import teal +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'e93aec8fc41f' +down_revision = 'b9b0ee7d9dca' +branch_labels = None +depends_on = None + + +def get_inv(): + INV = context.get_x_argument(as_dictionary=True).get('inventory') + if not INV: + raise ValueError("Inventory value is not specified") + return INV + +def upgrade(): + op.create_table('assigned', + sa.Column('assigned', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), + sa.Column('n_beneficiaries', sa.Numeric(precision=4), nullable=False), + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + + +def downgrade(): + op.drop_table('assigned') From 69368a8ca36fccc319b5766024398a7e076bac3c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 17 Nov 2020 19:21:32 +0100 Subject: [PATCH 14/72] rent with assigned concept --- ereuse_devicehub/resources/action/schemas.py | 14 ++++++++---- ereuse_devicehub/resources/rent/views.py | 24 +++++++++++++++----- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 48ae5970..ebd4cd97 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -460,8 +460,12 @@ class Transferred(ActionWithMultipleDevices): class Assigned(ActionWithMultipleDevices): __doc__ = m.Assigned.__doc__ - shipping_date = DateTime(data_key='shippingDate') - invoice_number = SanitizedStr(validate=Length(max=STR_SIZE), data_key='invoiceNumber') - price = NestedOn(Price) - to = NestedOn(s_agent.Agent, only_query='id', required=True, comment=m.Trade.to_comment) - confirms = NestedOn(Organize) + agent = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Trade.to_comment) + description = SanitizedStr(default='', description=m.Action.description.comment) + start_time = DateTime(data_key='startTime', description=m.Action.start_time.comment) + end_time = DateTime(data_key='endTime', description=m.Action.end_time.comment) + assigned = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), + required=False, + description='The code of the agent to assigned.') + n_beneficiaries = Integer(validate=[Range(min=1, error="Value must be greater than 0")], + required=True) diff --git a/ereuse_devicehub/resources/rent/views.py b/ereuse_devicehub/resources/rent/views.py index 0b5659d6..e8ed15ad 100644 --- a/ereuse_devicehub/resources/rent/views.py +++ b/ereuse_devicehub/resources/rent/views.py @@ -1,25 +1,34 @@ +import uuid # from typing import Callable, Iterable, Tuple -# from flask import g +from flask import g, request # from flask.json import jsonify from teal.resource import View from ereuse_devicehub import auth +from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import Assigned + class RentingView(View): @auth.Auth.requires_auth - def get(self, id): + def get(self, id: uuid.UUID) -> Assigned: return super().get(id) @auth.Auth.requires_auth def post(self): """ Create one rent """ - return super().get(id) - # return jsonify('ok') + res_json = request.get_json() + assigned = Assigned(**res_json) + db.session.add(assigned) + db.session().final_flush() + ret = self.schema.jsonify(assigned) + ret.status_code = 201 + db.session.commit() + return ret def find(self, args: dict): - rents = Assigned.query.filter() \ + rents = Assigned.query.filter_by(author=g.user) \ .order_by(Assigned.created.desc()) \ .paginate(per_page=200) return things_response( @@ -27,4 +36,7 @@ class RentingView(View): rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num ) - + def one(self, id: uuid.UUID): + """Gets one action.""" + assigned = Assigned.query.filter_by(id=id, author=g.user).one() + return self.schema.jsonify(assigned, nested=2) From 64fe93491c5f1dcfa454e35e524dad4c03b12846 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 18 Nov 2020 11:31:23 +0100 Subject: [PATCH 15/72] change name rent resource for assigned --- ereuse_devicehub/config.py | 4 ++-- .../resources/{rent => assigned}/__init__.py | 0 ereuse_devicehub/resources/assigned/definitions.py | 9 +++++++++ ereuse_devicehub/resources/{rent => assigned}/views.py | 2 +- ereuse_devicehub/resources/rent/definitions.py | 8 -------- 5 files changed, 12 insertions(+), 11 deletions(-) rename ereuse_devicehub/resources/{rent => assigned}/__init__.py (100%) create mode 100644 ereuse_devicehub/resources/assigned/definitions.py rename ereuse_devicehub/resources/{rent => assigned}/views.py (98%) delete mode 100644 ereuse_devicehub/resources/rent/definitions.py diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index 7c28f5fd..d5226c26 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -14,7 +14,7 @@ from ereuse_devicehub.resources.device import definitions from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.enums import PriceSoftware from ereuse_devicehub.resources.versions import versions -from ereuse_devicehub.resources.rent import definitions as rent_def +from ereuse_devicehub.resources.assigned import definitions as assigned_def class DevicehubConfig(Config): @@ -29,7 +29,7 @@ class DevicehubConfig(Config): import_resource(documents), import_resource(inventory), import_resource(versions), - import_resource(rent_def)), + import_resource(assigned_def)), ) PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str] DB_USER = config('DB_USER', 'dhub') diff --git a/ereuse_devicehub/resources/rent/__init__.py b/ereuse_devicehub/resources/assigned/__init__.py similarity index 100% rename from ereuse_devicehub/resources/rent/__init__.py rename to ereuse_devicehub/resources/assigned/__init__.py diff --git a/ereuse_devicehub/resources/assigned/definitions.py b/ereuse_devicehub/resources/assigned/definitions.py new file mode 100644 index 00000000..f2ce97ba --- /dev/null +++ b/ereuse_devicehub/resources/assigned/definitions.py @@ -0,0 +1,9 @@ +from typing import Callable, Iterable, Tuple +from ereuse_devicehub.resources.action import schemas +from teal.resource import Resource +from ereuse_devicehub.resources.assigned.views import AssignedView + + +class AssignedDef(Resource): + VIEW = AssignedView + SCHEMA = schemas.Assigned diff --git a/ereuse_devicehub/resources/rent/views.py b/ereuse_devicehub/resources/assigned/views.py similarity index 98% rename from ereuse_devicehub/resources/rent/views.py rename to ereuse_devicehub/resources/assigned/views.py index e8ed15ad..e07471cd 100644 --- a/ereuse_devicehub/resources/rent/views.py +++ b/ereuse_devicehub/resources/assigned/views.py @@ -10,7 +10,7 @@ from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import Assigned -class RentingView(View): +class AssignedView(View): @auth.Auth.requires_auth def get(self, id: uuid.UUID) -> Assigned: return super().get(id) diff --git a/ereuse_devicehub/resources/rent/definitions.py b/ereuse_devicehub/resources/rent/definitions.py deleted file mode 100644 index e87e0f72..00000000 --- a/ereuse_devicehub/resources/rent/definitions.py +++ /dev/null @@ -1,8 +0,0 @@ -from ereuse_devicehub.resources.action import schemas -from teal.resource import Resource -from ereuse_devicehub.resources.rent.views import RentingView - - -class RentDef(Resource): - VIEW = RentingView - SCHEMA = schemas.Assigned From 16735d0199d243c85b61a581fa8f36cbfbc3b8be Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 18 Nov 2020 18:13:13 +0100 Subject: [PATCH 16/72] change assigned for allocate --- ereuse_devicehub/config.py | 4 +- .../e93aec8fc41f_added_assigned_action.py | 17 ++++- ereuse_devicehub/resources/action/models.py | 24 +++--- ereuse_devicehub/resources/action/schemas.py | 33 +++------ .../{assigned => allocate}/__init__.py | 0 .../resources/allocate/definitions.py | 15 ++++ ereuse_devicehub/resources/allocate/views.py | 74 +++++++++++++++++++ .../resources/assigned/definitions.py | 9 --- ereuse_devicehub/resources/assigned/views.py | 42 ----------- 9 files changed, 124 insertions(+), 94 deletions(-) rename ereuse_devicehub/resources/{assigned => allocate}/__init__.py (100%) create mode 100644 ereuse_devicehub/resources/allocate/definitions.py create mode 100644 ereuse_devicehub/resources/allocate/views.py delete mode 100644 ereuse_devicehub/resources/assigned/definitions.py delete mode 100644 ereuse_devicehub/resources/assigned/views.py diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index d5226c26..6de4a9e1 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -14,7 +14,7 @@ from ereuse_devicehub.resources.device import definitions from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.enums import PriceSoftware from ereuse_devicehub.resources.versions import versions -from ereuse_devicehub.resources.assigned import definitions as assigned_def +from ereuse_devicehub.resources.allocate import definitions as allocate_def class DevicehubConfig(Config): @@ -29,7 +29,7 @@ class DevicehubConfig(Config): import_resource(documents), import_resource(inventory), import_resource(versions), - import_resource(assigned_def)), + import_resource(allocate_def)), ) PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str] DB_USER = config('DB_USER', 'dhub') diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 7caec6c0..273ba1c3 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -27,9 +27,18 @@ def get_inv(): return INV def upgrade(): - op.create_table('assigned', - sa.Column('assigned', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), - sa.Column('n_beneficiaries', sa.Numeric(precision=4), nullable=False), + op.drop_table('allocate') + op.create_table('allocate', + sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), + sa.Column('end_users', sa.Numeric(precision=4), nullable=False), + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + + op.drop_table('deallocate') + op.create_table('deallocate', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), @@ -38,4 +47,4 @@ def upgrade(): def downgrade(): - op.drop_table('assigned') + op.drop_table('allocate') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index e75964bf..5f442e2d 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -312,15 +312,19 @@ class Remove(ActionWithOneDevice): class Allocate(JoinedTableMixin, ActionWithMultipleDevices): - to_id = Column(UUID, ForeignKey(User.id)) - to = relationship(User, primaryjoin=User.id == to_id) - organization = Column(CIText()) + """The act of assigned one list of devices to one person of the system or not + """ + code = Column(CIText(), default='', nullable=True) + code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ + end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=False) class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): - from_id = Column(UUID, ForeignKey(User.id)) - from_rel = relationship(User, primaryjoin=User.id == from_id) - organization = Column(CIText()) + @property + def allocate(self): + """The URL of the allocate than closes one allocate. """ + allocate = [a for a in self.devices[0].actions if is_instance(action, 'Allocate')][-1] + return urlutils.URL(url_for_resource('Allocate', item=allocate)) class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): @@ -1472,14 +1476,6 @@ class MigrateFrom(Migrate): pass -class Assigned(JoinedTableMixin, ActionWithMultipleDevices): - """The act of assigned one list of devices to one person of the system or not - """ - assigned = Column(CIText(), default='', nullable=True) - assigned.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ - n_beneficiaries = Column(Numeric(precision=4), check_range('n_beneficiaries', 0), nullable=False) - - # Listeners # Listeners validate values and keep relationships synced diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index ebd4cd97..554317eb 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -64,21 +64,20 @@ class Remove(ActionWithOneDevice): class Allocate(ActionWithMultipleDevices): __doc__ = m.Allocate.__doc__ - to = NestedOn(s_user.User, - description='The user the devices are allocated to.') - organization = SanitizedStr(validate=Length(max=STR_SIZE), - description='The organization where the ' - 'user was when this happened.') + agent = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Trade.to_comment) + description = SanitizedStr(default='', description=m.Action.description.comment) + start_time = DateTime(data_key='start_time', description=m.Action.start_time.comment) + end_time = DateTime(data_key='end_time', description=m.Action.end_time.comment) + code = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), + required=False, + description='The code of the agent to assigned.') + end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")], + required=True) class Deallocate(ActionWithMultipleDevices): __doc__ = m.Deallocate.__doc__ - from_rel = Nested(s_user.User, - data_key='from', - description='The user where the devices are not allocated to anymore.') - organization = SanitizedStr(validate=Length(max=STR_SIZE), - description='The organization where the ' - 'user was when this happened.') + end_time = DateTime(data_key='end_time', description=m.Action.end_time.comment) class EraseBasic(ActionWithOneDevice): @@ -457,15 +456,3 @@ class MigrateFrom(Migrate): class Transferred(ActionWithMultipleDevices): __doc__ = m.Transferred.__doc__ - -class Assigned(ActionWithMultipleDevices): - __doc__ = m.Assigned.__doc__ - agent = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Trade.to_comment) - description = SanitizedStr(default='', description=m.Action.description.comment) - start_time = DateTime(data_key='startTime', description=m.Action.start_time.comment) - end_time = DateTime(data_key='endTime', description=m.Action.end_time.comment) - assigned = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), - required=False, - description='The code of the agent to assigned.') - n_beneficiaries = Integer(validate=[Range(min=1, error="Value must be greater than 0")], - required=True) diff --git a/ereuse_devicehub/resources/assigned/__init__.py b/ereuse_devicehub/resources/allocate/__init__.py similarity index 100% rename from ereuse_devicehub/resources/assigned/__init__.py rename to ereuse_devicehub/resources/allocate/__init__.py diff --git a/ereuse_devicehub/resources/allocate/definitions.py b/ereuse_devicehub/resources/allocate/definitions.py new file mode 100644 index 00000000..e5c6f62c --- /dev/null +++ b/ereuse_devicehub/resources/allocate/definitions.py @@ -0,0 +1,15 @@ +from typing import Callable, Iterable, Tuple +from ereuse_devicehub.resources.action import schemas +from teal.resource import Resource +from ereuse_devicehub.resources.allocate.views import AllocateView, DeAllocateView + + +class AssignedDef(Resource): + VIEW = AllocateView + SCHEMA = schemas.Allocate + + +# class EndAssignedDef(Resource): + # VIEW = DeAllocateView + # SCHEMA = schemas.DeAllocate + diff --git a/ereuse_devicehub/resources/allocate/views.py b/ereuse_devicehub/resources/allocate/views.py new file mode 100644 index 00000000..b87c592e --- /dev/null +++ b/ereuse_devicehub/resources/allocate/views.py @@ -0,0 +1,74 @@ +import uuid +# from typing import Callable, Iterable, Tuple +from flask import g, request +# from flask.json import jsonify +from teal.resource import View + +from ereuse_devicehub import auth +from ereuse_devicehub.db import db +from ereuse_devicehub.query import things_response +from ereuse_devicehub.resources.action.models import Allocate + + +class AllocateView(View): + @auth.Auth.requires_auth + def get(self, id: uuid.UUID) -> Allocate: + return super().get(id) + + @auth.Auth.requires_auth + def post(self): + """ Create one rent """ + res_json = request.get_json() + assigned = Allocate(**res_json) + db.session.add(assigned) + db.session().final_flush() + ret = self.schema.jsonify(assigned) + ret.status_code = 201 + db.session.commit() + return ret + + def find(self, args: dict): + rents = Allocate.query.filter_by(author=g.user) \ + .order_by(Allocate.created.desc()) \ + .paginate(per_page=200) + return things_response( + self.schema.dump(rents.items, many=True, nested=0), + rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num + ) + + def one(self, id: uuid.UUID): + """Gets one action.""" + assigned = Allocate.query.filter_by(id=id, author=g.user).one() + return self.schema.jsonify(assigned, nested=2) + + +class DeAllocateView(View): + @auth.Auth.requires_auth + def get(self, id: uuid.UUID) -> Allocate: + return super().get(id) + + @auth.Auth.requires_auth + def post(self): + """ Create one rent """ + res_json = request.get_json() + assigned = Allocate(**res_json) + db.session.add(assigned) + db.session().final_flush() + ret = self.schema.jsonify(assigned) + ret.status_code = 201 + db.session.commit() + return ret + + def find(self, args: dict): + rents = Allocate.query.filter_by(author=g.user) \ + .order_by(Allocate.created.desc()) \ + .paginate(per_page=200) + return things_response( + self.schema.dump(rents.items, many=True, nested=0), + rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num + ) + + def one(self, id: uuid.UUID): + """Gets one action.""" + assigned = Allocate.query.filter_by(id=id, author=g.user).one() + return self.schema.jsonify(assigned, nested=2) diff --git a/ereuse_devicehub/resources/assigned/definitions.py b/ereuse_devicehub/resources/assigned/definitions.py deleted file mode 100644 index f2ce97ba..00000000 --- a/ereuse_devicehub/resources/assigned/definitions.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Callable, Iterable, Tuple -from ereuse_devicehub.resources.action import schemas -from teal.resource import Resource -from ereuse_devicehub.resources.assigned.views import AssignedView - - -class AssignedDef(Resource): - VIEW = AssignedView - SCHEMA = schemas.Assigned diff --git a/ereuse_devicehub/resources/assigned/views.py b/ereuse_devicehub/resources/assigned/views.py deleted file mode 100644 index e07471cd..00000000 --- a/ereuse_devicehub/resources/assigned/views.py +++ /dev/null @@ -1,42 +0,0 @@ -import uuid -# from typing import Callable, Iterable, Tuple -from flask import g, request -# from flask.json import jsonify -from teal.resource import View - -from ereuse_devicehub import auth -from ereuse_devicehub.db import db -from ereuse_devicehub.query import things_response -from ereuse_devicehub.resources.action.models import Assigned - - -class AssignedView(View): - @auth.Auth.requires_auth - def get(self, id: uuid.UUID) -> Assigned: - return super().get(id) - - @auth.Auth.requires_auth - def post(self): - """ Create one rent """ - res_json = request.get_json() - assigned = Assigned(**res_json) - db.session.add(assigned) - db.session().final_flush() - ret = self.schema.jsonify(assigned) - ret.status_code = 201 - db.session.commit() - return ret - - def find(self, args: dict): - rents = Assigned.query.filter_by(author=g.user) \ - .order_by(Assigned.created.desc()) \ - .paginate(per_page=200) - return things_response( - self.schema.dump(rents.items, many=True, nested=0), - rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num - ) - - def one(self, id: uuid.UUID): - """Gets one action.""" - assigned = Assigned.query.filter_by(id=id, author=g.user).one() - return self.schema.jsonify(assigned, nested=2) From cc6f16934d9247f546fdb78975d492cf1531a4aa Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 18 Nov 2020 18:21:22 +0100 Subject: [PATCH 17/72] fixing migrations --- .../versions/e93aec8fc41f_added_assigned_action.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 273ba1c3..b3c45ca7 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -27,7 +27,7 @@ def get_inv(): return INV def upgrade(): - op.drop_table('allocate') + op.drop_table('allocate', schema=f'{get_inv()}') op.create_table('allocate', sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), sa.Column('end_users', sa.Numeric(precision=4), nullable=False), @@ -37,7 +37,7 @@ def upgrade(): schema=f'{get_inv()}' ) - op.drop_table('deallocate') + op.drop_table('deallocate', schema=f'{get_inv()}') op.create_table('deallocate', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), @@ -47,4 +47,5 @@ def upgrade(): def downgrade(): - op.drop_table('allocate') + op.drop_table('allocate', schema=f'{get_inv()}') + op.drop_table('deallocate', schema=f'{get_inv()}') From 5adfad8a5e5bcf18ddb7c6b39e7e60afccfb6b4c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 18 Nov 2020 19:00:43 +0100 Subject: [PATCH 18/72] adding deallocate --- ereuse_devicehub/resources/action/models.py | 6 +-- .../resources/allocate/definitions.py | 7 ++- ereuse_devicehub/resources/allocate/views.py | 49 ++++++++++--------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 5f442e2d..06c9e6cc 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -320,11 +320,7 @@ class Allocate(JoinedTableMixin, ActionWithMultipleDevices): class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): - @property - def allocate(self): - """The URL of the allocate than closes one allocate. """ - allocate = [a for a in self.devices[0].actions if is_instance(action, 'Allocate')][-1] - return urlutils.URL(url_for_resource('Allocate', item=allocate)) + pass class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): diff --git a/ereuse_devicehub/resources/allocate/definitions.py b/ereuse_devicehub/resources/allocate/definitions.py index e5c6f62c..7cda6eb4 100644 --- a/ereuse_devicehub/resources/allocate/definitions.py +++ b/ereuse_devicehub/resources/allocate/definitions.py @@ -9,7 +9,6 @@ class AssignedDef(Resource): SCHEMA = schemas.Allocate -# class EndAssignedDef(Resource): - # VIEW = DeAllocateView - # SCHEMA = schemas.DeAllocate - +class EndAssignedDef(Resource): + VIEW = DeAllocateView + SCHEMA = schemas.Deallocate diff --git a/ereuse_devicehub/resources/allocate/views.py b/ereuse_devicehub/resources/allocate/views.py index b87c592e..4a368799 100644 --- a/ereuse_devicehub/resources/allocate/views.py +++ b/ereuse_devicehub/resources/allocate/views.py @@ -7,68 +7,71 @@ from teal.resource import View from ereuse_devicehub import auth from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response -from ereuse_devicehub.resources.action.models import Allocate +from ereuse_devicehub.resources.action.models import Allocate, Deallocate class AllocateView(View): @auth.Auth.requires_auth def get(self, id: uuid.UUID) -> Allocate: return super().get(id) - + @auth.Auth.requires_auth def post(self): - """ Create one rent """ + """ Create one allocate """ res_json = request.get_json() - assigned = Allocate(**res_json) - db.session.add(assigned) + allocate = Allocate(**res_json) + db.session.add(allocate) db.session().final_flush() - ret = self.schema.jsonify(assigned) + ret = self.schema.jsonify(allocate) ret.status_code = 201 db.session.commit() return ret def find(self, args: dict): - rents = Allocate.query.filter_by(author=g.user) \ + allocates = Allocate.query.filter_by(author=g.user) \ .order_by(Allocate.created.desc()) \ .paginate(per_page=200) return things_response( - self.schema.dump(rents.items, many=True, nested=0), - rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num + self.schema.dump(allocates.items, many=True, nested=0), + allocates.page, allocates.per_page, allocates.total, + allocates.prev_num, allocates.next_num ) def one(self, id: uuid.UUID): """Gets one action.""" - assigned = Allocate.query.filter_by(id=id, author=g.user).one() - return self.schema.jsonify(assigned, nested=2) + allocate = Allocate.query.filter_by(id=id, author=g.user).one() + return self.schema.jsonify(allocate, nested=2) + - class DeAllocateView(View): @auth.Auth.requires_auth def get(self, id: uuid.UUID) -> Allocate: return super().get(id) - + @auth.Auth.requires_auth def post(self): - """ Create one rent """ + """ Create one Deallocate """ res_json = request.get_json() - assigned = Allocate(**res_json) - db.session.add(assigned) + deallocate = Deallocate(**res_json) + db.session.add(deallocate) db.session().final_flush() - ret = self.schema.jsonify(assigned) + ret = self.schema.jsonify(deallocate) ret.status_code = 201 db.session.commit() return ret def find(self, args: dict): - rents = Allocate.query.filter_by(author=g.user) \ - .order_by(Allocate.created.desc()) \ + deallocates = Deallocate.query.filter_by(author=g.user) \ + .order_by(Deallocate.created.desc()) \ .paginate(per_page=200) return things_response( - self.schema.dump(rents.items, many=True, nested=0), - rents.page, rents.per_page, rents.total, rents.prev_num, rents.next_num + self.schema.dump(deallocates.items, many=True, nested=0), + deallocates.page, deallocates.per_page, deallocates.total, + deallocates.prev_num, deallocates.next_num ) def one(self, id: uuid.UUID): """Gets one action.""" - assigned = Allocate.query.filter_by(id=id, author=g.user).one() - return self.schema.jsonify(assigned, nested=2) + deallocate = Deallocate.query.filter_by(id=id, author=g.user).one() + res = self.schema.jsonify(deallocate, nested=2) + return res From 9f1564a5335ec7dbb29af31dfd07946d4dfa170d Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 18 Nov 2020 19:15:30 +0100 Subject: [PATCH 19/72] add column inuse to device table --- .../migrations/versions/e93aec8fc41f_added_assigned_action.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index b3c45ca7..effd4dcf 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -45,6 +45,7 @@ def upgrade(): schema=f'{get_inv()}' ) + op.add_column('device', sa.Column('inuse', sa.Boolean(), nullable=True), schema=f'{get_inv()}') def downgrade(): op.drop_table('allocate', schema=f'{get_inv()}') From 200974e8f6447ca791e5b53bb2af504a7ecd4800 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 11:36:09 +0100 Subject: [PATCH 20/72] remove deallocate --- .../versions/e93aec8fc41f_added_assigned_action.py | 9 +-------- ereuse_devicehub/resources/action/models.py | 4 ---- ereuse_devicehub/resources/action/schemas.py | 5 ----- ereuse_devicehub/resources/allocate/definitions.py | 6 +----- 4 files changed, 2 insertions(+), 22 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index effd4dcf..0867d8f9 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -38,15 +38,8 @@ def upgrade(): ) op.drop_table('deallocate', schema=f'{get_inv()}') - op.create_table('deallocate', - sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), - sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), - sa.PrimaryKeyConstraint('id'), - schema=f'{get_inv()}' - ) - op.add_column('device', sa.Column('inuse', sa.Boolean(), nullable=True), schema=f'{get_inv()}') + op.add_column('device', sa.Column('allocate', sa.Boolean(), nullable=True), schema=f'{get_inv()}') def downgrade(): op.drop_table('allocate', schema=f'{get_inv()}') - op.drop_table('deallocate', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 06c9e6cc..734a5207 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -319,10 +319,6 @@ class Allocate(JoinedTableMixin, ActionWithMultipleDevices): end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=False) -class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): - pass - - class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): """An erasure attempt to a ``DataStorage``. The action contains information about success and nature of the erasure. diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 554317eb..0eb3f1c4 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -75,11 +75,6 @@ class Allocate(ActionWithMultipleDevices): required=True) -class Deallocate(ActionWithMultipleDevices): - __doc__ = m.Deallocate.__doc__ - end_time = DateTime(data_key='end_time', description=m.Action.end_time.comment) - - class EraseBasic(ActionWithOneDevice): __doc__ = m.EraseBasic.__doc__ steps = NestedOn('Step', many=True) diff --git a/ereuse_devicehub/resources/allocate/definitions.py b/ereuse_devicehub/resources/allocate/definitions.py index 7cda6eb4..38e740ed 100644 --- a/ereuse_devicehub/resources/allocate/definitions.py +++ b/ereuse_devicehub/resources/allocate/definitions.py @@ -1,14 +1,10 @@ from typing import Callable, Iterable, Tuple from ereuse_devicehub.resources.action import schemas from teal.resource import Resource -from ereuse_devicehub.resources.allocate.views import AllocateView, DeAllocateView +from ereuse_devicehub.resources.allocate.views import AllocateView class AssignedDef(Resource): VIEW = AllocateView SCHEMA = schemas.Allocate - -class EndAssignedDef(Resource): - VIEW = DeAllocateView - SCHEMA = schemas.Deallocate From 11d766d2a4d0ad09866d7bf6bf976d4d6b447d35 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 11:38:41 +0100 Subject: [PATCH 21/72] remove deallocate view --- ereuse_devicehub/resources/allocate/views.py | 36 +------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/ereuse_devicehub/resources/allocate/views.py b/ereuse_devicehub/resources/allocate/views.py index 4a368799..d1df9e2a 100644 --- a/ereuse_devicehub/resources/allocate/views.py +++ b/ereuse_devicehub/resources/allocate/views.py @@ -7,7 +7,7 @@ from teal.resource import View from ereuse_devicehub import auth from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response -from ereuse_devicehub.resources.action.models import Allocate, Deallocate +from ereuse_devicehub.resources.action.models import Allocate class AllocateView(View): @@ -41,37 +41,3 @@ class AllocateView(View): """Gets one action.""" allocate = Allocate.query.filter_by(id=id, author=g.user).one() return self.schema.jsonify(allocate, nested=2) - - -class DeAllocateView(View): - @auth.Auth.requires_auth - def get(self, id: uuid.UUID) -> Allocate: - return super().get(id) - - @auth.Auth.requires_auth - def post(self): - """ Create one Deallocate """ - res_json = request.get_json() - deallocate = Deallocate(**res_json) - db.session.add(deallocate) - db.session().final_flush() - ret = self.schema.jsonify(deallocate) - ret.status_code = 201 - db.session.commit() - return ret - - def find(self, args: dict): - deallocates = Deallocate.query.filter_by(author=g.user) \ - .order_by(Deallocate.created.desc()) \ - .paginate(per_page=200) - return things_response( - self.schema.dump(deallocates.items, many=True, nested=0), - deallocates.page, deallocates.per_page, deallocates.total, - deallocates.prev_num, deallocates.next_num - ) - - def one(self, id: uuid.UUID): - """Gets one action.""" - deallocate = Deallocate.query.filter_by(id=id, author=g.user).one() - res = self.schema.jsonify(deallocate, nested=2) - return res From cf3d44a5e377649bb244fbfb8027d96e1bd1ad72 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 15:25:56 +0100 Subject: [PATCH 22/72] adding receives --- .../e93aec8fc41f_added_assigned_action.py | 16 ++++++++++ ereuse_devicehub/resources/action/models.py | 30 +++++++++++-------- ereuse_devicehub/resources/device/models.py | 18 ++++++++++- ereuse_devicehub/resources/device/states.py | 18 ++++++++++- 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 0867d8f9..9212fbcf 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -27,6 +27,7 @@ def get_inv(): return INV def upgrade(): + # Allocate action op.drop_table('allocate', schema=f'{get_inv()}') op.create_table('allocate', sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), @@ -39,7 +40,22 @@ def upgrade(): op.drop_table('deallocate', schema=f'{get_inv()}') + # Add allocate as a column in device op.add_column('device', sa.Column('allocate', sa.Boolean(), nullable=True), schema=f'{get_inv()}') + # Receive action + op.drop_table('receive', schema=f'{get_inv()}') + op.create_table('receive', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('agent_from_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('agent_to_id', postgresql.UUID(as_uuid=True), nullable=False), + + sa.ForeignKeyConstraint(['agent_from_id'], [f'{get_inv()}.agent.id'], ), + sa.ForeignKeyConstraint(['agent_to_id'], [f'{get_inv()}.agent.id'], ), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + def downgrade(): op.drop_table('allocate', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 734a5207..638f28be 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1433,21 +1433,25 @@ class MakeAvailable(ActionWithMultipleDevices): class Receive(JoinedTableMixin, ActionWithMultipleDevices): """The act of physically taking delivery of a device. - The receiver confirms that the devices have arrived, and thus, - they are the + The Agent confirm than the device changes hands and have a new possessor :attr:`ereuse_devicehub.resources.device.models.Device.physical_possessor`. - - This differs from :class:`.Trade` in that trading changes the - political possession. As an example, a transporter can *receive* - a device but it is not it's owner. After the delivery, the - transporter performs another *receive* to the final owner. - - The receiver can optionally take a - :class:`ereuse_devicehub.resources.enums.ReceiverRole`. """ - role = Column(DBEnum(ReceiverRole), - nullable=False, - default=ReceiverRole.Intermediary) + agent_from_id = Column(UUID(as_uuid=True), + ForeignKey(Agent.id), + nullable=False, + default=lambda: g.user.individual.id) + agent_from = relationship(Agent, + backref=backref('actions_agent', lazy=True, **_sorted_actions), + primaryjoin=agent_from_id == Agent.id) + agent_from_id.comment = """ This device go from this agent """ + agent_to_id = Column(UUID(as_uuid=True), + ForeignKey(Agent.id), + nullable=False, + default=lambda: g.user.individual.id) + agent_to = relationship(Agent, + backref=backref('actions_agent', lazy=True, **_sorted_actions), + primaryjoin=agent_to_id == Agent.id) + agent_to_id.comment = """ This device go to this agent """ class Migrate(JoinedTableMixin, ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 682327bb..21688eed 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -221,6 +221,22 @@ class Device(Thing): action = self.last_action_of(*states.Physical.actions()) return states.Physical(action.__class__) + @property + def traking(self): + """The actual traking state, None otherwise.""" + from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): + action = self.last_action_of(*states.Traking.actions()) + return states.Traking(action.__class__) + + @property + def usage(self): + """The actual usage state, None otherwise.""" + from ereuse_devicehub.resources.device import states + with suppress(LookupError, ValueError): + action = self.last_action_of(*states.Usage.actions()) + return states.Usage(action.__class__) + @property def physical_possessor(self): """The actual physical possessor or None. @@ -240,7 +256,7 @@ class Device(Thing): from ereuse_devicehub.resources.action.models import Receive with suppress(LookupError): action = self.last_action_of(Receive) - return action.agent + return action.to @property def working(self): diff --git a/ereuse_devicehub/resources/device/states.py b/ereuse_devicehub/resources/device/states.py index b0d0d439..8a916419 100644 --- a/ereuse_devicehub/resources/device/states.py +++ b/ereuse_devicehub/resources/device/states.py @@ -51,11 +51,27 @@ class Physical(State): :cvar Preparing: The device is going to be or being prepared. :cvar Prepared: The device has been prepared. :cvar Ready: The device is in working conditions. - :cvar InUse: The device is being reported to be in active use. """ ToBeRepaired = e.ToRepair Repaired = e.Repair Preparing = e.ToPrepare Prepared = e.Prepare Ready = e.Ready + + +class Traking(State): + """Traking states. + + :cvar Receive: The device changes hands + """ + Receive = e.Receive + + +class Usage(State): + """Usage states. + + :cvar Allocate: The device is allocate in other Agent (organization, person ...) + :cvar InUse: The device is being reported to be in active use. + """ + Allocate = e.Allocate InUse = e.Live From 13ee6d09e6e3034229b79831f27150aa9029afe8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 15:50:21 +0100 Subject: [PATCH 23/72] adding acctions into receives --- .../versions/e93aec8fc41f_added_assigned_action.py | 2 ++ ereuse_devicehub/resources/action/models.py | 9 ++++++++- ereuse_devicehub/resources/action/models.pyi | 8 +++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 9212fbcf..70778fc9 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -49,9 +49,11 @@ def upgrade(): sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('agent_from_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('agent_to_id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('action_id', postgresql.UUID(as_uuid=True), nullable=True), sa.ForeignKeyConstraint(['agent_from_id'], [f'{get_inv()}.agent.id'], ), sa.ForeignKeyConstraint(['agent_to_id'], [f'{get_inv()}.agent.id'], ), + sa.ForeignKeyConstraint(['action_id'], [f'{get_inv()}.action.id'], ), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), schema=f'{get_inv()}' diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 638f28be..5f3b9f19 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1450,8 +1450,15 @@ class Receive(JoinedTableMixin, ActionWithMultipleDevices): default=lambda: g.user.individual.id) agent_to = relationship(Agent, backref=backref('actions_agent', lazy=True, **_sorted_actions), - primaryjoin=agent_to_id == Agent.id) + primaryjoin=agent_to_id == Action.id) agent_to_id.comment = """ This device go to this agent """ + action_id = Column(UUID(as_uuid=True), + ForeignKey(Action.id), + nullable=True) + action = relationship(Action, + backref=backref('actions_id', lazy=True, **_sorted_actions), + primaryjoin=action_id == Action.id) + action_id.comment = """ This Receive confirm this action """ class Migrate(JoinedTableMixin, ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/action/models.pyi b/ereuse_devicehub/resources/action/models.pyi index 6cd52d73..e95c3945 100644 --- a/ereuse_devicehub/resources/action/models.pyi +++ b/ereuse_devicehub/resources/action/models.pyi @@ -530,11 +530,9 @@ class TransferOwnershipBlockchain(Trade): class Receive(ActionWithMultipleDevices): - role = ... # type:Column - - def __init__(self, **kwargs) -> None: - super().__init__(**kwargs) - self.role = ... # type: ReceiverRole + agent_from = ... # type: relationship + agent_to = ... # type: relationship + action = ... # type: relationship class Migrate(ActionWithMultipleDevices): From c75cdb2c60d823ca215da934dfedc9cb76a02003 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 17:00:04 +0100 Subject: [PATCH 24/72] fixed model receive --- ereuse_devicehub/resources/action/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 5f3b9f19..7d8cfb27 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1441,7 +1441,7 @@ class Receive(JoinedTableMixin, ActionWithMultipleDevices): nullable=False, default=lambda: g.user.individual.id) agent_from = relationship(Agent, - backref=backref('actions_agent', lazy=True, **_sorted_actions), + backref=backref('receive_agent_from', lazy=True, **_sorted_actions), primaryjoin=agent_from_id == Agent.id) agent_from_id.comment = """ This device go from this agent """ agent_to_id = Column(UUID(as_uuid=True), @@ -1449,8 +1449,8 @@ class Receive(JoinedTableMixin, ActionWithMultipleDevices): nullable=False, default=lambda: g.user.individual.id) agent_to = relationship(Agent, - backref=backref('actions_agent', lazy=True, **_sorted_actions), - primaryjoin=agent_to_id == Action.id) + backref=backref('receive_agent_to', lazy=True, **_sorted_actions), + primaryjoin=agent_to_id == Agent.id) agent_to_id.comment = """ This device go to this agent """ action_id = Column(UUID(as_uuid=True), ForeignKey(Action.id), From a1eb0f4c9054a1fa8f8990a5ef7c4bae28f10892 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 17:00:30 +0100 Subject: [PATCH 25/72] end point receive --- ereuse_devicehub/resources/action/__init__.py | 4 ++-- ereuse_devicehub/resources/action/views.py | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 59f49b46..6bbd3937 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -3,7 +3,7 @@ from typing import Callable, Iterable, Tuple from teal.resource import Converters, Resource from ereuse_devicehub.resources.action import schemas -from ereuse_devicehub.resources.action.views import ActionView +from ereuse_devicehub.resources.action.views import ActionView, ReceiveView from ereuse_devicehub.resources.device.sync import Sync @@ -249,7 +249,7 @@ class DisposeProductDef(ActionDef): class ReceiveDef(ActionDef): - VIEW = None + VIEW = ReceiveView SCHEMA = schemas.Receive diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 2d71b4fd..8bc0f28b 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -6,6 +6,7 @@ import shutil from datetime import datetime from distutils.version import StrictVersion from uuid import UUID +from flask.json import jsonify from flask import current_app as app, request, g from sqlalchemy.util import OrderedSet @@ -168,3 +169,11 @@ class ActionView(View): def transfer_ownership(self): """Perform a InitTransfer action to change author_id of device""" pass + +class ReceiveView(View): + + def post(self): + return jsonify('Ok') + + def find(self, args): + return jsonify('Ok find') From 67d7e27cf9d191cda04d7a49df19ff7a76704a85 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 19 Nov 2020 21:04:14 +0100 Subject: [PATCH 26/72] adding view of receives --- ereuse_devicehub/resources/action/schemas.py | 5 +++- ereuse_devicehub/resources/action/views.py | 27 ++++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 0eb3f1c4..397cf8b2 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -11,6 +11,7 @@ from teal.resource import Schema from ereuse_devicehub.marshmallow import NestedOn from ereuse_devicehub.resources import enums from ereuse_devicehub.resources.action import models as m +from ereuse_devicehub.resources.action import schemas as s_action from ereuse_devicehub.resources.agent import schemas as s_agent from ereuse_devicehub.resources.device import schemas as s_device from ereuse_devicehub.resources.enums import AppearanceRange, BiosAccessRange, FunctionalityRange, \ @@ -433,7 +434,9 @@ class TransferOwnershipBlockchain(Trade): class Receive(ActionWithMultipleDevices): __doc__ = m.Receive.__doc__ - role = EnumField(ReceiverRole) + agent_from = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Receive.agent_from_id.comment) + agent_to = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Receive.agent_to_id.comment) + action = NestedOn(s_action.Action, only_query='id', required=False, comment=m.Receive.action_id.comment) class Migrate(ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 8bc0f28b..84c92b0f 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -14,8 +14,9 @@ from teal.marshmallow import ValidationError from teal.resource import View from ereuse_devicehub.db import db -from ereuse_devicehub.resources.action.models import Action, RateComputer, Snapshot, VisualTest, \ - InitTransfer +from ereuse_devicehub.query import things_response +from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, + InitTransfer, Receive) from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity from ereuse_devicehub.resources.user.exceptions import InsufficientPermission @@ -173,7 +174,23 @@ class ActionView(View): class ReceiveView(View): def post(self): - return jsonify('Ok') + # return jsonify('Ok') + """ Create one receive """ + res_json = request.get_json() + receive = Receive(**res_json) + db.session.add(receive) + db.session().final_flush() + ret = self.schema.jsonify(receive) + ret.status_code = 201 + db.session.commit() + return ret - def find(self, args): - return jsonify('Ok find') + def find(self, args: dict): + receives = Receive.query.filter_by(author=g.user) \ + .order_by(Receive.created.desc()) \ + .paginate(per_page=200) + return things_response( + self.schema.dump(receives.items, many=True, nested=0), + receives.page, receives.per_page, receives.total, + receives.prev_num, receives.next_num + ) From 32a17decd70aba1ba285980775caed7d5ce244a0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 20 Nov 2020 18:16:56 +0100 Subject: [PATCH 27/72] remove receives --- .../e93aec8fc41f_added_assigned_action.py | 15 +-------- ereuse_devicehub/resources/action/__init__.py | 7 +---- ereuse_devicehub/resources/action/models.py | 31 ------------------- ereuse_devicehub/resources/action/schemas.py | 7 ----- ereuse_devicehub/resources/action/views.py | 25 +-------------- ereuse_devicehub/resources/device/models.py | 2 +- ereuse_devicehub/resources/device/states.py | 3 +- 7 files changed, 6 insertions(+), 84 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 70778fc9..88c61fbf 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -41,23 +41,10 @@ def upgrade(): op.drop_table('deallocate', schema=f'{get_inv()}') # Add allocate as a column in device - op.add_column('device', sa.Column('allocate', sa.Boolean(), nullable=True), schema=f'{get_inv()}') + op.add_column('device', sa.Column('allocated', sa.Boolean(), nullable=True), schema=f'{get_inv()}') # Receive action op.drop_table('receive', schema=f'{get_inv()}') - op.create_table('receive', - sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), - sa.Column('agent_from_id', postgresql.UUID(as_uuid=True), nullable=False), - sa.Column('agent_to_id', postgresql.UUID(as_uuid=True), nullable=False), - sa.Column('action_id', postgresql.UUID(as_uuid=True), nullable=True), - - sa.ForeignKeyConstraint(['agent_from_id'], [f'{get_inv()}.agent.id'], ), - sa.ForeignKeyConstraint(['agent_to_id'], [f'{get_inv()}.agent.id'], ), - sa.ForeignKeyConstraint(['action_id'], [f'{get_inv()}.action.id'], ), - sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), - sa.PrimaryKeyConstraint('id'), - schema=f'{get_inv()}' - ) def downgrade(): op.drop_table('allocate', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 6bbd3937..01b32ac4 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -3,7 +3,7 @@ from typing import Callable, Iterable, Tuple from teal.resource import Converters, Resource from ereuse_devicehub.resources.action import schemas -from ereuse_devicehub.resources.action.views import ActionView, ReceiveView +from ereuse_devicehub.resources.action.views import ActionView from ereuse_devicehub.resources.device.sync import Sync @@ -248,11 +248,6 @@ class DisposeProductDef(ActionDef): SCHEMA = schemas.DisposeProduct -class ReceiveDef(ActionDef): - VIEW = ReceiveView - SCHEMA = schemas.Receive - - class MigrateToDef(ActionDef): VIEW = None SCHEMA = schemas.MigrateTo diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 7d8cfb27..7f64cd7e 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1430,37 +1430,6 @@ class MakeAvailable(ActionWithMultipleDevices): pass -class Receive(JoinedTableMixin, ActionWithMultipleDevices): - """The act of physically taking delivery of a device. - - The Agent confirm than the device changes hands and have a new possessor - :attr:`ereuse_devicehub.resources.device.models.Device.physical_possessor`. - """ - agent_from_id = Column(UUID(as_uuid=True), - ForeignKey(Agent.id), - nullable=False, - default=lambda: g.user.individual.id) - agent_from = relationship(Agent, - backref=backref('receive_agent_from', lazy=True, **_sorted_actions), - primaryjoin=agent_from_id == Agent.id) - agent_from_id.comment = """ This device go from this agent """ - agent_to_id = Column(UUID(as_uuid=True), - ForeignKey(Agent.id), - nullable=False, - default=lambda: g.user.individual.id) - agent_to = relationship(Agent, - backref=backref('receive_agent_to', lazy=True, **_sorted_actions), - primaryjoin=agent_to_id == Agent.id) - agent_to_id.comment = """ This device go to this agent """ - action_id = Column(UUID(as_uuid=True), - ForeignKey(Action.id), - nullable=True) - action = relationship(Action, - backref=backref('actions_id', lazy=True, **_sorted_actions), - primaryjoin=action_id == Action.id) - action_id.comment = """ This Receive confirm this action """ - - class Migrate(JoinedTableMixin, ActionWithMultipleDevices): """Moves the devices to a new database/inventory. Devices cannot be modified anymore at the previous database. diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 397cf8b2..8534b8f7 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -432,13 +432,6 @@ class TransferOwnershipBlockchain(Trade): __doc__ = m.TransferOwnershipBlockchain.__doc__ -class Receive(ActionWithMultipleDevices): - __doc__ = m.Receive.__doc__ - agent_from = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Receive.agent_from_id.comment) - agent_to = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Receive.agent_to_id.comment) - action = NestedOn(s_action.Action, only_query='id', required=False, comment=m.Receive.action_id.comment) - - class Migrate(ActionWithMultipleDevices): __doc__ = m.Migrate.__doc__ other = URL() diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 84c92b0f..1e0908cb 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -16,7 +16,7 @@ from teal.resource import View from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, - InitTransfer, Receive) + InitTransfer) from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity from ereuse_devicehub.resources.user.exceptions import InsufficientPermission @@ -171,26 +171,3 @@ class ActionView(View): """Perform a InitTransfer action to change author_id of device""" pass -class ReceiveView(View): - - def post(self): - # return jsonify('Ok') - """ Create one receive """ - res_json = request.get_json() - receive = Receive(**res_json) - db.session.add(receive) - db.session().final_flush() - ret = self.schema.jsonify(receive) - ret.status_code = 201 - db.session.commit() - return ret - - def find(self, args: dict): - receives = Receive.query.filter_by(author=g.user) \ - .order_by(Receive.created.desc()) \ - .paginate(per_page=200) - return things_response( - self.schema.dump(receives.items, many=True, nested=0), - receives.page, receives.per_page, receives.total, - receives.prev_num, receives.next_num - ) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 21688eed..399bab92 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -256,7 +256,7 @@ class Device(Thing): from ereuse_devicehub.resources.action.models import Receive with suppress(LookupError): action = self.last_action_of(Receive) - return action.to + return action.agent_to @property def working(self): diff --git a/ereuse_devicehub/resources/device/states.py b/ereuse_devicehub/resources/device/states.py index 8a916419..a67a410d 100644 --- a/ereuse_devicehub/resources/device/states.py +++ b/ereuse_devicehub/resources/device/states.py @@ -64,7 +64,8 @@ class Traking(State): :cvar Receive: The device changes hands """ - Receive = e.Receive + # Receive = e.Receive + pass class Usage(State): From 0415b7efb96c4c00c3c275a3014a94228a76d233 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 21 Nov 2020 13:17:23 +0100 Subject: [PATCH 28/72] deallocate --- .../e93aec8fc41f_added_assigned_action.py | 7 ++++ ereuse_devicehub/resources/action/models.py | 7 +++- .../resources/allocate/definitions.py | 10 +++-- ereuse_devicehub/resources/allocate/views.py | 42 +++++++++---------- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 88c61fbf..f1940919 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -38,7 +38,14 @@ def upgrade(): schema=f'{get_inv()}' ) + # Deallocate action op.drop_table('deallocate', schema=f'{get_inv()}') + op.create_table('deallocate', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) # Add allocate as a column in device op.add_column('device', sa.Column('allocated', sa.Boolean(), nullable=True), schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 7f64cd7e..7da55f9d 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -312,13 +312,18 @@ class Remove(ActionWithOneDevice): class Allocate(JoinedTableMixin, ActionWithMultipleDevices): - """The act of assigned one list of devices to one person of the system or not + """The act of allocate one list of devices to one person """ code = Column(CIText(), default='', nullable=True) code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=False) +class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): + """The act of deallocate one list of devices to one person of the system or not + """ + pass + class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): """An erasure attempt to a ``DataStorage``. The action contains information about success and nature of the erasure. diff --git a/ereuse_devicehub/resources/allocate/definitions.py b/ereuse_devicehub/resources/allocate/definitions.py index 38e740ed..17ab926e 100644 --- a/ereuse_devicehub/resources/allocate/definitions.py +++ b/ereuse_devicehub/resources/allocate/definitions.py @@ -1,10 +1,14 @@ -from typing import Callable, Iterable, Tuple from ereuse_devicehub.resources.action import schemas from teal.resource import Resource -from ereuse_devicehub.resources.allocate.views import AllocateView +from ereuse_devicehub.resources.allocate.views import AllocateView, DeallocateView -class AssignedDef(Resource): +class AllocateDef(Resource): VIEW = AllocateView SCHEMA = schemas.Allocate + AUTH = True +class DeallocateDef(Resource): + VIEW = DeallocateView + SCHEMA = schemas.Deallocate + AUTH = True diff --git a/ereuse_devicehub/resources/allocate/views.py b/ereuse_devicehub/resources/allocate/views.py index d1df9e2a..7864fe62 100644 --- a/ereuse_devicehub/resources/allocate/views.py +++ b/ereuse_devicehub/resources/allocate/views.py @@ -1,43 +1,39 @@ -import uuid -# from typing import Callable, Iterable, Tuple from flask import g, request -# from flask.json import jsonify from teal.resource import View -from ereuse_devicehub import auth from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response -from ereuse_devicehub.resources.action.models import Allocate +from ereuse_devicehub.resources.action.models import Allocate, Deallocate -class AllocateView(View): - @auth.Auth.requires_auth - def get(self, id: uuid.UUID) -> Allocate: - return super().get(id) +class AllocateMix(): + model = None - @auth.Auth.requires_auth def post(self): - """ Create one allocate """ + """ Create one res_obj """ res_json = request.get_json() - allocate = Allocate(**res_json) - db.session.add(allocate) + res_obj = model(**res_json) + db.session.add(res_obj) db.session().final_flush() - ret = self.schema.jsonify(allocate) + ret = self.schema.jsonify(res_obj) ret.status_code = 201 db.session.commit() return ret def find(self, args: dict): - allocates = Allocate.query.filter_by(author=g.user) \ - .order_by(Allocate.created.desc()) \ + res_objs = model.query.filter_by(author=g.user) \ + .order_by(model.created.desc()) \ .paginate(per_page=200) return things_response( - self.schema.dump(allocates.items, many=True, nested=0), - allocates.page, allocates.per_page, allocates.total, - allocates.prev_num, allocates.next_num + self.schema.dump(res_objs.items, many=True, nested=0), + res_objs.page, res_objs.per_page, res_objs.total, + res_objs.prev_num, res_objs.next_num ) - def one(self, id: uuid.UUID): - """Gets one action.""" - allocate = Allocate.query.filter_by(id=id, author=g.user).one() - return self.schema.jsonify(allocate, nested=2) + +class AllocateView(AllocateMix): + model = Allocate + + +class DeallocateView(AllocateMix): + model = Deallocate From 775cd9a215e8a982ca19b307aa9d2c88addff163 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 21 Nov 2020 15:52:29 +0100 Subject: [PATCH 29/72] fixing bugs --- ereuse_devicehub/resources/action/schemas.py | 6 +++++- ereuse_devicehub/resources/allocate/views.py | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 8534b8f7..0ac2586e 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -69,13 +69,17 @@ class Allocate(ActionWithMultipleDevices): description = SanitizedStr(default='', description=m.Action.description.comment) start_time = DateTime(data_key='start_time', description=m.Action.start_time.comment) end_time = DateTime(data_key='end_time', description=m.Action.end_time.comment) - code = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), + code = SanitizedStr(data_key='Transaction', validate=Length(min=1, max=STR_BIG_SIZE), required=False, description='The code of the agent to assigned.') end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")], required=True) +class Deallocate(ActionWithMultipleDevices): + __doc__ = m.Deallocate.__doc__ + + class EraseBasic(ActionWithOneDevice): __doc__ = m.EraseBasic.__doc__ steps = NestedOn('Step', many=True) diff --git a/ereuse_devicehub/resources/allocate/views.py b/ereuse_devicehub/resources/allocate/views.py index 7864fe62..cd044203 100644 --- a/ereuse_devicehub/resources/allocate/views.py +++ b/ereuse_devicehub/resources/allocate/views.py @@ -12,7 +12,7 @@ class AllocateMix(): def post(self): """ Create one res_obj """ res_json = request.get_json() - res_obj = model(**res_json) + res_obj = self.model(**res_json) db.session.add(res_obj) db.session().final_flush() ret = self.schema.jsonify(res_obj) @@ -21,8 +21,8 @@ class AllocateMix(): return ret def find(self, args: dict): - res_objs = model.query.filter_by(author=g.user) \ - .order_by(model.created.desc()) \ + res_objs = self.model.query.filter_by(author=g.user) \ + .order_by(self.model.created.desc()) \ .paginate(per_page=200) return things_response( self.schema.dump(res_objs.items, many=True, nested=0), @@ -31,9 +31,9 @@ class AllocateMix(): ) -class AllocateView(AllocateMix): +class AllocateView(AllocateMix, View): model = Allocate -class DeallocateView(AllocateMix): +class DeallocateView(AllocateMix, View): model = Deallocate From 0e539196078cd9815a365299545e2ff14fdeb633 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 21 Nov 2020 19:10:31 +0100 Subject: [PATCH 30/72] listener --- ereuse_devicehub/resources/action/models.py | 69 +++++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 7da55f9d..b856f221 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -43,7 +43,7 @@ from ereuse_devicehub.resources.device.models import Component, Computer, DataSt Device, Laptop, Server from ereuse_devicehub.resources.enums import AppearanceRange, BatteryHealth, BiosAccessRange, \ ErasureStandards, FunctionalityRange, PhysicalErasureMethod, PriceSoftware, \ - R_NEGATIVE, R_POSITIVE, RatingRange, ReceiverRole, Severity, SnapshotSoftware, \ + R_NEGATIVE, R_POSITIVE, RatingRange, Severity, SnapshotSoftware, \ TestDataStorageLength from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing from ereuse_devicehub.resources.user.models import User @@ -91,7 +91,7 @@ class Action(Thing): end_time = Column(db.TIMESTAMP(timezone=True)) end_time.comment = """When the action ends. For some actions like reservations the time when they expire, for others like renting - the time the end rents. For punctual actions it is the time + the time the end rents. For punctual actions it is the time they are performed; it differs with ``created`` in which created is the where the system received the action. """ @@ -115,7 +115,7 @@ class Action(Thing): backref=backref('authored_actions', lazy=True, collection_class=set), primaryjoin=author_id == User.id) author_id.comment = """The user that recorded this action in the system. - + This does not necessarily has to be the person that produced the action in the real world. For that purpose see ``agent``. @@ -129,9 +129,8 @@ class Action(Thing): agent = relationship(Agent, backref=backref('actions_agent', lazy=True, **_sorted_actions), primaryjoin=agent_id == Agent.id) - agent_id.comment = """The direct performer or driver of the action. - e.g. John wrote a book. - + agent_id.comment = """The direct performer or driver of the action. e.g. John wrote a book. + It can differ with the user that registered the action in the system, which can be in their behalf. """ @@ -142,14 +141,14 @@ class Action(Thing): order_by=lambda: Component.id, collection_class=OrderedSet) components.comment = """The components that are affected by the action. - + When performing actions to parent devices their components are affected too. - + For example: an ``Allocate`` is performed to a Computer and this relationship is filled with the components the computer had at the time of the action. - + For Add and Remove though, this has another meaning: the components that are added or removed. """ @@ -157,9 +156,9 @@ class Action(Thing): parent = relationship(Computer, backref=backref('actions_parent', lazy=True, **_sorted_actions), primaryjoin=parent_id == Computer.id) - parent_id.comment = """For actions that are performed to components, + parent_id.comment = """For actions that are performed to components, the device parent at that time. - + For example: for a ``EraseBasic`` performed on a data storage, this would point to the computer that contained this data storage, if any. """ @@ -324,6 +323,7 @@ class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): """ pass + class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): """An erasure attempt to a ``DataStorage``. The action contains information about success and nature of the erasure. @@ -534,7 +534,7 @@ class Snapshot(JoinedWithOneDeviceMixin, ActionWithOneDevice): version = Column(StrictVersionType(STR_SM_SIZE), nullable=False) software = Column(DBEnum(SnapshotSoftware), nullable=False) elapsed = Column(Interval) - elapsed.comment = """For Snapshots made with Workbench, the total amount + elapsed.comment = """For Snapshots made with Workbench, the total amount of time it took to complete. """ @@ -681,11 +681,11 @@ class MeasureBattery(TestMixin, Test): voltage = db.Column(db.Integer, nullable=False) voltage.comment = """The actual voltage of the battery, in mV.""" cycle_count = db.Column(db.Integer) - cycle_count.comment = """The number of full charges – discharges + cycle_count.comment = """The number of full charges – discharges cycles. """ health = db.Column(db.Enum(BatteryHealth)) - health.comment = """The health of the Battery. + health.comment = """The health of the Battery. Only reported in Android. """ @@ -884,12 +884,12 @@ class TestBios(TestMixin, Test): beeps_power_on = Column(Boolean) beeps_power_on.comment = """Whether there are no beeps or error codes when booting up. - + Reference: R2 provision 6 page 23. """ access_range = Column(DBEnum(BiosAccessRange)) access_range.comment = """Difficulty to modify the boot menu. - + This is used as an usability measure for accessing and modifying a bios, specially as something as important as modifying the boot menu. @@ -1349,7 +1349,7 @@ class Trade(JoinedTableMixin, ActionWithMultipleDevices): extend `Schema's Trade `_. """ shipping_date = Column(db.TIMESTAMP(timezone=True)) - shipping_date.comment = """When are the devices going to be ready + shipping_date.comment = """When are the devices going to be ready for shipping? """ invoice_number = Column(CIText()) @@ -1358,7 +1358,7 @@ class Trade(JoinedTableMixin, ActionWithMultipleDevices): price = relationship(Price, backref=backref('trade', lazy=True, uselist=False), primaryjoin=price_id == Price.id) - price_id.comment = """The price set for this trade. + price_id.comment = """The price set for this trade. If no price is set it is supposed that the trade was not payed, usual in donations. """ @@ -1372,8 +1372,7 @@ class Trade(JoinedTableMixin, ActionWithMultipleDevices): confirms = relationship(Organize, backref=backref('confirmation', lazy=True, uselist=False), primaryjoin=confirms_id == Organize.id) - confirms_id.comment = """An organize action that this association confirms. - + confirms_id.comment = """An organize action that this association confirms. For example, a ``Sell`` or ``Rent`` can confirm a ``Reserve`` action. """ @@ -1531,6 +1530,36 @@ def update_parent(target: Union[EraseBasic, Test, Install], device: Device, _, _ target.parent = device.parent +@event.listens_for(Allocate.devices, 'append') +def update_allocated(target: Allocate, device, initiatort): + """Mark one device as allocated.""" + +# for device in target.devices: + actions = [a for a in device.actions] + actions.sort(key=lambda x: x.created) + actions.reverse() + allocate = None + #import pdb; pdb.set_trace() + for a in actions: + if isinstance(a, Allocate): + allocate = a + break + if isinstance(a, Deallocate): + break + + if allocate: + txt = "You need deallocate before allocate this device again" + same_allocate = [ + allocate.code == target.code, + allocate.start_time == target.start_time, + allocate.end_users == target.end_users + ] + assert all(same_allocate), txt + + import pdb; pdb.set_trace() + target.allocated = True + + class InvalidRangeForPrice(ValueError): pass From ee702884329e0ad73fd32c80a58e4d25a8367774 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sun, 22 Nov 2020 18:47:58 +0100 Subject: [PATCH 31/72] validate errors of allocate in scheme instead of signal --- ereuse_devicehub/resources/action/models.py | 30 ---------------- ereuse_devicehub/resources/action/schemas.py | 37 ++++++++++++++++++++ ereuse_devicehub/resources/device/models.py | 6 +++- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index b856f221..4b14fda9 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1530,36 +1530,6 @@ def update_parent(target: Union[EraseBasic, Test, Install], device: Device, _, _ target.parent = device.parent -@event.listens_for(Allocate.devices, 'append') -def update_allocated(target: Allocate, device, initiatort): - """Mark one device as allocated.""" - -# for device in target.devices: - actions = [a for a in device.actions] - actions.sort(key=lambda x: x.created) - actions.reverse() - allocate = None - #import pdb; pdb.set_trace() - for a in actions: - if isinstance(a, Allocate): - allocate = a - break - if isinstance(a, Deallocate): - break - - if allocate: - txt = "You need deallocate before allocate this device again" - same_allocate = [ - allocate.code == target.code, - allocate.start_time == target.start_time, - allocate.end_users == target.end_users - ] - assert all(same_allocate), txt - - import pdb; pdb.set_trace() - target.allocated = True - - class InvalidRangeForPrice(ValueError): pass diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 0ac2586e..f39b5e6f 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -75,10 +75,47 @@ class Allocate(ActionWithMultipleDevices): end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")], required=True) + @validates_schema + def validate_allocate(self, data: dict): + for device in data['devices']: + actions = [a for a in device.actions] + actions.sort(key=lambda x: x.created) + actions.reverse() + allocate = None + + for a in actions: + if isinstance(a, m.Allocate): + allocate = a + break + if isinstance(a, m.Deallocate): + break + + if allocate: + txt = "You need deallocate before allocate this device again" + same_allocate = [ + allocate.code == data['code'], + allocate.start_time == data['start_time'], + allocate.end_users == data['end_users'] + ] + if not all(same_allocate): + raise ValidationError(txt) + + device.allocated = True + class Deallocate(ActionWithMultipleDevices): __doc__ = m.Deallocate.__doc__ + @validates_schema + def validate_deallocate(self, data: dict): + txt = "Sorry some of this devices are actually deallocate" + + for device in data['devices']: + if hasattr(device, 'allocated') and device.allocated: + device.allocated = False + else: + raise ValidationError(txt) + class EraseBasic(ActionWithOneDevice): __doc__ = m.EraseBasic.__doc__ diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 399bab92..54f30324 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -106,6 +106,9 @@ class Device(Thing): image = db.Column(db.URL) image.comment = "An image of the device." + allocated = db.Column(Boolean, default=False) + allocated.comment = "An image of the device." + _NON_PHYSICAL_PROPS = { 'id', 'type', @@ -125,7 +128,8 @@ class Device(Thing): 'variant', 'version', 'sku', - 'image' + 'image', + 'allocated' } __table_args__ = ( From 73716a73310c02d4ec6a642313c1ed5f0ca3e821 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 11:43:30 +0100 Subject: [PATCH 32/72] fixing tests --- ereuse_devicehub/resources/action/__init__.py | 5 +++++ ereuse_devicehub/resources/device/models.py | 10 ++++++---- ereuse_devicehub/resources/device/schemas.py | 2 ++ ereuse_devicehub/resources/device/states.py | 2 ++ tests/test_action.py | 2 +- tests/test_basic.py | 6 ++++-- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 01b32ac4..1cf8c1b7 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -228,6 +228,11 @@ class DonateDef(ActionDef): SCHEMA = schemas.Donate +class RentDef(ActionDef): + VIEW = None + SCHEMA = schemas.Rent + + class MakeAvailable(ActionDef): VIEW = None SCHEMA = schemas.MakeAvailable diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 54f30324..907b61e0 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -257,10 +257,12 @@ class Device(Thing): and :class:`ereuse_devicehub.resources.action.models.Receive` changes it. """ - from ereuse_devicehub.resources.action.models import Receive - with suppress(LookupError): - action = self.last_action_of(Receive) - return action.agent_to + pass + # TODO @cayop uncomment this lines for link the possessor with the device + # from ereuse_devicehub.resources.action.models import Receive + # with suppress(LookupError): + # action = self.last_action_of(Receive) + # return action.agent_to @property def working(self): diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index e6eb6b4f..cd86a671 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -52,6 +52,8 @@ class Device(Thing): price = NestedOn('Price', dump_only=True, description=m.Device.price.__doc__) trading = EnumField(states.Trading, dump_only=True, description=m.Device.trading.__doc__) physical = EnumField(states.Physical, dump_only=True, description=m.Device.physical.__doc__) + traking= EnumField(states.Traking, dump_only=True, description=m.Device.physical.__doc__) + usage = EnumField(states.Usage, dump_only=True, description=m.Device.physical.__doc__) physical_possessor = NestedOn('Agent', dump_only=True, data_key='physicalPossessor') production_date = DateTime('iso', description=m.Device.updated.comment, diff --git a/ereuse_devicehub/resources/device/states.py b/ereuse_devicehub/resources/device/states.py index a67a410d..4d03778a 100644 --- a/ereuse_devicehub/resources/device/states.py +++ b/ereuse_devicehub/resources/device/states.py @@ -72,7 +72,9 @@ class Usage(State): """Usage states. :cvar Allocate: The device is allocate in other Agent (organization, person ...) + :cvar Deallocate: The device is deallocate and return to the owner :cvar InUse: The device is being reported to be in active use. """ Allocate = e.Allocate + Deallocate = e.Deallocate InUse = e.Live diff --git a/tests/test_action.py b/tests/test_action.py index ba095685..f5d00280 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -265,7 +265,7 @@ def test_live(): assert live['subdivision'] == 'ES-CA' assert live['country'] == 'ES' device, _ = client.get(res=Device, item=live['device']['id']) - assert device['physical'] == states.Physical.InUse.name + assert device['usage'] == states.Usage.InUse.name @pytest.mark.mvp diff --git a/tests/test_basic.py b/tests/test_basic.py index fe3dd1da..065ba42c 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -100,7 +100,9 @@ def test_api_docs(client: Client): '/videoconferences/{id}/merge/', '/videos/{id}/merge/', '/wireless-access-points/{id}/merge/', - '/versions/' + '/versions/', + '/allocates/', + '/deallocates/', } assert docs['info'] == {'title': 'Devicehub', 'version': '0.2'} assert docs['components']['securitySchemes']['bearerAuth'] == { @@ -111,4 +113,4 @@ def test_api_docs(client: Client): 'scheme': 'basic', 'name': 'Authorization' } - assert len(docs['definitions']) == 122 + assert len(docs['definitions']) == 123 From 78c1f1326037252f2f9470d259a151f1e38ef69e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 15:53:25 +0100 Subject: [PATCH 33/72] clean code --- ereuse_devicehub/resources/action/schemas.py | 43 ++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index f39b5e6f..f7952ae9 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -68,43 +68,44 @@ class Allocate(ActionWithMultipleDevices): agent = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Trade.to_comment) description = SanitizedStr(default='', description=m.Action.description.comment) start_time = DateTime(data_key='start_time', description=m.Action.start_time.comment) - end_time = DateTime(data_key='end_time', description=m.Action.end_time.comment) + end_time = DateTime(data_key='end_time', required=False, + description=m.Action.end_time.comment) code = SanitizedStr(data_key='Transaction', validate=Length(min=1, max=STR_BIG_SIZE), - required=False, - description='The code of the agent to assigned.') + required=False, + description='The code of the agent to assigned.') end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")], - required=True) + required=True) @validates_schema def validate_allocate(self, data: dict): + txt = "You need deallocate before allocate this device again" for device in data['devices']: + if device.allocated == False: + device.allocated = True + continue + actions = [a for a in device.actions] actions.sort(key=lambda x: x.created) actions.reverse() - allocate = None - for a in actions: - if isinstance(a, m.Allocate): - allocate = a - break - if isinstance(a, m.Deallocate): + for allocate in actions: + if isinstance(allocate, m.Allocate): + same_allocate = [ + allocate.code == data['code'], + allocate.start_time == data['start_time'], + allocate.end_users == data['end_users'] + ] + if not all(same_allocate): + raise ValidationError(txt) + if isinstance(allocate, m.Deallocate): break - if allocate: - txt = "You need deallocate before allocate this device again" - same_allocate = [ - allocate.code == data['code'], - allocate.start_time == data['start_time'], - allocate.end_users == data['end_users'] - ] - if not all(same_allocate): - raise ValidationError(txt) - - device.allocated = True + device.allocated = True class Deallocate(ActionWithMultipleDevices): __doc__ = m.Deallocate.__doc__ + start_time = DateTime(data_key='start_time', description=m.Action.start_time.comment) @validates_schema def validate_deallocate(self, data: dict): From 3e8eb03b58bc1f0d6b82e2edb281a5c201039316 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 15:53:56 +0100 Subject: [PATCH 34/72] fixing bug --- ereuse_devicehub/resources/device/schemas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index cd86a671..d3671c1b 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -65,6 +65,7 @@ class Device(Thing): variant = SanitizedStr(description=m.Device.variant.comment) sku = SanitizedStr(description=m.Device.sku.comment) image = URL(description=m.Device.image.comment) + allocated = Boolean(description=m.Device.allocated.comment) @pre_load def from_actions_to_actions_one(self, data: dict): From 6ae0218a1fc8404ccb9021198e60c22a057e826b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 15:55:24 +0100 Subject: [PATCH 35/72] adding tests for allocate and deallocate --- tests/test_action.py | 74 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/tests/test_action.py b/tests/test_action.py index f5d00280..d6fab3f2 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1,9 +1,11 @@ import ipaddress +import copy +import pytest + from datetime import timedelta from decimal import Decimal from typing import Tuple, Type -import pytest from flask import current_app as app, g from sqlalchemy.util import OrderedSet from teal.enums import Currency, Subdivision @@ -268,6 +270,76 @@ def test_live(): assert device['usage'] == states.Usage.InUse.name +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_allocate(user: UserClient): + """ Tests allocate """ + snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) + device_id = snapshot['device']['id'] + post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + "devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00", + "end_time": "2020-12-01T02:00:00+00:00" + } + + allocate, _ = user.post(res=models.Allocate, data=post_request) + allocate_get, _ = user.get(res=models.Action, item=allocate['id']) + for f in ('name', 'Transaction', 'created', 'start_time', 'end_users'): + assert allocate_get[f] == allocate[f] + # Normal allocate + device, _ = user.get(res=Device, item=device_id) + assert device['allocated'] == True + action = [a for a in device['actions'] if a['type'] == 'Allocate'][0] + assert action['Transaction'] == allocate['Transaction'] + assert action['created'] == allocate['created'] + assert action['start_time'] == allocate['start_time'] + assert action['end_users'] == allocate['end_users'] + assert action['name'] == allocate['name'] + + post_bad_request1 = copy.copy(post_request) + post_bad_request1['end_users'] = 2 + post_bad_request2 = copy.copy(post_request) + post_bad_request2['start_time'] = "2020-11-01T02:00:00+00:01" + post_bad_request3 = copy.copy(post_request) + post_bad_request3['Transaction'] = "aaa" + res1, _ = user.post(res=models.Allocate, data=post_bad_request1, status=422) + res2, _ = user.post(res=models.Allocate, data=post_bad_request2, status=422) + res3, _ = user.post(res=models.Allocate, data=post_bad_request3, status=422) + for r in (res1, res2, res3): + assert r['code'] == 422 + assert r['type'] == 'ValidationError' + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_deallocate(user: UserClient): + """ Tests deallocate """ + snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) + device_id = snapshot['device']['id'] + post_deallocate = {"start_time": "2020-11-01T02:00:00+00:00", + "devices": [device_id] + } + res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) + assert res['code'] == 422 + assert res['type'] == 'ValidationError' + post_allocate = {"Transaction": "ccc", "name": "John", "end_users": 1, + "devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00", + "end_time": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_allocate) + device, _ = user.get(res=Device, item=device_id) + assert device['allocated'] == True + deallocate, _ = user.post(res=models.Deallocate, data=post_deallocate) + assert deallocate['start_time'] == post_deallocate['start_time'] + assert deallocate['devices'][0]['id'] == device_id + assert deallocate['devices'][0]['allocated'] == False + res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) + assert res['code'] == 422 + assert res['type'] == 'ValidationError' + + @pytest.mark.mvp @pytest.mark.parametrize('action_model_state', (pytest.param(ams, id=ams[0].__name__) From 6334120237cdf20a2fa61f98bb2d99a94634c2a2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 18:03:06 +0100 Subject: [PATCH 36/72] Adding endpoint of metrics --- ereuse_devicehub/config.py | 6 ++-- ereuse_devicehub/resources/metric/__init__.py | 0 .../resources/metric/definitions.py | 32 +++++++++++++++++++ ereuse_devicehub/resources/metric/schema.py | 11 +++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 ereuse_devicehub/resources/metric/__init__.py create mode 100644 ereuse_devicehub/resources/metric/definitions.py create mode 100644 ereuse_devicehub/resources/metric/schema.py diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index 6de4a9e1..c0b1a955 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -15,6 +15,7 @@ from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.enums import PriceSoftware from ereuse_devicehub.resources.versions import versions from ereuse_devicehub.resources.allocate import definitions as allocate_def +from ereuse_devicehub.resources.metric import definitions as metric_def class DevicehubConfig(Config): @@ -29,8 +30,9 @@ class DevicehubConfig(Config): import_resource(documents), import_resource(inventory), import_resource(versions), - import_resource(allocate_def)), - ) + import_resource(allocate_def), + import_resource(metric_def), + ),) PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str] DB_USER = config('DB_USER', 'dhub') DB_PASSWORD = config('DB_PASSWORD', 'ereuse') diff --git a/ereuse_devicehub/resources/metric/__init__.py b/ereuse_devicehub/resources/metric/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ereuse_devicehub/resources/metric/definitions.py b/ereuse_devicehub/resources/metric/definitions.py new file mode 100644 index 00000000..70901e2b --- /dev/null +++ b/ereuse_devicehub/resources/metric/definitions.py @@ -0,0 +1,32 @@ +from flask import request, g, jsonify +from ereuse_devicehub.resources.action import schemas +from teal.resource import Resource, View + +from ereuse_devicehub.resources.action.models import Allocate +from ereuse_devicehub.resources.device import models as m +from ereuse_devicehub.resources.metric.schema import Metric + + +class MetricsView(View): + def find(self, args: dict): + self.params = request.get_json() + metrics = { + "allocateds": self.allocated(), + "live": 0, + "null": 0, + } + return jsonify(metrics) + + def allocated(self): + return Allocate.query.filter( + Allocate.start_time.between( + self.params['start_time'], self.params['end_time'] + ) + ).count() + + +class MetricDef(Resource): + __type__ = 'Metric' + VIEW = MetricsView + SCHEMA = Metric + AUTH = True diff --git a/ereuse_devicehub/resources/metric/schema.py b/ereuse_devicehub/resources/metric/schema.py new file mode 100644 index 00000000..8bee7c81 --- /dev/null +++ b/ereuse_devicehub/resources/metric/schema.py @@ -0,0 +1,11 @@ +from teal.resource import Schema +from marshmallow.fields import DateTime + +class Metric(Schema): + """ + This schema filter dates for search the metrics + """ + start_time = DateTime(data_key='start_time', required=True, + description="Start date for search metrics") + end_time = DateTime(data_key='end_time', required=True, + description="End date for search metrics") From 19d0410e744a473ecd172d13af3cbfabcfeac161 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 18:08:40 +0100 Subject: [PATCH 37/72] bugfix --- tests/test_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 2670a684..8fcf36e3 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -100,7 +100,7 @@ def test_api_docs(client: Client): '/videoconferences/{dev1_id}/merge/{dev2_id}', '/videos/{dev1_id}/merge/{dev2_id}', '/wireless-access-points/{dev1_id}/merge/{dev2_id}', - '/versions/' + '/versions/', '/allocates/', '/deallocates/', } From a664b8cc6c4da7b5a5926176b2e54c5d41e57ac1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 18:34:44 +0100 Subject: [PATCH 38/72] adding metrics in test_basic --- tests/test_basic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_basic.py b/tests/test_basic.py index 8fcf36e3..520d3845 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -103,6 +103,7 @@ def test_api_docs(client: Client): '/versions/', '/allocates/', '/deallocates/', + '/metrics/', } assert docs['info'] == {'title': 'Devicehub', 'version': '0.2'} assert docs['components']['securitySchemes']['bearerAuth'] == { From 8b4c27dfe294bae61552b775e15cf50f332cec83 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 18:35:50 +0100 Subject: [PATCH 39/72] modify live model --- ereuse_devicehub/resources/action/models.py | 22 +++------------------ 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 4b14fda9..94fabd1e 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1295,25 +1295,9 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): information about its state (in the form of a ``Snapshot`` action) and usage statistics. """ - ip = Column(IP, nullable=False, - comment='The IP where the live was triggered.') - subdivision_confidence = Column(SmallInteger, - check_range('subdivision_confidence', 0, 100), - nullable=False) - subdivision = Column(DBEnum(Subdivision), nullable=False) - city = Column(Unicode(STR_SM_SIZE), check_lower('city'), nullable=False) - city_confidence = Column(SmallInteger, - check_range('city_confidence', 0, 100), - nullable=False) - isp = Column(Unicode(STR_SM_SIZE), check_lower('isp'), nullable=False) - organization = Column(Unicode(STR_SM_SIZE), check_lower('organization')) - organization_type = Column(Unicode(STR_SM_SIZE), check_lower('organization_type')) - - @property - def country(self) -> Country: - return self.subdivision.country - # todo relate to snapshot - # todo testing + serial_number = Column(Unicode(), check_lower('serial_number')) + serial_number.comment = """The serial number of the HardDisk in lower case.""" + time = Column(Interval) class Organize(JoinedTableMixin, ActionWithMultipleDevices): From 8999b6e9a57df1018c956d47e53f6fb377855729 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 23 Nov 2020 18:42:31 +0100 Subject: [PATCH 40/72] adding migration for live --- .../versions/e93aec8fc41f_added_assigned_action.py | 12 ++++++++++++ ereuse_devicehub/resources/action/models.py | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index f1940919..59010a74 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -53,5 +53,17 @@ def upgrade(): # Receive action op.drop_table('receive', schema=f'{get_inv()}') + # Live action + op.drop_table('live', schema=f'{get_inv()}') + op.create_table('live', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('serial_number', sa.Unicode(), nullable=True, + comment='The serial number of the Hard Disk in lower case.'), + sa.Column('time', sa.Interval(), nullable=True), + sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), + sa.PrimaryKeyConstraint('id'), + schema=f'{get_inv()}' + ) + def downgrade(): op.drop_table('allocate', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 94fabd1e..416e612c 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1296,8 +1296,8 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): and usage statistics. """ serial_number = Column(Unicode(), check_lower('serial_number')) - serial_number.comment = """The serial number of the HardDisk in lower case.""" - time = Column(Interval) + serial_number.comment = """The serial number of the Hard Disk in lower case.""" + time = Column(Interval, nullable=True) class Organize(JoinedTableMixin, ActionWithMultipleDevices): From 87704db27142c1b3c0143e313d0e0235253d8be3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 24 Nov 2020 13:44:49 +0100 Subject: [PATCH 41/72] adding live into snapshot and adding test --- .../e93aec8fc41f_added_assigned_action.py | 2 +- ereuse_devicehub/resources/action/models.py | 2 +- ereuse_devicehub/resources/action/views.py | 19 +++++++- tests/test_action.py | 48 ++++++++++--------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 59010a74..08d6c52c 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -59,7 +59,7 @@ def upgrade(): sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('serial_number', sa.Unicode(), nullable=True, comment='The serial number of the Hard Disk in lower case.'), - sa.Column('time', sa.Interval(), nullable=True), + sa.Column('time', sa.SmallInteger(), nullable=True), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), schema=f'{get_inv()}' diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 416e612c..a32ebbdd 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1297,7 +1297,7 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): """ serial_number = Column(Unicode(), check_lower('serial_number')) serial_number.comment = """The serial number of the Hard Disk in lower case.""" - time = Column(Interval, nullable=True) + time = Column(SmallInteger, nullable=False) class Organize(JoinedTableMixin, ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 1e0908cb..61ed9e16 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -16,7 +16,7 @@ from teal.resource import View from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, - InitTransfer) + InitTransfer, Live) from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity from ereuse_devicehub.resources.user.exceptions import InsufficientPermission @@ -160,6 +160,7 @@ class ActionView(View): # Check if HID is null and add Severity:Warning to Snapshot if snapshot.device.hid is None: snapshot.severity = Severity.Warning + self.live(snapshot) db.session.add(snapshot) db.session().final_flush() ret = self.schema.jsonify(snapshot) # transform it back @@ -167,6 +168,22 @@ class ActionView(View): db.session.commit() return ret + def live(self, snapshot): + test_hdd= [a for a in snapshot.actions if a.type == "TestDataStorage"] + if not (test_hdd and snapshot.device.allocated): + return + + test_hdd = test_hdd[0] + time = test_hdd.power_cycle_count + if time: + data_live = {'time': time, + 'serial_number': test_hdd.device.serial_number, + 'device': snapshot.device + } + live = Live(**data_live) + snapshot.actions.add(live) + + def transfer_ownership(self): """Perform a InitTransfer action to change author_id of device""" pass diff --git a/tests/test_action.py b/tests/test_action.py index d6fab3f2..4d2a7231 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -10,8 +10,9 @@ from flask import current_app as app, g from sqlalchemy.util import OrderedSet from teal.enums import Currency, Subdivision -from ereuse_devicehub.client import UserClient from ereuse_devicehub.db import db +from ereuse_devicehub.client import UserClient +from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.resources import enums from ereuse_devicehub.resources.action import models from ereuse_devicehub.resources.device import states @@ -245,29 +246,30 @@ def test_generic_action(action_model_state: Tuple[models.Action, states.Trading] @pytest.mark.mvp -@pytest.mark.usefixtures(conftest.auth_app_context.__name__) -def test_live(): +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live(user: UserClient, app: Devicehub): """Tests inserting a Live into the database and GETting it.""" - db_live = models.Live(ip=ipaddress.ip_address('79.147.10.10'), - subdivision_confidence=84, - subdivision=Subdivision['ES-CA'], - city='barcelona', - city_confidence=20, - isp='acme', - device=Desktop(serial_number='sn1', model='ml1', manufacturer='mr1', - chassis=ComputerChassis.Docking), - organization='acme1', - organization_type='acme1bis') - db.session.add(db_live) - db.session.commit() - client = UserClient(app, 'foo@foo.com', 'foo', response_wrapper=app.response_class) - client.login() - live, _ = client.get(res=models.Action, item=str(db_live.id)) - assert live['ip'] == '79.147.10.10' - assert live['subdivision'] == 'ES-CA' - assert live['country'] == 'ES' - device, _ = client.get(res=Device, item=live['device']['id']) - assert device['usage'] == states.Usage.InUse.name + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + "devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00", + "end_time": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['powerCycleCount'] += 1000 + snapshot, _ = user.post(acer, res=models.Snapshot) + db_device = Device.query.filter_by(id=1).one() + action_live = [a for a in db_device.actions if a.type == 'Live'] + assert len(action_live) == 1 + assert action_live[0].time == 6293 + assert action_live[0].serial_number == 'wd-wx11a80w7430' @pytest.mark.mvp From fd1efb871538b9515498431421185c332e48bfec Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 24 Nov 2020 16:12:59 +0100 Subject: [PATCH 42/72] fixed test_basic --- tests/test_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 520d3845..8c62a216 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -114,4 +114,4 @@ def test_api_docs(client: Client): 'scheme': 'basic', 'name': 'Authorization' } - assert len(docs['definitions']) == 123 + assert len(docs['definitions']) == 124 From 413ce7d76c9714ba22cf36af6d479eb81c0adc37 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 24 Nov 2020 21:15:49 +0100 Subject: [PATCH 43/72] adding metrics --- .../resources/metric/definitions.py | 45 ++++++-- tests/test_metrics.py | 104 ++++++++++++++++++ 2 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 tests/test_metrics.py diff --git a/ereuse_devicehub/resources/metric/definitions.py b/ereuse_devicehub/resources/metric/definitions.py index 70901e2b..134db628 100644 --- a/ereuse_devicehub/resources/metric/definitions.py +++ b/ereuse_devicehub/resources/metric/definitions.py @@ -2,28 +2,59 @@ from flask import request, g, jsonify from ereuse_devicehub.resources.action import schemas from teal.resource import Resource, View -from ereuse_devicehub.resources.action.models import Allocate +from ereuse_devicehub.resources.action.models import Allocate, Live, Action, ToRepair, ToPrepare from ereuse_devicehub.resources.device import models as m from ereuse_devicehub.resources.metric.schema import Metric class MetricsView(View): def find(self, args: dict): - self.params = request.get_json() + + self.params = dict(request.args) + unvalid = self.schema.validate(self.params) + if unvalid: + res = jsonify(unvalid) + res.status = 404 + return res + metrics = { "allocateds": self.allocated(), - "live": 0, - "null": 0, + "live": self.live(), + "null": self.nulls(), } return jsonify(metrics) def allocated(self): return Allocate.query.filter( - Allocate.start_time.between( - self.params['start_time'], self.params['end_time'] - ) + Allocate.start_time.between( + self.params['start_time'], self.params['end_time'] + ), + Action.author==g.user ).count() + def live(self): + return Live.query.filter( + Live.created.between( + self.params['start_time'], self.params['end_time'] + ), + Action.author==g.user + ).distinct(Live.serial_number).count() + + def nulls(self): + to_repair = ToRepair.query.filter( + ToRepair.created.between( + self.params['start_time'], self.params['end_time'] + ), + Action.author==g.user + ).count() + to_prepare = ToPrepare.query.filter( + ToPrepare.created.between( + self.params['start_time'], self.params['end_time'] + ), + Action.author==g.user + ).count() + return to_repair + to_prepare + class MetricDef(Resource): __type__ = 'Metric' diff --git a/tests/test_metrics.py b/tests/test_metrics.py new file mode 100644 index 00000000..5806afc7 --- /dev/null +++ b/tests/test_metrics.py @@ -0,0 +1,104 @@ +import pytest +from datetime import timedelta +from datetime import datetime + +from ereuse_devicehub.client import UserClient +from ereuse_devicehub.resources.action import models as ma +from tests import conftest +from tests.conftest import file + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_simple_metrics(user: UserClient): + """ Checks one standard query of metrics """ + # Insert computer + lenovo = file('desktop-9644w8n-lenovo-0169622.snapshot') + acer = file('acer.happy.battery.snapshot') + user.post(lenovo, res=ma.Snapshot) + snapshot, _ = user.post(acer, res=ma.Snapshot) + device_id = snapshot['device']['id'] + post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + "devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00", + "end_time": "2020-12-01T02:00:00+00:00" + } + + # Create Allocate + user.post(res=ma.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['powerCycleCount'] += 1000 + user.post(acer, res=ma.Snapshot) + + # Create a live + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec4" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['powerCycleCount'] += 1000 + user.post(acer, res=ma.Snapshot) + + # Create an other live + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec5" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['powerCycleCount'] += 1000 + user.post(acer, res=ma.Snapshot) + + # Check metrics + today = datetime.now() + delta = timedelta(days=30) + data = {"start_time": today-delta, + "end_time": today+delta + } + metrics = {'allocateds': 1, 'live': 1, 'null': 0} + res, _ = user.get("/metrics/", query_string=data) + assert res == metrics + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_second_hdd_metrics(user: UserClient): + """ Checks one standard query of metrics """ + # Insert computer + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=ma.Snapshot) + device_id = snapshot['device']['id'] + post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + "devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00", + "end_time": "2020-12-01T02:00:00+00:00" + } + + # Create Allocate + user.post(res=ma.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['powerCycleCount'] += 1000 + user.post(acer, res=ma.Snapshot) + + # Create a live + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec4" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['powerCycleCount'] += 1000 + user.post(acer, res=ma.Snapshot) + + # Create a second device + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec5" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd['serialNumber'] = 'WD-WX11A80W7440' + user.post(acer, res=ma.Snapshot) + + # Check metrics + today = datetime.now() + delta = timedelta(days=30) + data = {"start_time": today-delta, + "end_time": today+delta + } + metrics = {'allocateds': 1, 'live': 2, 'null': 0} + res, _ = user.get("/metrics/", query_string=data) + assert res == metrics + From 4657a3bcf9fcc719a63fd8ba16da209284111bf9 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 25 Nov 2020 13:58:32 +0100 Subject: [PATCH 44/72] clean metrics --- .../resources/metric/definitions.py | 57 +------------------ tests/test_metrics.py | 4 +- 2 files changed, 4 insertions(+), 57 deletions(-) diff --git a/ereuse_devicehub/resources/metric/definitions.py b/ereuse_devicehub/resources/metric/definitions.py index 134db628..4c90c77f 100644 --- a/ereuse_devicehub/resources/metric/definitions.py +++ b/ereuse_devicehub/resources/metric/definitions.py @@ -1,59 +1,6 @@ -from flask import request, g, jsonify -from ereuse_devicehub.resources.action import schemas -from teal.resource import Resource, View - -from ereuse_devicehub.resources.action.models import Allocate, Live, Action, ToRepair, ToPrepare -from ereuse_devicehub.resources.device import models as m +from teal.resource import Resource from ereuse_devicehub.resources.metric.schema import Metric - - -class MetricsView(View): - def find(self, args: dict): - - self.params = dict(request.args) - unvalid = self.schema.validate(self.params) - if unvalid: - res = jsonify(unvalid) - res.status = 404 - return res - - metrics = { - "allocateds": self.allocated(), - "live": self.live(), - "null": self.nulls(), - } - return jsonify(metrics) - - def allocated(self): - return Allocate.query.filter( - Allocate.start_time.between( - self.params['start_time'], self.params['end_time'] - ), - Action.author==g.user - ).count() - - def live(self): - return Live.query.filter( - Live.created.between( - self.params['start_time'], self.params['end_time'] - ), - Action.author==g.user - ).distinct(Live.serial_number).count() - - def nulls(self): - to_repair = ToRepair.query.filter( - ToRepair.created.between( - self.params['start_time'], self.params['end_time'] - ), - Action.author==g.user - ).count() - to_prepare = ToPrepare.query.filter( - ToPrepare.created.between( - self.params['start_time'], self.params['end_time'] - ), - Action.author==g.user - ).count() - return to_repair + to_prepare +from ereuse_devicehub.resources.metric.views import MetricsView class MetricDef(Resource): diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 5806afc7..b976d28f 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -52,7 +52,7 @@ def test_simple_metrics(user: UserClient): data = {"start_time": today-delta, "end_time": today+delta } - metrics = {'allocateds': 1, 'live': 1, 'null': 0} + metrics = {'allocateds': 1, 'live': 1} res, _ = user.get("/metrics/", query_string=data) assert res == metrics @@ -98,7 +98,7 @@ def test_second_hdd_metrics(user: UserClient): data = {"start_time": today-delta, "end_time": today+delta } - metrics = {'allocateds': 1, 'live': 2, 'null': 0} + metrics = {'allocateds': 1, 'live': 2} res, _ = user.get("/metrics/", query_string=data) assert res == metrics From 4421db3858dc01e67f50b9c9e145ee879fd10a9a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 25 Nov 2020 13:58:53 +0100 Subject: [PATCH 45/72] clean metrics with views --- ereuse_devicehub/resources/metric/views.py | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 ereuse_devicehub/resources/metric/views.py diff --git a/ereuse_devicehub/resources/metric/views.py b/ereuse_devicehub/resources/metric/views.py new file mode 100644 index 00000000..a37aeb1e --- /dev/null +++ b/ereuse_devicehub/resources/metric/views.py @@ -0,0 +1,39 @@ +from flask import request, g, jsonify +from ereuse_devicehub.resources.action import schemas +from teal.resource import View + +from ereuse_devicehub.resources.action.models import Allocate, Live, Action, ToRepair, ToPrepare +from ereuse_devicehub.resources.device import models as m +from ereuse_devicehub.resources.metric.schema import Metric + + +class MetricsView(View): + def find(self, args: dict): + + metrics = { + "allocateds": self.allocated(), + "live": self.live(), + } + return jsonify(metrics) + + def allocated(self): + # TODO @cayop we need uncomment when the pr/83 is approved + # return m.Device.query.filter(m.Device.allocated==True, owner==g.user).count() + return m.Device.query.filter(m.Device.allocated==True).count() + + def live(self): + # TODO @cayop we need uncomment when the pr/83 is approved + # devices = m.Device.query.filter(m.Device.allocated==True, owner==g.user) + devices = m.Device.query.filter(m.Device.allocated==True) + count = 0 + for dev in devices: + live = dev.last_action_of(Live) + allocate = dev.last_action_of(Allocate) + if not live: + continue + if allocate and allocate.created > live.created: + continue + count += 1 + + return count + From 821656ffc87318b841d852e509568a09eb0342c3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 25 Nov 2020 15:55:47 +0100 Subject: [PATCH 46/72] fixed new version of metrics for second_hdd test --- tests/test_metrics.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index b976d28f..49874582 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -1,6 +1,4 @@ import pytest -from datetime import timedelta -from datetime import datetime from ereuse_devicehub.client import UserClient from ereuse_devicehub.resources.action import models as ma @@ -47,13 +45,8 @@ def test_simple_metrics(user: UserClient): user.post(acer, res=ma.Snapshot) # Check metrics - today = datetime.now() - delta = timedelta(days=30) - data = {"start_time": today-delta, - "end_time": today+delta - } metrics = {'allocateds': 1, 'live': 1} - res, _ = user.get("/metrics/", query_string=data) + res, _ = user.get("/metrics/") assert res == metrics @@ -92,13 +85,8 @@ def test_second_hdd_metrics(user: UserClient): hdd['serialNumber'] = 'WD-WX11A80W7440' user.post(acer, res=ma.Snapshot) - # Check metrics - today = datetime.now() - delta = timedelta(days=30) - data = {"start_time": today-delta, - "end_time": today+delta - } - metrics = {'allocateds': 1, 'live': 2} - res, _ = user.get("/metrics/", query_string=data) + # Check metrics if we change the hdd we need a result of one device + metrics = {'allocateds': 1, 'live': 1} + res, _ = user.get("/metrics/") assert res == metrics From 2ed3e3f77f19b7092b1e1f1f0acb670816e91e37 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 25 Nov 2020 17:46:58 +0100 Subject: [PATCH 47/72] fixing LookupError of metrics --- ereuse_devicehub/resources/metric/views.py | 9 +++++++-- tests/test_metrics.py | 23 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/metric/views.py b/ereuse_devicehub/resources/metric/views.py index a37aeb1e..0b16c8a8 100644 --- a/ereuse_devicehub/resources/metric/views.py +++ b/ereuse_devicehub/resources/metric/views.py @@ -7,6 +7,11 @@ from ereuse_devicehub.resources.device import models as m from ereuse_devicehub.resources.metric.schema import Metric +def last_action(dev, action): + act = [e for e in reversed(dev.actions) if isinstance(e, action)] + return act[0] if act else None + + class MetricsView(View): def find(self, args: dict): @@ -27,8 +32,8 @@ class MetricsView(View): devices = m.Device.query.filter(m.Device.allocated==True) count = 0 for dev in devices: - live = dev.last_action_of(Live) - allocate = dev.last_action_of(Allocate) + live = last_action(dev, Live) + allocate = last_action(dev, Allocate) if not live: continue if allocate and allocate.created > live.created: diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 49874582..99020641 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -90,3 +90,26 @@ def test_second_hdd_metrics(user: UserClient): res, _ = user.get("/metrics/") assert res == metrics + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_metrics_with_live_null(user: UserClient): + """ Checks one standard query of metrics """ + # Insert computer + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=ma.Snapshot) + device_id = snapshot['device']['id'] + post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + "devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00", + "end_time": "2020-12-01T02:00:00+00:00" + } + + # Create Allocate + user.post(res=ma.Allocate, data=post_request) + + # Check metrics if we change the hdd we need a result of one device + metrics = {'allocateds': 1, 'live': 0} + res, _ = user.get("/metrics/") + assert res == metrics + From ab7bf75bd764e9af13a7f233dfe660c9c7665714 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 25 Nov 2020 17:57:43 +0100 Subject: [PATCH 48/72] new version of fixed with suppress --- ereuse_devicehub/resources/metric/views.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ereuse_devicehub/resources/metric/views.py b/ereuse_devicehub/resources/metric/views.py index 0b16c8a8..561150da 100644 --- a/ereuse_devicehub/resources/metric/views.py +++ b/ereuse_devicehub/resources/metric/views.py @@ -1,17 +1,13 @@ from flask import request, g, jsonify -from ereuse_devicehub.resources.action import schemas +from contextlib import suppress from teal.resource import View +from ereuse_devicehub.resources.action import schemas from ereuse_devicehub.resources.action.models import Allocate, Live, Action, ToRepair, ToPrepare from ereuse_devicehub.resources.device import models as m from ereuse_devicehub.resources.metric.schema import Metric -def last_action(dev, action): - act = [e for e in reversed(dev.actions) if isinstance(e, action)] - return act[0] if act else None - - class MetricsView(View): def find(self, args: dict): @@ -32,8 +28,12 @@ class MetricsView(View): devices = m.Device.query.filter(m.Device.allocated==True) count = 0 for dev in devices: - live = last_action(dev, Live) - allocate = last_action(dev, Allocate) + live = allocate = None + with suppress(LookupError): + live = dev.last_action_of(Live) + with suppress(LookupError): + allocate = dev.last_action_of(Allocate) + if not live: continue if allocate and allocate.created > live.created: From b072bc3b57208113bfe1b9b2413ba68af1ac0447 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 26 Nov 2020 18:44:08 +0100 Subject: [PATCH 49/72] change allocate and deallocate --- .../e93aec8fc41f_added_assigned_action.py | 3 +- ereuse_devicehub/resources/action/models.py | 2 +- ereuse_devicehub/resources/action/schemas.py | 61 ++++++++--------- tests/test_action.py | 66 ++++++++++++++++--- 4 files changed, 90 insertions(+), 42 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 08d6c52c..b1f6aa4f 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -31,7 +31,7 @@ def upgrade(): op.drop_table('allocate', schema=f'{get_inv()}') op.create_table('allocate', sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), - sa.Column('end_users', sa.Numeric(precision=4), nullable=False), + sa.Column('end_users', sa.Numeric(precision=4), nullable=True), sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), @@ -41,6 +41,7 @@ def upgrade(): # Deallocate action op.drop_table('deallocate', schema=f'{get_inv()}') op.create_table('deallocate', + sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index a32ebbdd..936298d7 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -315,7 +315,7 @@ class Allocate(JoinedTableMixin, ActionWithMultipleDevices): """ code = Column(CIText(), default='', nullable=True) code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ - end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=False) + end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=True) class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index f7952ae9..168bcb3e 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -1,3 +1,5 @@ +from datetime import datetime, timedelta +from dateutil.tz import tzutc from flask import current_app as app from marshmallow import Schema as MarshmallowSchema, ValidationError, fields as f, validates_schema from marshmallow.fields import Boolean, DateTime, Decimal, Float, Integer, Nested, String, \ @@ -65,58 +67,57 @@ class Remove(ActionWithOneDevice): class Allocate(ActionWithMultipleDevices): __doc__ = m.Allocate.__doc__ - agent = NestedOn(s_agent.Agent, only_query='id', required=False, comment=m.Trade.to_comment) - description = SanitizedStr(default='', description=m.Action.description.comment) - start_time = DateTime(data_key='start_time', description=m.Action.start_time.comment) + start_time = DateTime(data_key='start_time', required=True, + description=m.Action.start_time.comment) end_time = DateTime(data_key='end_time', required=False, description=m.Action.end_time.comment) - code = SanitizedStr(data_key='Transaction', validate=Length(min=1, max=STR_BIG_SIZE), + code = SanitizedStr(data_key='transaction', validate=Length(min=1, max=STR_BIG_SIZE), required=False, description='The code of the agent to assigned.') - end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")], - required=True) + end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")]) @validates_schema def validate_allocate(self, data: dict): + txt = "You need to allocate for a day before today" + delay = timedelta(days=1) + today = datetime.now().replace(tzinfo=tzutc()) + delay + start_time = data['start_time'].replace(tzinfo=tzutc()) + if start_time > today: + raise ValidationError(txt) + txt = "You need deallocate before allocate this device again" for device in data['devices']: - if device.allocated == False: - device.allocated = True - continue - - actions = [a for a in device.actions] - actions.sort(key=lambda x: x.created) - actions.reverse() - - for allocate in actions: - if isinstance(allocate, m.Allocate): - same_allocate = [ - allocate.code == data['code'], - allocate.start_time == data['start_time'], - allocate.end_users == data['end_users'] - ] - if not all(same_allocate): - raise ValidationError(txt) - if isinstance(allocate, m.Deallocate): - break + if device.allocated: + raise ValidationError(txt) device.allocated = True class Deallocate(ActionWithMultipleDevices): __doc__ = m.Deallocate.__doc__ - start_time = DateTime(data_key='start_time', description=m.Action.start_time.comment) + start_time = DateTime(data_key='start_time', required=True, + description=m.Action.start_time.comment) + code = SanitizedStr(data_key='transaction', validate=Length(min=1, max=STR_BIG_SIZE), + required=False, + description='The code of the agent to assigned.') @validates_schema def validate_deallocate(self, data: dict): - txt = "Sorry some of this devices are actually deallocate" + txt = "You need to deallocate for a day before today" + import pdb; pdb.set_trace() + delay = timedelta(days=1) + today = datetime.now().replace(tzinfo=tzutc()) + delay + start_time = data['start_time'].replace(tzinfo=tzutc()) + if start_time > today: + raise ValidationError(txt) + txt = "Sorry some of this devices are actually deallocate" for device in data['devices']: - if hasattr(device, 'allocated') and device.allocated: - device.allocated = False - else: + if not device.allocated: raise ValidationError(txt) + device.allocated = False + class EraseBasic(ActionWithOneDevice): __doc__ = m.EraseBasic.__doc__ diff --git a/tests/test_action.py b/tests/test_action.py index 4d2a7231..410fb265 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -2,7 +2,7 @@ import ipaddress import copy import pytest -from datetime import timedelta +from datetime import datetime, timedelta from decimal import Decimal from typing import Tuple, Type @@ -278,21 +278,22 @@ def test_allocate(user: UserClient): """ Tests allocate """ snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) device_id = snapshot['device']['id'] - post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, - "devices": [device_id], "description": "aaa", + post_request = {"transaction": "ccc", + "name": "John", + "severity": "Info", + "end_users": 1, + "devices": [device_id], + "description": "aaa", "start_time": "2020-11-01T02:00:00+00:00", "end_time": "2020-12-01T02:00:00+00:00" } allocate, _ = user.post(res=models.Allocate, data=post_request) - allocate_get, _ = user.get(res=models.Action, item=allocate['id']) - for f in ('name', 'Transaction', 'created', 'start_time', 'end_users'): - assert allocate_get[f] == allocate[f] # Normal allocate device, _ = user.get(res=Device, item=device_id) assert device['allocated'] == True action = [a for a in device['actions'] if a['type'] == 'Allocate'][0] - assert action['Transaction'] == allocate['Transaction'] + assert action['transaction'] == allocate['transaction'] assert action['created'] == allocate['created'] assert action['start_time'] == allocate['start_time'] assert action['end_users'] == allocate['end_users'] @@ -303,7 +304,7 @@ def test_allocate(user: UserClient): post_bad_request2 = copy.copy(post_request) post_bad_request2['start_time'] = "2020-11-01T02:00:00+00:01" post_bad_request3 = copy.copy(post_request) - post_bad_request3['Transaction'] = "aaa" + post_bad_request3['transaction'] = "aaa" res1, _ = user.post(res=models.Allocate, data=post_bad_request1, status=422) res2, _ = user.post(res=models.Allocate, data=post_bad_request2, status=422) res3, _ = user.post(res=models.Allocate, data=post_bad_request3, status=422) @@ -312,6 +313,28 @@ def test_allocate(user: UserClient): assert r['type'] == 'ValidationError' +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_allocate_bad_dates(user: UserClient): + """ Tests allocate """ + snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) + device_id = snapshot['device']['id'] + delta = timedelta(days=30) + future = datetime.now() + delta + post_request = {"transaction": "ccc", + "name": "John", + "severity": "Info", + "end_users": 1, + "devices": [device_id], + "description": "aaa", + "start_time": future, + } + + res, _ = user.post(res=models.Allocate, data=post_request, status=422) + assert res['code'] == 422 + assert res['type'] == 'ValidationError' + + @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_deallocate(user: UserClient): @@ -319,12 +342,13 @@ def test_deallocate(user: UserClient): snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) device_id = snapshot['device']['id'] post_deallocate = {"start_time": "2020-11-01T02:00:00+00:00", - "devices": [device_id] + "transaction": "ccc", + "devices": [device_id] } res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) assert res['code'] == 422 assert res['type'] == 'ValidationError' - post_allocate = {"Transaction": "ccc", "name": "John", "end_users": 1, + post_allocate = {"transaction": "ccc", "name": "John", "end_users": 1, "devices": [device_id], "description": "aaa", "start_time": "2020-11-01T02:00:00+00:00", "end_time": "2020-12-01T02:00:00+00:00" @@ -342,6 +366,28 @@ def test_deallocate(user: UserClient): assert res['type'] == 'ValidationError' +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_deallocate_bad_dates(user: UserClient): + """ Tests deallocate with bad date of start_time """ + snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) + device_id = snapshot['device']['id'] + delta = timedelta(days=30) + future = datetime.now() + delta + post_deallocate = {"start_time": future, + "devices": [device_id] + } + post_allocate = {"devices": [device_id], "description": "aaa", + "start_time": "2020-11-01T02:00:00+00:00" + } + + import pdb; pdb.set_trace() + user.post(res=models.Allocate, data=post_allocate) + res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=400) + assert res['code'] == 422 + assert res['type'] == 'ValidationError' + + @pytest.mark.mvp @pytest.mark.parametrize('action_model_state', (pytest.param(ams, id=ams[0].__name__) From 988f5c175103740ccb1af978eba16e4d73c40e8b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 26 Nov 2020 18:51:36 +0100 Subject: [PATCH 50/72] fixed dates --- ereuse_devicehub/resources/action/schemas.py | 1 - tests/test_action.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 168bcb3e..d160d83b 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -104,7 +104,6 @@ class Deallocate(ActionWithMultipleDevices): @validates_schema def validate_deallocate(self, data: dict): txt = "You need to deallocate for a day before today" - import pdb; pdb.set_trace() delay = timedelta(days=1) today = datetime.now().replace(tzinfo=tzutc()) + delay start_time = data['start_time'].replace(tzinfo=tzutc()) diff --git a/tests/test_action.py b/tests/test_action.py index 410fb265..d9231923 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -381,9 +381,8 @@ def test_deallocate_bad_dates(user: UserClient): "start_time": "2020-11-01T02:00:00+00:00" } - import pdb; pdb.set_trace() user.post(res=models.Allocate, data=post_allocate) - res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=400) + res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) assert res['code'] == 422 assert res['type'] == 'ValidationError' From daeae1b4b4b3005e5247d98a1f690222da472fd7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 26 Nov 2020 19:08:07 +0100 Subject: [PATCH 51/72] fixed deallocate code bug --- ereuse_devicehub/resources/action/models.py | 4 +++- tests/test_action.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 936298d7..dfd8e348 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -321,7 +321,9 @@ class Allocate(JoinedTableMixin, ActionWithMultipleDevices): class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): """The act of deallocate one list of devices to one person of the system or not """ - pass + code = Column(CIText(), default='', nullable=True) + code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ + end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=True) class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): diff --git a/tests/test_action.py b/tests/test_action.py index d9231923..17bc1b39 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -253,7 +253,7 @@ def test_live(user: UserClient, app: Devicehub): snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] db_device = Device.query.filter_by(id=1).one() - post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "end_users": 1, "devices": [device_id], "description": "aaa", "start_time": "2020-11-01T02:00:00+00:00", "end_time": "2020-12-01T02:00:00+00:00" From 23e124721c17f94a452617af3c246baffd08df5c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 26 Nov 2020 19:21:35 +0100 Subject: [PATCH 52/72] fixing metrics --- tests/test_metrics.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 99020641..882c1d8c 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -16,7 +16,7 @@ def test_simple_metrics(user: UserClient): user.post(lenovo, res=ma.Snapshot) snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "end_users": 1, "devices": [device_id], "description": "aaa", "start_time": "2020-11-01T02:00:00+00:00", "end_time": "2020-12-01T02:00:00+00:00" @@ -58,7 +58,7 @@ def test_second_hdd_metrics(user: UserClient): acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "end_users": 1, "devices": [device_id], "description": "aaa", "start_time": "2020-11-01T02:00:00+00:00", "end_time": "2020-12-01T02:00:00+00:00" @@ -99,7 +99,7 @@ def test_metrics_with_live_null(user: UserClient): acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"Transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "end_users": 1, "devices": [device_id], "description": "aaa", "start_time": "2020-11-01T02:00:00+00:00", "end_time": "2020-12-01T02:00:00+00:00" From 4172711c93a3717a052c7114a607a85541ca8001 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 27 Nov 2020 18:10:51 +0100 Subject: [PATCH 53/72] change the endpoints for allocate and deallocate --- ereuse_devicehub/config.py | 2 - ereuse_devicehub/resources/action/__init__.py | 12 +++++- ereuse_devicehub/resources/action/models.py | 1 - ereuse_devicehub/resources/action/schemas.py | 8 ++-- ereuse_devicehub/resources/action/views.py | 36 ++++++++++++++++- .../resources/allocate/__init__.py | 0 .../resources/allocate/definitions.py | 14 ------- ereuse_devicehub/resources/allocate/views.py | 39 ------------------- ereuse_devicehub/resources/device/models.py | 6 ++- 9 files changed, 53 insertions(+), 65 deletions(-) delete mode 100644 ereuse_devicehub/resources/allocate/__init__.py delete mode 100644 ereuse_devicehub/resources/allocate/definitions.py delete mode 100644 ereuse_devicehub/resources/allocate/views.py diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index c0b1a955..d8734f65 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -14,7 +14,6 @@ from ereuse_devicehub.resources.device import definitions from ereuse_devicehub.resources.documents import documents from ereuse_devicehub.resources.enums import PriceSoftware from ereuse_devicehub.resources.versions import versions -from ereuse_devicehub.resources.allocate import definitions as allocate_def from ereuse_devicehub.resources.metric import definitions as metric_def @@ -30,7 +29,6 @@ class DevicehubConfig(Config): import_resource(documents), import_resource(inventory), import_resource(versions), - import_resource(allocate_def), import_resource(metric_def), ),) PASSWORD_SCHEMES = {'pbkdf2_sha256'} # type: Set[str] diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 1cf8c1b7..1d70d631 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -3,7 +3,7 @@ from typing import Callable, Iterable, Tuple from teal.resource import Converters, Resource from ereuse_devicehub.resources.action import schemas -from ereuse_devicehub.resources.action.views import ActionView +from ereuse_devicehub.resources.action.views import ActionView, AllocateView, DeallocateView from ereuse_devicehub.resources.device.sync import Sync @@ -198,6 +198,16 @@ class ToPrepareDef(ActionDef): SCHEMA = schemas.ToPrepare +class AllocateDef(ActionDef): + VIEW = AllocateView + SCHEMA = schemas.Allocate + + +class DeallocateDef(ActionDef): + VIEW = DeallocateView + SCHEMA = schemas.Deallocate + + class PrepareDef(ActionDef): VIEW = None SCHEMA = schemas.Prepare diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index dfd8e348..6b22f9b8 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -323,7 +323,6 @@ class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): """ code = Column(CIText(), default='', nullable=True) code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ - end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=True) class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index d160d83b..1d361f20 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -67,14 +67,14 @@ class Remove(ActionWithOneDevice): class Allocate(ActionWithMultipleDevices): __doc__ = m.Allocate.__doc__ - start_time = DateTime(data_key='start_time', required=True, + start_time = DateTime(data_key='startTime', required=True, description=m.Action.start_time.comment) - end_time = DateTime(data_key='end_time', required=False, + end_time = DateTime(data_key='endTime', required=False, description=m.Action.end_time.comment) code = SanitizedStr(data_key='transaction', validate=Length(min=1, max=STR_BIG_SIZE), required=False, description='The code of the agent to assigned.') - end_users = Integer(validate=[Range(min=1, error="Value must be greater than 0")]) + end_users = Integer(data_key='endUsers', validate=[Range(min=1, error="Value must be greater than 0")]) @validates_schema def validate_allocate(self, data: dict): @@ -95,7 +95,7 @@ class Allocate(ActionWithMultipleDevices): class Deallocate(ActionWithMultipleDevices): __doc__ = m.Deallocate.__doc__ - start_time = DateTime(data_key='start_time', required=True, + start_time = DateTime(data_key='startTime', required=True, description=m.Action.start_time.comment) code = SanitizedStr(data_key='transaction', validate=Length(min=1, max=STR_BIG_SIZE), required=False, diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 61ed9e16..2fc5704f 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -8,7 +8,7 @@ from distutils.version import StrictVersion from uuid import UUID from flask.json import jsonify -from flask import current_app as app, request, g +from flask import current_app as app, request, g, redirect from sqlalchemy.util import OrderedSet from teal.marshmallow import ValidationError from teal.resource import View @@ -16,7 +16,7 @@ from teal.resource import View from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, - InitTransfer, Live) + InitTransfer, Live, Allocate, Deallocate) from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity from ereuse_devicehub.resources.user.exceptions import InsufficientPermission @@ -63,6 +63,38 @@ def move_json(tmp_snapshots, path_name, user): os.remove(path_name) +class AllocateMix(): + model = None + + def post(self): + """ Create one res_obj """ + res_json = request.get_json() + res_obj = self.model(**res_json) + db.session.add(res_obj) + db.session().final_flush() + ret = self.schema.jsonify(res_obj) + ret.status_code = 201 + db.session.commit() + return ret + + def find(self, args: dict): + res_objs = self.model.query.filter_by(author=g.user) \ + .order_by(self.model.created.desc()) \ + .paginate(per_page=200) + return things_response( + self.schema.dump(res_objs.items, many=True, nested=0), + res_objs.page, res_objs.per_page, res_objs.total, + res_objs.prev_num, res_objs.next_num + ) + + +class AllocateView(AllocateMix, View): + model = Allocate + +class DeallocateView(AllocateMix, View): + model = Deallocate + + class ActionView(View): def post(self): """Posts an action.""" diff --git a/ereuse_devicehub/resources/allocate/__init__.py b/ereuse_devicehub/resources/allocate/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ereuse_devicehub/resources/allocate/definitions.py b/ereuse_devicehub/resources/allocate/definitions.py deleted file mode 100644 index 17ab926e..00000000 --- a/ereuse_devicehub/resources/allocate/definitions.py +++ /dev/null @@ -1,14 +0,0 @@ -from ereuse_devicehub.resources.action import schemas -from teal.resource import Resource -from ereuse_devicehub.resources.allocate.views import AllocateView, DeallocateView - - -class AllocateDef(Resource): - VIEW = AllocateView - SCHEMA = schemas.Allocate - AUTH = True - -class DeallocateDef(Resource): - VIEW = DeallocateView - SCHEMA = schemas.Deallocate - AUTH = True diff --git a/ereuse_devicehub/resources/allocate/views.py b/ereuse_devicehub/resources/allocate/views.py deleted file mode 100644 index cd044203..00000000 --- a/ereuse_devicehub/resources/allocate/views.py +++ /dev/null @@ -1,39 +0,0 @@ -from flask import g, request -from teal.resource import View - -from ereuse_devicehub.db import db -from ereuse_devicehub.query import things_response -from ereuse_devicehub.resources.action.models import Allocate, Deallocate - - -class AllocateMix(): - model = None - - def post(self): - """ Create one res_obj """ - res_json = request.get_json() - res_obj = self.model(**res_json) - db.session.add(res_obj) - db.session().final_flush() - ret = self.schema.jsonify(res_obj) - ret.status_code = 201 - db.session.commit() - return ret - - def find(self, args: dict): - res_objs = self.model.query.filter_by(author=g.user) \ - .order_by(self.model.created.desc()) \ - .paginate(per_page=200) - return things_response( - self.schema.dump(res_objs.items, many=True, nested=0), - res_objs.page, res_objs.per_page, res_objs.total, - res_objs.prev_num, res_objs.next_num - ) - - -class AllocateView(AllocateMix, View): - model = Allocate - - -class DeallocateView(AllocateMix, View): - model = Deallocate diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 907b61e0..e8ebc62a 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -152,7 +152,7 @@ class Device(Thing): Actions are returned by descending ``created`` time. """ - return sorted(chain(self.actions_multiple, self.actions_one)) + return sorted(chain(self.actions_multiple, self.actions_one), key=lambda x: x.created) @property def problems(self): @@ -298,7 +298,9 @@ class Device(Thing): """ try: # noinspection PyTypeHints - return next(e for e in reversed(self.actions) if isinstance(e, types)) + actions = self.actions + actions.sort(key=lambda x: x.created) + return next(e for e in reversed(actions) if isinstance(e, types)) except StopIteration: raise LookupError('{!r} does not contain actions of types {}.'.format(self, types)) From bcb3358af36a84fc54b922420bfb099e6c54e5f8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 27 Nov 2020 19:14:29 +0100 Subject: [PATCH 54/72] fixed tests --- tests/test_action.py | 34 +++++++++++++++++----------------- tests/test_metrics.py | 18 +++++++++--------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index 17bc1b39..5e4e014d 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -253,10 +253,10 @@ def test_live(user: UserClient, app: Devicehub): snapshot, _ = user.post(acer, res=models.Snapshot) device_id = snapshot['device']['id'] db_device = Device.query.filter_by(id=1).one() - post_request = {"transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00", - "end_time": "2020-12-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" } user.post(res=models.Allocate, data=post_request) @@ -281,11 +281,11 @@ def test_allocate(user: UserClient): post_request = {"transaction": "ccc", "name": "John", "severity": "Info", - "end_users": 1, + "endUsers": 1, "devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00", - "end_time": "2020-12-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00", } allocate, _ = user.post(res=models.Allocate, data=post_request) @@ -295,14 +295,14 @@ def test_allocate(user: UserClient): action = [a for a in device['actions'] if a['type'] == 'Allocate'][0] assert action['transaction'] == allocate['transaction'] assert action['created'] == allocate['created'] - assert action['start_time'] == allocate['start_time'] - assert action['end_users'] == allocate['end_users'] + assert action['startTime'] == allocate['startTime'] + assert action['endUsers'] == allocate['endUsers'] assert action['name'] == allocate['name'] post_bad_request1 = copy.copy(post_request) - post_bad_request1['end_users'] = 2 + post_bad_request1['endUsers'] = 2 post_bad_request2 = copy.copy(post_request) - post_bad_request2['start_time'] = "2020-11-01T02:00:00+00:01" + post_bad_request2['startTime'] = "2020-11-01T02:00:00+00:01" post_bad_request3 = copy.copy(post_request) post_bad_request3['transaction'] = "aaa" res1, _ = user.post(res=models.Allocate, data=post_bad_request1, status=422) @@ -341,24 +341,24 @@ def test_deallocate(user: UserClient): """ Tests deallocate """ snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) device_id = snapshot['device']['id'] - post_deallocate = {"start_time": "2020-11-01T02:00:00+00:00", + post_deallocate = {"startTime": "2020-11-01T02:00:00+00:00", "transaction": "ccc", "devices": [device_id] } res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) assert res['code'] == 422 assert res['type'] == 'ValidationError' - post_allocate = {"transaction": "ccc", "name": "John", "end_users": 1, + post_allocate = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00", - "end_time": "2020-12-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" } user.post(res=models.Allocate, data=post_allocate) device, _ = user.get(res=Device, item=device_id) assert device['allocated'] == True deallocate, _ = user.post(res=models.Deallocate, data=post_deallocate) - assert deallocate['start_time'] == post_deallocate['start_time'] + assert deallocate['startTime'] == post_deallocate['startTime'] assert deallocate['devices'][0]['id'] == device_id assert deallocate['devices'][0]['allocated'] == False res, _ = user.post(res=models.Deallocate, data=post_deallocate, status=422) @@ -374,11 +374,11 @@ def test_deallocate_bad_dates(user: UserClient): device_id = snapshot['device']['id'] delta = timedelta(days=30) future = datetime.now() + delta - post_deallocate = {"start_time": future, + post_deallocate = {"startTime": future, "devices": [device_id] } post_allocate = {"devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00" } user.post(res=models.Allocate, data=post_allocate) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 882c1d8c..c053235f 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -16,10 +16,10 @@ def test_simple_metrics(user: UserClient): user.post(lenovo, res=ma.Snapshot) snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00", - "end_time": "2020-12-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" } # Create Allocate @@ -58,10 +58,10 @@ def test_second_hdd_metrics(user: UserClient): acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00", - "end_time": "2020-12-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" } # Create Allocate @@ -99,10 +99,10 @@ def test_metrics_with_live_null(user: UserClient): acer = file('acer.happy.battery.snapshot') snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] - post_request = {"transaction": "ccc", "name": "John", "end_users": 1, + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", - "start_time": "2020-11-01T02:00:00+00:00", - "end_time": "2020-12-01T02:00:00+00:00" + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" } # Create Allocate From 2fd0c61cc3870b439623cc8164f2e783789f195b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 28 Nov 2020 18:35:53 +0100 Subject: [PATCH 55/72] adding test for reproduce the bug --- tests/test_snapshot.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index 0c4bbf1d..c722cd1b 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -18,7 +18,7 @@ from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub from ereuse_devicehub.resources.action.models import Action, BenchmarkDataStorage, \ BenchmarkProcessor, EraseSectors, RateComputer, Snapshot, SnapshotRequest, VisualTest, \ - EreusePrice + EreusePrice, Ready from ereuse_devicehub.resources.device import models as m from ereuse_devicehub.resources.device.exceptions import NeedsId from ereuse_devicehub.resources.device.models import SolidStateDrive @@ -541,6 +541,26 @@ def test_save_snapshot_in_file(app: Devicehub, user: UserClient): assert snapshot['version'] == snapshot_no_hid['version'] assert snapshot['uuid'] == uuid + +@pytest.mark.mvp +def test_action_no_snapshot_without_save_file(app: Devicehub, user: UserClient): + """ This test check if the function save_snapshot_in_file not work when we + send one other action different to snapshot + """ + s = file('laptop-hp_255_g3_notebook-hewlett-packard-cnd52270fw.snapshot') + snapshot, _ = user.post(res=Snapshot, data=s) + + tmp_snapshots = app.config['TMP_SNAPSHOTS'] + path_dir_base = os.path.join(tmp_snapshots, user.user['email']) + + shutil.rmtree(tmp_snapshots) + + action = {'type': Ready.t, 'devices': [snapshot['device']['id']]} + action, _ = user.post(action, res=Action) + + files = [x for x in os.listdir(path_dir_base) if '.json' in x] + assert len(files) == 0 + @pytest.mark.mvp def test_save_snapshot_with_debug(app: Devicehub, user: UserClient): """ This test check if works the function save_snapshot_in_file """ From a9f6e9ccaaed42fd4116556a2c3eec04f53896b7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 28 Nov 2020 18:47:35 +0100 Subject: [PATCH 56/72] fixing bug --- ereuse_devicehub/resources/action/views.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 2d71b4fd..4797a5b2 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -65,16 +65,16 @@ class ActionView(View): def post(self): """Posts an action.""" json = request.get_json(validate=False) - tmp_snapshots = app.config['TMP_SNAPSHOTS'] - path_snapshot = save_json(json, tmp_snapshots, g.user.email) - json.pop('debug', None) if not json or 'type' not in json: raise ValidationError('Resource needs a type.') # todo there should be a way to better get subclassess resource # defs resource_def = app.resources[json['type']] - a = resource_def.schema.load(json) 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 @@ -82,8 +82,8 @@ class ActionView(View): pass # TODO JN add compute rate with new visual test and old components device if json['type'] == InitTransfer.t: - move_json(tmp_snapshots, path_snapshot, g.user.email) return self.transfer_ownership() + a = resource_def.schema.load(json) Model = db.Model._decl_class_registry.data[json['type']]() action = Model(**a) db.session.add(action) @@ -91,7 +91,6 @@ class ActionView(View): ret = self.schema.jsonify(action) ret.status_code = 201 db.session.commit() - move_json(tmp_snapshots, path_snapshot, g.user.email) return ret def one(self, id: UUID): From 517007ef50790933755e192ef98ecee39599a414 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 28 Nov 2020 19:04:54 +0100 Subject: [PATCH 57/72] fixing test --- tests/test_snapshot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index c722cd1b..274e4451 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -558,8 +558,7 @@ def test_action_no_snapshot_without_save_file(app: Devicehub, user: UserClient): action = {'type': Ready.t, 'devices': [snapshot['device']['id']]} action, _ = user.post(action, res=Action) - files = [x for x in os.listdir(path_dir_base) if '.json' in x] - assert len(files) == 0 + assert os.path.exists(tmp_snapshots) == False @pytest.mark.mvp def test_save_snapshot_with_debug(app: Devicehub, user: UserClient): From c140a58ca2384b0d4766e2db538f0451ce55af71 Mon Sep 17 00:00:00 2001 From: Jordi Nadeu Date: Mon, 30 Nov 2020 17:42:02 +0100 Subject: [PATCH 58/72] Update models.pyi of actions Allocate and Deallocate --- ereuse_devicehub/resources/action/models.pyi | 35 ++++++-------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.pyi b/ereuse_devicehub/resources/action/models.pyi index e95c3945..5082702d 100644 --- a/ereuse_devicehub/resources/action/models.pyi +++ b/ereuse_devicehub/resources/action/models.pyi @@ -447,26 +447,8 @@ class Prepare(ActionWithMultipleDevices): class Live(ActionWithOneDevice): - ip = ... # type: Column - subdivision_confidence = ... # type: Column - subdivision = ... # type: Column - city = ... # type: Column - city_confidence = ... # type: Column - isp = ... # type: Column - organization = ... # type: Column - organization_type = ... # type: Column - - def __init__(self, **kwargs) -> None: - super().__init__(**kwargs) - self.ip = ... # type: Union[ipaddress.IPv4Address, ipaddress.IPv6Address] - self.subdivision_confidence = ... # type: int - self.subdivision = ... # type: enums.Subdivision - self.city = ... # type: str - self.city_confidence = ... # type: int - self.isp = ... # type: str - self.organization = ... # type: str - self.organization_type = ... # type: str - self.country = ... # type: Country + serial_number = ... # type: Column + time = ... # type: Column class Organize(ActionWithMultipleDevices): @@ -527,12 +509,15 @@ class DisposeProduct(Trade): class TransferOwnershipBlockchain(Trade): pass + + +class Allocate(ActionWithMultipleDevices): + code = ... # type: Column + end_users = ... # type: Column - -class Receive(ActionWithMultipleDevices): - agent_from = ... # type: relationship - agent_to = ... # type: relationship - action = ... # type: relationship + +class Deallocate(ActionWithMultipleDevices): + code = ... # type: Column class Migrate(ActionWithMultipleDevices): From 23abf3e08d788d434ade149aa677481427fa38e2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 30 Nov 2020 18:17:47 +0100 Subject: [PATCH 59/72] change code for transaction --- .../versions/e93aec8fc41f_added_assigned_action.py | 4 ++-- ereuse_devicehub/resources/action/models.py | 4 ++-- ereuse_devicehub/resources/action/schemas.py | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index b1f6aa4f..690967e4 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -30,7 +30,7 @@ def upgrade(): # Allocate action op.drop_table('allocate', schema=f'{get_inv()}') op.create_table('allocate', - sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), + sa.Column('transaction', citext.CIText(), nullable=True, comment='The code used from the owner for relation with external tool.'), sa.Column('end_users', sa.Numeric(precision=4), nullable=True), sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), @@ -41,7 +41,7 @@ def upgrade(): # Deallocate action op.drop_table('deallocate', schema=f'{get_inv()}') op.create_table('deallocate', - sa.Column('code', citext.CIText(), nullable=True, comment=' This is a internal code for mainteing the secrets of the personal datas of the new holder '), + sa.Column('transaction', citext.CIText(), nullable=True, comment='The code used from the owner for relation with external tool.'), sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 6b22f9b8..31be2b40 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -321,8 +321,8 @@ class Allocate(JoinedTableMixin, ActionWithMultipleDevices): class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): """The act of deallocate one list of devices to one person of the system or not """ - code = Column(CIText(), default='', nullable=True) - code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ + transaction= Column(CIText(), default='', nullable=True) + transaction.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 1d361f20..4c72a456 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -71,9 +71,10 @@ class Allocate(ActionWithMultipleDevices): description=m.Action.start_time.comment) end_time = DateTime(data_key='endTime', required=False, description=m.Action.end_time.comment) - code = SanitizedStr(data_key='transaction', validate=Length(min=1, max=STR_BIG_SIZE), + transaction = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), required=False, - description='The code of the agent to assigned.') + description='The code used from the owner for \ + relation with external tool.') end_users = Integer(data_key='endUsers', validate=[Range(min=1, error="Value must be greater than 0")]) @validates_schema @@ -97,9 +98,10 @@ class Deallocate(ActionWithMultipleDevices): __doc__ = m.Deallocate.__doc__ start_time = DateTime(data_key='startTime', required=True, description=m.Action.start_time.comment) - code = SanitizedStr(data_key='transaction', validate=Length(min=1, max=STR_BIG_SIZE), + transaction = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), required=False, - description='The code of the agent to assigned.') + description='The code used from the owner for \ + relation with external tool.') @validates_schema def validate_deallocate(self, data: dict): From 4a217634c7d71b6cc49c4aead4ab15d65f9a85bc Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 30 Nov 2020 18:47:17 +0100 Subject: [PATCH 60/72] change code for transaction --- ereuse_devicehub/resources/action/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 31be2b40..ad05efca 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -313,8 +313,8 @@ class Remove(ActionWithOneDevice): class Allocate(JoinedTableMixin, ActionWithMultipleDevices): """The act of allocate one list of devices to one person """ - code = Column(CIText(), default='', nullable=True) - code.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ + transaction = Column(CIText(), default='', nullable=True) + transaction.comment = "The code used from the owner for relation with external tool." end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=True) @@ -322,7 +322,7 @@ class Deallocate(JoinedTableMixin, ActionWithMultipleDevices): """The act of deallocate one list of devices to one person of the system or not """ transaction= Column(CIText(), default='', nullable=True) - transaction.comment = """ This is a internal code for mainteing the secrets of the personal datas of the new holder """ + transaction.comment = "The code used from the owner for relation with external tool." class EraseBasic(JoinedWithOneDeviceMixin, ActionWithOneDevice): From 92c403579bd4f31b28f4e30cf953f77672c89578 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 1 Dec 2020 15:33:49 +0100 Subject: [PATCH 61/72] ading finalUserCode to allocate action --- .../versions/e93aec8fc41f_added_assigned_action.py | 2 ++ ereuse_devicehub/resources/action/models.py | 3 +++ ereuse_devicehub/resources/action/schemas.py | 5 +++++ tests/test_action.py | 3 +++ tests/test_metrics.py | 3 +++ 5 files changed, 16 insertions(+) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 690967e4..0d65cf9d 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -30,6 +30,8 @@ def upgrade(): # Allocate action op.drop_table('allocate', schema=f'{get_inv()}') op.create_table('allocate', + sa.Column('final_user_code', citext.CIText(), default='', nullable=True, + comment = "This is a internal code for mainteing the secrets of the personal datas of the new holder") sa.Column('transaction', citext.CIText(), nullable=True, comment='The code used from the owner for relation with external tool.'), sa.Column('end_users', sa.Numeric(precision=4), nullable=True), sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index ad05efca..fadc23ad 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -313,6 +313,9 @@ class Remove(ActionWithOneDevice): class Allocate(JoinedTableMixin, ActionWithMultipleDevices): """The act of allocate one list of devices to one person """ + final_user_code = Column(CIText(), default='', nullable=True) + final_user_code.comment = """This is a internal code for mainteing the secrets of the + personal datas of the new holder""" transaction = Column(CIText(), default='', nullable=True) transaction.comment = "The code used from the owner for relation with external tool." end_users = Column(Numeric(precision=4), check_range('end_users', 0), nullable=True) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 4c72a456..e32112ca 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -71,6 +71,11 @@ class Allocate(ActionWithMultipleDevices): description=m.Action.start_time.comment) end_time = DateTime(data_key='endTime', required=False, description=m.Action.end_time.comment) + final_user_code = SanitizedStr(data_key="finalUserCode" + validate=Length(min=1, max=STR_BIG_SIZE), + required=False, + description='This is a internal code for mainteing the secrets of the \ + personal datas of the new holder') transaction = SanitizedStr(validate=Length(min=1, max=STR_BIG_SIZE), required=False, description='The code used from the owner for \ diff --git a/tests/test_action.py b/tests/test_action.py index 5e4e014d..79cfa89c 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -279,6 +279,7 @@ def test_allocate(user: UserClient): snapshot, _ = user.post(file('basic.snapshot'), res=models.Snapshot) device_id = snapshot['device']['id'] post_request = {"transaction": "ccc", + "finalUserCode": "aabbcc", "name": "John", "severity": "Info", "endUsers": 1, @@ -294,6 +295,7 @@ def test_allocate(user: UserClient): assert device['allocated'] == True action = [a for a in device['actions'] if a['type'] == 'Allocate'][0] assert action['transaction'] == allocate['transaction'] + assert action['finalUserCode'] == allocate['finalUserCode'] assert action['created'] == allocate['created'] assert action['startTime'] == allocate['startTime'] assert action['endUsers'] == allocate['endUsers'] @@ -322,6 +324,7 @@ def test_allocate_bad_dates(user: UserClient): delta = timedelta(days=30) future = datetime.now() + delta post_request = {"transaction": "ccc", + "finalUserCode": "aabbcc", "name": "John", "severity": "Info", "end_users": 1, diff --git a/tests/test_metrics.py b/tests/test_metrics.py index c053235f..238b6132 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -17,6 +17,7 @@ def test_simple_metrics(user: UserClient): snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "finalUserCode": "abcdefjhi", "devices": [device_id], "description": "aaa", "startTime": "2020-11-01T02:00:00+00:00", "endTime": "2020-12-01T02:00:00+00:00" @@ -59,6 +60,7 @@ def test_second_hdd_metrics(user: UserClient): snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "finalUserCode": "abcdefjhi", "devices": [device_id], "description": "aaa", "startTime": "2020-11-01T02:00:00+00:00", "endTime": "2020-12-01T02:00:00+00:00" @@ -100,6 +102,7 @@ def test_metrics_with_live_null(user: UserClient): snapshot, _ = user.post(acer, res=ma.Snapshot) device_id = snapshot['device']['id'] post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "finalUserCode": "abcdefjhi", "devices": [device_id], "description": "aaa", "startTime": "2020-11-01T02:00:00+00:00", "endTime": "2020-12-01T02:00:00+00:00" From 70733db95d2eda74462b4cf5157297cb5bbe386b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 1 Dec 2020 15:45:19 +0100 Subject: [PATCH 62/72] fixing bugs --- .../migrations/versions/e93aec8fc41f_added_assigned_action.py | 2 +- ereuse_devicehub/resources/action/schemas.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 0d65cf9d..48a74602 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -31,7 +31,7 @@ def upgrade(): op.drop_table('allocate', schema=f'{get_inv()}') op.create_table('allocate', sa.Column('final_user_code', citext.CIText(), default='', nullable=True, - comment = "This is a internal code for mainteing the secrets of the personal datas of the new holder") + comment = "This is a internal code for mainteing the secrets of the personal datas of the new holder"), sa.Column('transaction', citext.CIText(), nullable=True, comment='The code used from the owner for relation with external tool.'), sa.Column('end_users', sa.Numeric(precision=4), nullable=True), sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index e32112ca..73c48140 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -71,7 +71,7 @@ class Allocate(ActionWithMultipleDevices): description=m.Action.start_time.comment) end_time = DateTime(data_key='endTime', required=False, description=m.Action.end_time.comment) - final_user_code = SanitizedStr(data_key="finalUserCode" + final_user_code = SanitizedStr(data_key="finalUserCode", validate=Length(min=1, max=STR_BIG_SIZE), required=False, description='This is a internal code for mainteing the secrets of the \ From 1e597cdb93ebda47718362b36c99be8f97aa48d8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 1 Dec 2020 15:48:49 +0100 Subject: [PATCH 63/72] clean code --- ereuse_devicehub/resources/action/schemas.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 73c48140..167793e9 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -13,11 +13,10 @@ from teal.resource import Schema from ereuse_devicehub.marshmallow import NestedOn from ereuse_devicehub.resources import enums from ereuse_devicehub.resources.action import models as m -from ereuse_devicehub.resources.action import schemas as s_action from ereuse_devicehub.resources.agent import schemas as s_agent from ereuse_devicehub.resources.device import schemas as s_device from ereuse_devicehub.resources.enums import AppearanceRange, BiosAccessRange, FunctionalityRange, \ - PhysicalErasureMethod, R_POSITIVE, RatingRange, ReceiverRole, \ + PhysicalErasureMethod, R_POSITIVE, RatingRange, \ Severity, SnapshotSoftware, TestDataStorageLength from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE from ereuse_devicehub.resources.schemas import Thing From 05c81382f2cd5c1a630e5be16f4880a15c78c73e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 1 Dec 2020 15:55:21 +0100 Subject: [PATCH 64/72] change comment of allocated --- 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 e8ebc62a..3a91bc36 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -107,7 +107,7 @@ class Device(Thing): image.comment = "An image of the device." allocated = db.Column(Boolean, default=False) - allocated.comment = "An image of the device." + allocated.comment = "device is allocated or not." _NON_PHYSICAL_PROPS = { 'id', From 783265ad657e0c08443521423b2c381729628f20 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 1 Dec 2020 17:27:43 +0100 Subject: [PATCH 65/72] adding finale user to live action --- .../versions/e93aec8fc41f_added_assigned_action.py | 2 ++ ereuse_devicehub/resources/action/models.py | 3 +++ ereuse_devicehub/resources/action/schemas.py | 12 +++--------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 48a74602..85aecb55 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -60,6 +60,8 @@ def upgrade(): op.drop_table('live', schema=f'{get_inv()}') op.create_table('live', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('final_user_code', citext.CIText(), default='', nullable=True, + comment = "This is a internal code for mainteing the secrets of the personal datas of the new holder"), sa.Column('serial_number', sa.Unicode(), nullable=True, comment='The serial number of the Hard Disk in lower case.'), sa.Column('time', sa.SmallInteger(), nullable=True), diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index fadc23ad..3436993d 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1299,6 +1299,9 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): information about its state (in the form of a ``Snapshot`` action) and usage statistics. """ + final_user_code = Column(CIText(), default='', nullable=True) + final_user_code.comment = """This is a internal code for mainteing the secrets of the + personal datas of the new holder""" serial_number = Column(Unicode(), check_lower('serial_number')) serial_number.comment = """The serial number of the Hard Disk in lower case.""" time = Column(SmallInteger, nullable=False) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 167793e9..864043c9 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -412,15 +412,9 @@ class Prepare(ActionWithMultipleDevices): class Live(ActionWithOneDevice): __doc__ = m.Live.__doc__ - ip = IP(dump_only=True) - subdivision_confidence = Integer(dump_only=True, data_key='subdivisionConfidence') - subdivision = EnumField(Subdivision, dump_only=True) - country = EnumField(Country, dump_only=True) - city = SanitizedStr(lower=True, dump_only=True) - city_confidence = Integer(dump_only=True, data_key='cityConfidence') - isp = SanitizedStr(lower=True, dump_only=True) - organization = SanitizedStr(lower=True, dump_only=True) - organization_type = SanitizedStr(lower=True, dump_only=True, data_key='organizationType') + final_user_code = SanitizedStr(data_key="finalUserCode", dump_only=True) + serial_number = SanitizedStr(data_key="serialNumber", dump_only=True) + time = Integer(dump_only=False) class Organize(ActionWithMultipleDevices): From 4d9420d1e993ee46a0df8932f72aa5ece9b7ce48 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 1 Dec 2020 22:03:15 +0100 Subject: [PATCH 66/72] adding final user and timings as property instead of insert this datas in the database --- .../e93aec8fc41f_added_assigned_action.py | 2 -- ereuse_devicehub/resources/action/models.py | 32 +++++++++++++++++-- ereuse_devicehub/resources/action/schemas.py | 1 + tests/test_action.py | 3 ++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 85aecb55..48a74602 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -60,8 +60,6 @@ def upgrade(): op.drop_table('live', schema=f'{get_inv()}') op.create_table('live', sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), - sa.Column('final_user_code', citext.CIText(), default='', nullable=True, - comment = "This is a internal code for mainteing the secrets of the personal datas of the new holder"), sa.Column('serial_number', sa.Unicode(), nullable=True, comment='The serial number of the Hard Disk in lower case.'), sa.Column('time', sa.SmallInteger(), nullable=True), diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 3436993d..c48cfd5c 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1299,13 +1299,39 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): information about its state (in the form of a ``Snapshot`` action) and usage statistics. """ - final_user_code = Column(CIText(), default='', nullable=True) - final_user_code.comment = """This is a internal code for mainteing the secrets of the - personal datas of the new holder""" serial_number = Column(Unicode(), check_lower('serial_number')) serial_number.comment = """The serial number of the Hard Disk in lower case.""" time = Column(SmallInteger, nullable=False) + @property + def final_user_code(self): + """ show the final_user_code of the last action Allocate.""" + actions = self.device.actions + actions.sort(key=lambda x: x.created) + for e in reversed(actions): + if isinstance(e, Allocate) and e.created < self.created: + return e.final_user_code + + @property + def hours_of_use(self): + """Show how many hours is used one device from the last check""" + actions = self.device.actions + actions.sort(key=lambda x: x.created) + # import pdb; pdb.set_trace() + for e in reversed(actions): + if isinstance(e, Snapshot) and e.created < self.created: + return self.time - self.get_last_power_cycle(e) + + if isinstance(e, Live) and e.created < self.created: + return self.time - e.time + + def get_last_power_cycle(self, snapshot): + test_hdd= [a for a in snapshot.actions if a.type == "TestDataStorage"] + if not (test_hdd and snapshot.device.allocated): + return 0 + + return test_hdd[0].power_cycle_count + class Organize(JoinedTableMixin, ActionWithMultipleDevices): """The act of manipulating/administering/supervising/controlling diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 864043c9..c4aeeca0 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -415,6 +415,7 @@ class Live(ActionWithOneDevice): final_user_code = SanitizedStr(data_key="finalUserCode", dump_only=True) serial_number = SanitizedStr(data_key="serialNumber", dump_only=True) time = Integer(dump_only=False) + hours_of_use = Integer(dump_only=False) class Organize(ActionWithMultipleDevices): diff --git a/tests/test_action.py b/tests/test_action.py index 79cfa89c..633bee92 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -255,6 +255,7 @@ def test_live(user: UserClient, app: Devicehub): db_device = Device.query.filter_by(id=1).one() post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", "startTime": "2020-11-01T02:00:00+00:00", "endTime": "2020-12-01T02:00:00+00:00" } @@ -269,6 +270,8 @@ def test_live(user: UserClient, app: Devicehub): action_live = [a for a in db_device.actions if a.type == 'Live'] assert len(action_live) == 1 assert action_live[0].time == 6293 + assert action_live[0].hours_of_use == 0 + assert action_live[0].final_user_code == post_request['finalUserCode'] assert action_live[0].serial_number == 'wd-wx11a80w7430' From 8a508ebc0e372dcc90c995ad3d14747f05fca66b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 2 Dec 2020 12:53:15 +0100 Subject: [PATCH 67/72] modify live action --- ereuse_devicehub/resources/action/models.py | 9 ++-- ereuse_devicehub/resources/action/views.py | 55 +++++++++++++++------ tests/test_action.py | 2 +- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index c48cfd5c..95c2676b 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1317,7 +1317,6 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): """Show how many hours is used one device from the last check""" actions = self.device.actions actions.sort(key=lambda x: x.created) - # import pdb; pdb.set_trace() for e in reversed(actions): if isinstance(e, Snapshot) and e.created < self.created: return self.time - self.get_last_power_cycle(e) @@ -1326,11 +1325,11 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): return self.time - e.time def get_last_power_cycle(self, snapshot): - test_hdd= [a for a in snapshot.actions if a.type == "TestDataStorage"] - if not (test_hdd and snapshot.device.allocated): - return 0 + for a in snapshot.actions: + if a.type == 'TestDataStorage' and a.device.serial_number == self.serial_number: + return a.power_cycle_count - return test_hdd[0].power_cycle_count + return 0 class Organize(JoinedTableMixin, ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 2fc5704f..86ca07df 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -17,6 +17,7 @@ from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import (Action, RateComputer, Snapshot, VisualTest, InitTransfer, Live, Allocate, Deallocate) +from ereuse_devicehub.resources.device.models import Device, Computer, DataStorage from ereuse_devicehub.resources.action.rate.v1_0 import CannotRate from ereuse_devicehub.resources.enums import SnapshotSoftware, Severity from ereuse_devicehub.resources.user.exceptions import InsufficientPermission @@ -142,6 +143,16 @@ class ActionView(View): # model object, when we flush them to the db we will flush # snapshot, and we want to wait to flush snapshot at the end + # If the device is allocated, then snapshot is a live + live = self.live(snapshot_json) + if live: + db.session.add(live) + db.session().final_flush() + ret = self.schema.jsonify(live) # transform it back + ret.status_code = 201 + db.session.commit() + return ret + device = snapshot_json.pop('device') # type: Computer components = None if snapshot_json['software'] == (SnapshotSoftware.Workbench or SnapshotSoftware.WorkbenchAndroid): @@ -192,7 +203,7 @@ class ActionView(View): # Check if HID is null and add Severity:Warning to Snapshot if snapshot.device.hid is None: snapshot.severity = Severity.Warning - self.live(snapshot) + db.session.add(snapshot) db.session().final_flush() ret = self.schema.jsonify(snapshot) # transform it back @@ -201,22 +212,38 @@ class ActionView(View): return ret def live(self, snapshot): - test_hdd= [a for a in snapshot.actions if a.type == "TestDataStorage"] - if not (test_hdd and snapshot.device.allocated): + """If the device.allocated == True, then this snapshot create an action live.""" + device = snapshot.get('device') # type: Computer + # TODO @cayop dependency of pulls 85 and 83 + # if the pr/85 and pr/83 is merged, then you need change this way for get the device + if not Device.query.filter(Device.hid==device.hid).count(): return - test_hdd = test_hdd[0] - time = test_hdd.power_cycle_count - if time: - data_live = {'time': time, - 'serial_number': test_hdd.device.serial_number, - 'device': snapshot.device - } - live = Live(**data_live) - snapshot.actions.add(live) - + device = Device.query.filter(Device.hid==device.hid).one() + + if not device.allocated: + return + + time = 0 + serial_number = '' + for hd in snapshot['components']: + if not isinstance(hd, DataStorage): + continue + for act in hd.actions: + if not act.type == "TestDataStorage": + continue + time = act.power_cycle_count + serial_number = hd.serial_number + + if not serial_number: + return + + data_live = {'time': time, + 'serial_number': serial_number, + 'device': device} + + return Live(**data_live) def transfer_ownership(self): """Perform a InitTransfer action to change author_id of device""" pass - diff --git a/tests/test_action.py b/tests/test_action.py index 633bee92..9572c3eb 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -270,7 +270,7 @@ def test_live(user: UserClient, app: Devicehub): action_live = [a for a in db_device.actions if a.type == 'Live'] assert len(action_live) == 1 assert action_live[0].time == 6293 - assert action_live[0].hours_of_use == 0 + assert action_live[0].hours_of_use == 1000 assert action_live[0].final_user_code == post_request['finalUserCode'] assert action_live[0].serial_number == 'wd-wx11a80w7430' From c03d872d91e303031ba6dd069cb8ebd6206454a8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 2 Dec 2020 13:15:21 +0100 Subject: [PATCH 68/72] fixed bug hid == None --- ereuse_devicehub/resources/action/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index 86ca07df..e3dbc8fd 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -216,7 +216,7 @@ class ActionView(View): device = snapshot.get('device') # type: Computer # TODO @cayop dependency of pulls 85 and 83 # if the pr/85 and pr/83 is merged, then you need change this way for get the device - if not Device.query.filter(Device.hid==device.hid).count(): + if not device.hid or not Device.query.filter(Device.hid==device.hid).count(): return device = Device.query.filter(Device.hid==device.hid).one() From 7e41c6607305faa036758f3afe19599499904e9a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 4 Dec 2020 16:58:53 +0100 Subject: [PATCH 69/72] implementing the warnings and unnormal cases --- .../e93aec8fc41f_added_assigned_action.py | 3 +- ereuse_devicehub/resources/action/models.py | 65 +++++-- ereuse_devicehub/resources/action/schemas.py | 5 +- ereuse_devicehub/resources/action/views.py | 68 +++++-- ereuse_devicehub/resources/device/sync.py | 2 + tests/test_action.py | 184 +++++++++++++++++- 6 files changed, 291 insertions(+), 36 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py index 48a74602..b335256d 100644 --- a/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py +++ b/ereuse_devicehub/migrations/versions/e93aec8fc41f_added_assigned_action.py @@ -62,7 +62,8 @@ def upgrade(): sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('serial_number', sa.Unicode(), nullable=True, comment='The serial number of the Hard Disk in lower case.'), - sa.Column('time', sa.SmallInteger(), nullable=True), + sa.Column('usage_time_hdd', sa.Interval(), nullable=True), + sa.Column('snapshot_uuid', postgresql.UUID(as_uuid=True), nullable=False), sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.action.id'], ), sa.PrimaryKeyConstraint('id'), schema=f'{get_inv()}' diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 95c2676b..0ba94a91 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -10,6 +10,7 @@ to a structure based on: Within the above general classes are subclasses in A order. """ +import copy from collections import Iterable from contextlib import suppress from datetime import datetime, timedelta, timezone @@ -1301,7 +1302,8 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): """ serial_number = Column(Unicode(), check_lower('serial_number')) serial_number.comment = """The serial number of the Hard Disk in lower case.""" - time = Column(SmallInteger, nullable=False) + usage_time_hdd = Column(Interval, nullable=True) + snapshot_uuid = Column(UUID(as_uuid=True)) @property def final_user_code(self): @@ -1311,26 +1313,65 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): for e in reversed(actions): if isinstance(e, Allocate) and e.created < self.created: return e.final_user_code + return '' @property - def hours_of_use(self): + def usage_time_allocate(self): """Show how many hours is used one device from the last check""" - actions = self.device.actions - actions.sort(key=lambda x: x.created) - for e in reversed(actions): - if isinstance(e, Snapshot) and e.created < self.created: - return self.time - self.get_last_power_cycle(e) + self.sort_actions() + if self.usage_time_hdd is None: + return self.last_usage_time_allocate() + delta_zero = timedelta(0) + diff_time = self.diff_time() + if diff_time is None: + return delta_zero + + if diff_time < delta_zero: + return delta_zero + return diff_time + + def sort_actions(self): + self.actions = copy.copy(self.device.actions) + self.actions.sort(key=lambda x: x.created) + self.actions.reverse() + + def last_usage_time_allocate(self): + """If we don't have self.usage_time_hdd then we need search the last + usage_time_allocate valid""" + for e in self.actions: if isinstance(e, Live) and e.created < self.created: - return self.time - e.time + if not e.usage_time_allocate: + continue + return e.usage_time_allocate + return timedelta(0) - def get_last_power_cycle(self, snapshot): + def diff_time(self): + for e in self.actions: + if e.created > self.created: + continue + + if isinstance(e, Snapshot): + last_time = self.get_last_lifetime(e) + if not last_time: + continue + return self.usage_time_hdd - last_time + + if isinstance(e, Live): + if e.snapshot_uuid == self.snapshot_uuid: + continue + + if not e.usage_time_hdd: + continue + return self.usage_time_hdd - e.usage_time_hdd + return None + + def get_last_lifetime(self, snapshot): for a in snapshot.actions: if a.type == 'TestDataStorage' and a.device.serial_number == self.serial_number: - return a.power_cycle_count + return a.lifetime + return None - return 0 - class Organize(JoinedTableMixin, ActionWithMultipleDevices): """The act of manipulating/administering/supervising/controlling diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index c4aeeca0..71eb8224 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -414,8 +414,9 @@ class Live(ActionWithOneDevice): __doc__ = m.Live.__doc__ final_user_code = SanitizedStr(data_key="finalUserCode", dump_only=True) serial_number = SanitizedStr(data_key="serialNumber", dump_only=True) - time = Integer(dump_only=False) - hours_of_use = Integer(dump_only=False) + usage_time_hdd = TimeDelta(data_key="usageTimeHdd", precision=TimeDelta.HOURS, dump_only=True) + usage_time_allocate = TimeDelta(data_key="usageTimeAllocate", + precision=TimeDelta.HOURS, dump_only=True) class Organize(ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index e3dbc8fd..a6aa108e 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -3,7 +3,7 @@ import os import json import shutil -from datetime import datetime +from datetime import datetime, timedelta from distutils.version import StrictVersion from uuid import UUID from flask.json import jsonify @@ -12,6 +12,7 @@ from flask import current_app as app, request, g, redirect from sqlalchemy.util import OrderedSet from teal.marshmallow import ValidationError from teal.resource import View +from teal.db import ResourceNotFound from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response @@ -211,38 +212,69 @@ class ActionView(View): db.session.commit() return ret + def get_hdd_details(self, snapshot, device): + """We get the liftime and serial_number of the disk""" + usage_time_hdd = None + serial_number = None + for hd in snapshot['components']: + if not isinstance(hd, DataStorage): + continue + + serial_number = hd.serial_number + for act in hd.actions: + if not act.type == "TestDataStorage": + continue + usage_time_hdd = act.lifetime + break + + if usage_time_hdd: + break + + if not serial_number: + "There aren't any disk" + raise ResourceNotFound("There aren't any disk in this device {}".format(device)) + return usage_time_hdd, serial_number + def live(self, snapshot): """If the device.allocated == True, then this snapshot create an action live.""" device = snapshot.get('device') # type: Computer # TODO @cayop dependency of pulls 85 and 83 # if the pr/85 and pr/83 is merged, then you need change this way for get the device if not device.hid or not Device.query.filter(Device.hid==device.hid).count(): - return + return None device = Device.query.filter(Device.hid==device.hid).one() if not device.allocated: - return + return None - time = 0 - serial_number = '' - for hd in snapshot['components']: - if not isinstance(hd, DataStorage): - continue - for act in hd.actions: - if not act.type == "TestDataStorage": - continue - time = act.power_cycle_count - serial_number = hd.serial_number + usage_time_hdd, serial_number = self.get_hdd_details(snapshot, device) - if not serial_number: - return - - data_live = {'time': time, + data_live = {'usage_time_hdd': usage_time_hdd, 'serial_number': serial_number, + 'snapshot_uuid': snapshot['uuid'], + 'description': '', 'device': device} - return Live(**data_live) + live = Live(**data_live) + + if not usage_time_hdd: + warning = f"We don't found any TestDataStorage for disk sn: {serial_number}" + live.severity = Severity.Warning + live.description = warning + return live + + live.sort_actions() + diff_time = live.diff_time() + if diff_time is None: + warning = "Don't exist one previus live or snapshot as reference" + live.description += warning + live.severity = Severity.Warning + elif diff_time < timedelta(0): + warning = "The difference with the last live/snapshot is negative" + live.description += warning + live.severity = Severity.Warning + return live def transfer_ownership(self): """Perform a InitTransfer action to change author_id of device""" diff --git a/ereuse_devicehub/resources/device/sync.py b/ereuse_devicehub/resources/device/sync.py index 5f13d5a0..28925291 100644 --- a/ereuse_devicehub/resources/device/sync.py +++ b/ereuse_devicehub/resources/device/sync.py @@ -154,6 +154,8 @@ class Sync: if device.hid: with suppress(ResourceNotFound): db_device = Device.query.filter_by(hid=device.hid).one() + if db_device and db_device.allocated: + raise ResourceNotFound('device is actually allocated {}'.format(device)) try: tags = {Tag.from_an_id(tag.id).one() for tag in device.tags} # type: Set[Tag] except ResourceNotFound: diff --git a/tests/test_action.py b/tests/test_action.py index 9572c3eb..cafd392e 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -264,15 +264,193 @@ def test_live(user: UserClient, app: Devicehub): acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] - hdd_action['powerCycleCount'] += 1000 + hdd_action['lifetime'] += 1000 snapshot, _ = user.post(acer, res=models.Snapshot) db_device = Device.query.filter_by(id=1).one() action_live = [a for a in db_device.actions if a.type == 'Live'] assert len(action_live) == 1 - assert action_live[0].time == 6293 - assert action_live[0].hours_of_use == 1000 + assert action_live[0].usage_time_hdd == timedelta(hours=hdd_action['lifetime']) + assert action_live[0].usage_time_allocate == timedelta(hours=1000) assert action_live[0].final_user_code == post_request['finalUserCode'] assert action_live[0].serial_number == 'wd-wx11a80w7430' + assert str(action_live[0].snapshot_uuid) == acer['uuid'] + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live_without_TestDataStorage(user: UserClient, app: Devicehub): + """Tests inserting a Live into the database and GETting it. + If the live don't have a TestDataStorage, then save live and response None + """ + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + actions = [a for a in acer['components'][7]['actions'] if a['type'] != 'TestDataStorage'] + acer['components'][7]['actions'] = actions + live, _ = user.post(acer, res=models.Snapshot) + assert live['type'] == 'Live' + assert live['serialNumber'] == 'wd-wx11a80w7430' + assert live['severity'] == 'Warning' + description = "We don't found any TestDataStorage for disk sn: wd-wx11a80w7430" + assert live['description'] == description + db_live = models.Live.query.filter_by(id=live['id']).one() + assert db_live.usage_time_hdd is None + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live_without_hdd_1(user: UserClient, app: Devicehub): + """Tests inserting a Live into the database and GETting it. + The snapshot have hdd but the live no, and response 404 + """ + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + components = [a for a in acer['components'] if a['type'] != 'HardDrive'] + acer['components'] = components + response, _ = user.post(acer, res=models.Snapshot, status=404) + assert "The There aren't any disk in this device" in response['message'] + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live_without_hdd_2(user: UserClient, app: Devicehub): + """Tests inserting a Live into the database and GETting it. + The snapshot haven't hdd and the live neither, and response 404 + """ + acer = file('acer.happy.battery.snapshot') + components = [a for a in acer['components'] if a['type'] != 'HardDrive'] + acer['components'] = components + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + response, _ = user.post(acer, res=models.Snapshot, status=404) + assert "The There aren't any disk in this device" in response['message'] + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live_without_hdd_3(user: UserClient, app: Devicehub): + """Tests inserting a Live into the database and GETting it. + The snapshot haven't hdd and the live have, and save the live + with usage_time_allocate == 0 + """ + acer = file('acer.happy.battery.snapshot') + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + components = [a for a in acer['components'] if a['type'] != 'HardDrive'] + acer['components'] = components + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer = file('acer.happy.battery.snapshot') + live, _ = user.post(acer, res=models.Snapshot) + assert live['type'] == 'Live' + assert live['serialNumber'] == 'wd-wx11a80w7430' + assert live['severity'] == 'Warning' + description = "Don't exist one previus live or snapshot as reference" + assert live['description'] == description + db_live = models.Live.query.filter_by(id=live['id']).one() + assert str(db_live.usage_time_hdd) == '195 days, 12:00:00' + assert str(db_live.usage_time_allocate) == '0:00:00' + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live_with_hdd_with_old_time(user: UserClient, app: Devicehub): + """Tests inserting a Live into the database and GETting it. + The snapshot hdd have a lifetime higher than lifetime of the live action + save the live with usage_time_allocate == 0 + """ + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer = file('acer.happy.battery.snapshot') + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + action = [a for a in acer['components'][7]['actions'] if a['type'] == 'TestDataStorage'] + action[0]['lifetime'] -= 100 + live, _ = user.post(acer, res=models.Snapshot) + assert live['type'] == 'Live' + assert live['serialNumber'] == 'wd-wx11a80w7430' + assert live['severity'] == 'Warning' + description = "The difference with the last live/snapshot is negative" + assert live['description'] == description + db_live = models.Live.query.filter_by(id=live['id']).one() + assert str(db_live.usage_time_hdd) == '191 days, 8:00:00' + assert str(db_live.usage_time_allocate) == '0:00:00' + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_live_search_last_allocate(user: UserClient, app: Devicehub): + """Tests inserting a Live into the database and GETting it. + """ + acer = file('acer.happy.battery.snapshot') + snapshot, _ = user.post(acer, res=models.Snapshot) + device_id = snapshot['device']['id'] + db_device = Device.query.filter_by(id=1).one() + post_request = {"transaction": "ccc", "name": "John", "endUsers": 1, + "devices": [device_id], "description": "aaa", + "finalUserCode": "abcdefjhi", + "startTime": "2020-11-01T02:00:00+00:00", + "endTime": "2020-12-01T02:00:00+00:00" + } + + user.post(res=models.Allocate, data=post_request) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec3" + hdd = [c for c in acer['components'] if c['type'] == 'HardDrive'][0] + hdd_action = [a for a in hdd['actions'] if a['type'] == 'TestDataStorage'][0] + hdd_action['lifetime'] += 1000 + live, _ = user.post(acer, res=models.Snapshot) + acer['uuid'] = "490fb8c0-81a1-42e9-95e0-5e7db7038ec4" + actions = [a for a in acer['components'][7]['actions'] if a['type'] != 'TestDataStorage'] + acer['components'][7]['actions'] = actions + live, _ = user.post(acer, res=models.Snapshot) + assert live['usageTimeAllocate'] == 1000 @pytest.mark.mvp From 835f875e2efc005207c5bb727e4b871aa7e31b00 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 4 Dec 2020 19:33:05 +0100 Subject: [PATCH 70/72] fixed comments --- ereuse_devicehub/resources/action/models.py | 4 ++-- ereuse_devicehub/resources/action/views.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 0ba94a91..07c1c1b9 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1337,8 +1337,8 @@ class Live(JoinedWithOneDeviceMixin, ActionWithOneDevice): self.actions.reverse() def last_usage_time_allocate(self): - """If we don't have self.usage_time_hdd then we need search the last - usage_time_allocate valid""" + """If we don't have self.usage_time_hdd then we need search the last + action Live with usage_time_allocate valid""" for e in self.actions: if isinstance(e, Live) and e.created < self.created: if not e.usage_time_allocate: diff --git a/ereuse_devicehub/resources/action/views.py b/ereuse_devicehub/resources/action/views.py index a6aa108e..f6e5eb8c 100644 --- a/ereuse_devicehub/resources/action/views.py +++ b/ereuse_devicehub/resources/action/views.py @@ -267,7 +267,7 @@ class ActionView(View): live.sort_actions() diff_time = live.diff_time() if diff_time is None: - warning = "Don't exist one previus live or snapshot as reference" + warning = "Don't exist one previous live or snapshot as reference" live.description += warning live.severity = Severity.Warning elif diff_time < timedelta(0): From 2a57c436bd9df34b8835ffa4038d2b609ecddc78 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 5 Dec 2020 20:22:38 +0100 Subject: [PATCH 71/72] fixed comment in debug --- tests/test_action.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_action.py b/tests/test_action.py index cafd392e..09c60c05 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -383,7 +383,7 @@ def test_live_without_hdd_3(user: UserClient, app: Devicehub): assert live['type'] == 'Live' assert live['serialNumber'] == 'wd-wx11a80w7430' assert live['severity'] == 'Warning' - description = "Don't exist one previus live or snapshot as reference" + description = "Don't exist one previous live or snapshot as reference" assert live['description'] == description db_live = models.Live.query.filter_by(id=live['id']).one() assert str(db_live.usage_time_hdd) == '195 days, 12:00:00' From 2daee4ddd85a8b0955dfc23b73fbb97bed20032a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 9 Dec 2020 10:23:58 +0100 Subject: [PATCH 72/72] update version --- ereuse_devicehub/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/__init__.py b/ereuse_devicehub/__init__.py index 944f81a7..feee2d99 100644 --- a/ereuse_devicehub/__init__.py +++ b/ereuse_devicehub/__init__.py @@ -1 +1 @@ -__version__ = "1.0.1-beta" +__version__ = "1.0.2-beta"