From 35e891bf5d0618210865f6f39766487dad15bba2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 11 Oct 2021 14:11:56 +0200 Subject: [PATCH 01/48] trace in metrics --- ereuse_devicehub/resources/device/models.py | 43 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index f27a97d8..2b21734f 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -467,7 +467,7 @@ class Device(Thing): """ actions = copy.copy(self.actions) actions.sort(key=lambda x: x.created) - allocates = [] + allocates = [] lifetime = 0 for act in actions: if act.type == 'Snapshot': @@ -479,6 +479,12 @@ class Device(Thing): if act.type == 'Allocate': allo = {'type': 'Allocate', + 'action_type': 'Status', + 'status_receiver': 'Use', + 'trade_supplier': '', + 'trade_receiver': '', + 'trade_confirmed': '', + 'action_create_by': 'Receiver', 'devicehubID': self.devicehub_id, 'finalUserCode': act.final_user_code, 'numEndUsers': act.end_users, @@ -501,6 +507,12 @@ class Device(Thing): if act.type == 'Deallocate': deallo = {'type': 'Deallocate', 'devicehubID': self.devicehub_id, + 'action_type': 'Status', + 'status_receiver': 'Use', + 'trade_supplier': '', + 'trade_receiver': '', + 'trade_confirmed': '', + 'action_create_by': 'Receiver', 'finalUserCode': '', 'numEndUsers': '', 'hid': self.hid, @@ -510,6 +522,35 @@ class Device(Thing): 'usageTimeAllocate': 0} allocates.append(deallo) + if act.type == 'Trade': + confirm = False + if hasattr(act, 'acceptances'): + accept = act.acceptances[-1] + if accept.t == 'Confirm' and accept.user == act.user_to: + confirm = True + + action_create_by = 'Receiver' + if act.author == act.user_from: + action_create_by = 'Supplier' + trade = {'type': 'Trade', + 'action_type': 'Trade', + 'trade_supplier': act.user_from, + 'trade_receiver': act.user_to, + 'trade_confirmed': confirm, + 'action_create_by': action_create_by, + 'trade_confirmed': confirm, + 'devicehubID': self.devicehub_id, + 'finalUserCode': '', + 'numEndUsers': '', + 'hid': self.hid, + 'liveCreate': 0, + 'usageTimeHdd': lifetime, + 'start': act.start_time, + 'status_receiver': 'Use', + 'usageTimeAllocate': 0 + } + allocates.append(trade) + return allocates def __lt__(self, other): From 5e9b9bf08ddf127ed56c7b27d8f896843822d0fb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 14 Oct 2021 12:56:33 +0200 Subject: [PATCH 02/48] new metrics --- ereuse_devicehub/resources/device/metrics.py | 174 +++++++++++++++++++ ereuse_devicehub/resources/device/models.py | 102 +---------- tests/test_metrics.py | 54 ++++++ 3 files changed, 237 insertions(+), 93 deletions(-) create mode 100644 ereuse_devicehub/resources/device/metrics.py diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py new file mode 100644 index 00000000..c8646775 --- /dev/null +++ b/ereuse_devicehub/resources/device/metrics.py @@ -0,0 +1,174 @@ +import copy + + +class Metrics: + """we want get the data metrics of one device""" + + def __init__(self, device): + self.hid = device.hid + self.devicehub_id = device.devicehub_id + self.actions = copy.copy(device.actions) + self.actions.sort(key=lambda x: x.created) + self.rows = [] + self.lifetime = 0 + self.last_trade = None + self.action_create_by = 'Receiver' + self.status_receiver = 'Use' + self.status_supplier = '' + self.act = None + self.end_users = 0 + self.final_user_code = '' + + def get_template_row(self): + """ + This is a template of a row. + """ + return {'type': '', + 'action_type': 'Status', + 'status_receiver': self.status_receiver, + 'status_supplier': self.status_supplier, + 'trade_supplier': '', + 'trade_receiver': self.act.author, + 'trade_confirmed': '', + 'action_create_by': self.action_create_by, + 'devicehubID': self.devicehub_id, + 'hid': self.hid, + 'finalUserCode': '', + 'numEndUsers': 0, + 'liveCreate': 0, + 'usageTimeHdd': self.lifetime, + 'start': self.act.created, + 'usageTimeAllocate': 0} + + def get_action_status(self): + """ + Mark the status of one device. + If exist one trade before this action, then modify the trade action + else, create one row new. + """ + self.status_receiver = self.act.type + self.status_supplier = '' + if self.act.author != self.act.rol_user: + # It is neccesary exist one trade action before + self.last_trade['status_supplier'] = self.act.type + self.last_trade['status_supplier_created'] = self.act.created + return + + if self.last_trade: + # if exist one trade action before + self.last_trade['status_receiver'] = self.act.type + self.last_trade['status_receiver_created'] = self.act.created + return + + # If not exist any trade action for this device + self.action_create_by = 'Receiver' + row = self.get_template_row() + row['type'] = 'Status' + self.rows.append(row) + + def get_snapshot(self): + """ + If there are one snapshot get the last lifetime for to do a calcul of time of use. + """ + lifestimes = self.act.get_last_lifetimes() + if lifestimes: + self.lifetime = lifestimes[0]['lifetime'] + + def get_allocate(self): + """ + If the action is one Allocate, need modify the row base. + """ + self.end_users = self.act.end_users + self.final_user_code = self.act.final_user_code + row = self.get_template_row() + row['type'] = 'Allocate' + row['trade_supplier'] = '' + row['finalUserCode'] = self.final_user_code + row['numEndUsers'] = self.end_users + row['start'] = self.act.start_time + row['usageTimeAllocate'] = self.lifetime + self.rows.append(row) + + def get_live(self): + """ + If the action is one Live, need modify the row base. + """ + row = self.get_template_row() + row['type'] = 'Live' + row['finalUserCode'] = self.final_user_code + row['numEndUsers'] = self.end_users + row['start'] = self.act.start_time + row['usageTimeAllocate'] = self.lifetime + row['liveCreate'] = self.act.created + if self.act.usage_time_hdd: + row['usageTimeHdd'] = self.act.usage_time_hdd.total_seconds() / 3600 + self.rows.append(row) + + def get_deallocate(self): + """ + If the action is one Dellocate, need modify the row base. + """ + row = self.get_template_row() + row['type'] = 'Deallocate' + row['start'] = self.act.start_time + self.rows.append(row) + + def get_confirms(self): + """ + if the action is one trade action, is possible than have a list of confirmations. + Get the doble confirm for to know if this trade is confirmed or not. + """ + if hasattr(self.act, 'acceptances'): + accept = self.act.acceptances[-1] + if accept.t == 'Confirm' and accept.user == self.act.user_to: + return True + return False + + def get_trade(self): + """ + If this action is a trade action modify the base row. + """ + if self.act.author == self.act.user_from: + self.action_create_by = 'Supplier' + row = self.get_template_row() + self.last_trade = row + row['type'] = 'Trade' + row['action_type'] = 'Trade' + row['trade_supplier'] = self.act.user_from + row['trade_receiver'] = self.act.user_to + row['self.status_receiver'] = self.status_receiver + row['self.status_supplier'] = self.status_supplier + row['trade_confirmed'] = self.get_confirms() + self.rows.append(row) + + def get_metrics(self): + """ + This method get a list of values for calculate a metrics from a spreadsheet + """ + for act in self.actions: + self.act = act + if act.type in ['Use', 'Refurbish', 'Recycling', 'Management']: + self.get_action_status() + continue + + if act.type == 'Snapshot': + self.get_snapshot() + continue + + if act.type == 'Allocate': + self.get_allocate() + continue + + if act.type == 'Live': + self.get_live() + continue + + if act.type == 'Deallocate': + self.get_deallocate() + continue + + if act.type == 'Trade': + self.get_trade() + continue + + return self.rows diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 7c847cbf..d940534d 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -34,6 +34,7 @@ from ereuse_devicehub.resources.enums import BatteryTechnology, CameraFacing, Co DataStorageInterface, DisplayTech, PrinterTechnology, RamFormat, RamInterface, Severity, TransferState from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing, listener_reset_field_updated_in_actual_time from ereuse_devicehub.resources.user.models import User +from ereuse_devicehub.resources.device.metrics import Metrics def create_code(context): @@ -206,10 +207,10 @@ class Device(Thing): if isinstance(c, ColumnProperty) and not getattr(c, 'foreign_keys', None) and c.key not in self._NON_PHYSICAL_PROPS} - + @property def public_properties(self) -> Dict[str, object or None]: - """Fields that describe the properties of a device than next show + """Fields that describe the properties of a device than next show in the public page. :return A dictionary: @@ -341,7 +342,7 @@ class Device(Thing): ac = self.last_action_trading if not ac: - return + return first_owner = self.which_user_put_this_device_in_trace() @@ -349,7 +350,7 @@ class Device(Thing): # can to do revoke_confirmed return confirm_revoke - if ac.type == revoke: + if ac.type == revoke: if ac.user == g.user: # can todo revoke_pending return revoke_pending @@ -505,93 +506,8 @@ class Device(Thing): """ This method get a list of values for calculate a metrics from a spreadsheet """ - actions = copy.copy(self.actions) - actions.sort(key=lambda x: x.created) - allocates = [] - lifetime = 0 - for act in actions: - if act.type == 'Snapshot': - snapshot = act - lifestimes = snapshot.get_last_lifetimes() - lifetime = 0 - if lifestimes: - lifetime = lifestimes[0]['lifetime'] - - if act.type == 'Allocate': - allo = {'type': 'Allocate', - 'action_type': 'Status', - 'status_receiver': 'Use', - 'trade_supplier': '', - 'trade_receiver': '', - 'trade_confirmed': '', - 'action_create_by': 'Receiver', - 'devicehubID': self.devicehub_id, - 'finalUserCode': act.final_user_code, - 'numEndUsers': act.end_users, - 'hid': self.hid, - 'liveCreate': 0, - 'usageTimeHdd': 0, - 'start': act.start_time, - 'usageTimeAllocate': lifetime} - allocates.append(allo) - - if act.type == 'Live': - allocate = copy.copy(allo) - allocate['type'] = 'Live' - allocate['liveCreate'] = act.created - allocate['usageTimeHdd'] = 0 - if act.usage_time_hdd: - allocate['usageTimeHdd'] = act.usage_time_hdd.total_seconds()/3600 - allocates.append(allocate) - - if act.type == 'Deallocate': - deallo = {'type': 'Deallocate', - 'devicehubID': self.devicehub_id, - 'action_type': 'Status', - 'status_receiver': 'Use', - 'trade_supplier': '', - 'trade_receiver': '', - 'trade_confirmed': '', - 'action_create_by': 'Receiver', - 'finalUserCode': '', - 'numEndUsers': '', - 'hid': self.hid, - 'liveCreate': 0, - 'usageTimeHdd': lifetime, - 'start': act.start_time, - 'usageTimeAllocate': 0} - allocates.append(deallo) - - if act.type == 'Trade': - confirm = False - if hasattr(act, 'acceptances'): - accept = act.acceptances[-1] - if accept.t == 'Confirm' and accept.user == act.user_to: - confirm = True - - action_create_by = 'Receiver' - if act.author == act.user_from: - action_create_by = 'Supplier' - trade = {'type': 'Trade', - 'action_type': 'Trade', - 'trade_supplier': act.user_from, - 'trade_receiver': act.user_to, - 'trade_confirmed': confirm, - 'action_create_by': action_create_by, - 'trade_confirmed': confirm, - 'devicehubID': self.devicehub_id, - 'finalUserCode': '', - 'numEndUsers': '', - 'hid': self.hid, - 'liveCreate': 0, - 'usageTimeHdd': lifetime, - 'start': act.start_time, - 'status_receiver': 'Use', - 'usageTimeAllocate': 0 - } - allocates.append(trade) - - return allocates + metrics = Metrics(self) + return metrics.get_metrics() def __lt__(self, other): return self.id < other.id @@ -790,7 +706,7 @@ class Computer(Device): return urls def add_mac_to_hid(self, components_snap=None): - """Returns the Naming.hid with the first mac of network adapter, + """Returns the Naming.hid with the first mac of network adapter, following an alphabetical order. """ self.set_hid() @@ -923,7 +839,7 @@ class Component(Device): """ assert self.hid is None, 'Don\'t use this method with a component that has HID' component = self.__class__.query \ - .filter_by(parent=parent, hid=None, owner_id=self.owner_id, + .filter_by(parent=parent, hid=None, owner_id=self.owner_id, **self.physical_properties) \ .filter(~Component.id.in_(blacklist)) \ .first() diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 54544328..aca7808c 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -2,6 +2,7 @@ import pytest from ereuse_devicehub.client import UserClient from ereuse_devicehub.resources.action import models as ma +from ereuse_devicehub.resources.documents import documents from tests import conftest from tests.conftest import file, yaml2json, json_encode @@ -120,3 +121,56 @@ def test_metrics_with_live_null(user: UserClient): res, _ = user.get("/metrics/") assert res == metrics + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_metrics_action_status(user: UserClient, user2: UserClient): + """ Checks one standard query of metrics """ + # Insert computer + lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') + snap, _ = user.post(json_encode(lenovo), res=ma.Snapshot) + action = {'type': ma.Use.t, 'devices': [snap['device']['id']]} + action_use, _ = user.post(action, res=ma.Action) + # res, _ = user.get("/metrics/") + csv_str, _ = user.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + import pdb; pdb.set_trace() + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_complet_metrics(user: UserClient, user2: UserClient): + """ Checks one standard query of metrics """ + # Insert computer + lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') + acer = yaml2json('acer.happy.battery.snapshot') + snap1, _ = user.post(json_encode(lenovo), res=ma.Snapshot) + snap2, _ = user.post(json_encode(acer), res=ma.Snapshot) + lot, _ = user.post({'name': 'MyLot'}, res=Lot) + devices = [('id', snap1['device']['id']), + ('id', snap2['device']['id']) + ] + lot, _ = user.post({}, + res=Lot, + item='{}/devices'.format(lot['id']), + query=devices) + # request_post = { + # 'type': 'Trade', + # 'devices': [span1['device']['id'], snap2['device']['id']], + # 'userFromEmail': user2.email, + # 'userToEmail': user.email, + # 'price': 10, + # 'date': "2020-12-01T02:00:00+00:00", + # 'lot': lot['id'], + # 'confirms': True, + # } + + # user.post(res=models.Action, data=request_post) + + # ============================== + # Check metrics + metrics = {'allocateds': 1, 'live': 1} + res, _ = user.get("/metrics/") + assert res == metrics From 17f8aebb94d75e36177c0c9441108722d7bbace6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 14 Oct 2021 18:13:20 +0200 Subject: [PATCH 03/48] fixing rows --- ereuse_devicehub/resources/device/metrics.py | 14 +++++++++----- .../resources/documents/device_row.py | 17 ++++++++++++++--- tests/test_metrics.py | 7 ++++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index c8646775..68a790b4 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -25,11 +25,15 @@ class Metrics: """ return {'type': '', 'action_type': 'Status', + 'document_name': '', 'status_receiver': self.status_receiver, 'status_supplier': self.status_supplier, + 'status_receiver_created': '', + 'status_supplier_created': '', 'trade_supplier': '', - 'trade_receiver': self.act.author, + 'trade_receiver': self.act.author.email, 'trade_confirmed': '', + 'trade_weight': 0, 'action_create_by': self.action_create_by, 'devicehubID': self.devicehub_id, 'hid': self.hid, @@ -54,6 +58,7 @@ class Metrics: self.last_trade['status_supplier_created'] = self.act.created return + self.action_create_by = 'Receiver' if self.last_trade: # if exist one trade action before self.last_trade['status_receiver'] = self.act.type @@ -61,9 +66,8 @@ class Metrics: return # If not exist any trade action for this device - self.action_create_by = 'Receiver' row = self.get_template_row() - row['type'] = 'Status' + row['status_receiver_created'] = self.act.created self.rows.append(row) def get_snapshot(self): @@ -134,8 +138,8 @@ class Metrics: self.last_trade = row row['type'] = 'Trade' row['action_type'] = 'Trade' - row['trade_supplier'] = self.act.user_from - row['trade_receiver'] = self.act.user_to + row['trade_supplier'] = self.act.user_from.email + row['trade_receiver'] = self.act.user_to.email row['self.status_receiver'] = self.status_receiver row['self.status_supplier'] = self.status_supplier row['trade_confirmed'] = self.get_confirms() diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index 4e683ef9..36c93819 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -427,9 +427,20 @@ class ActionRow(OrderedDict): # General information about allocates, deallocate and lives self['DHID'] = allocate['devicehubID'] self['Hid'] = allocate['hid'] - self['Start'] = allocate['start'] - self['FinalUserCode'] = allocate['finalUserCode'] - self['NumEndUsers'] = allocate['numEndUsers'] + self['Document-Name'] = allocate['document_name'] + self['Action-Type'] = allocate['action_type'] + self['Action-User-LastOwner-Supplier'] = allocate['trade_supplier'] + self['Action-User-LastOwner-Receiver'] = allocate['trade_receiver'] + self['Action-Create-By'] = allocate['action_create_by'] + self['Trade-Confirmed'] = allocate['trade_confirmed'] + self['Status-Supplier'] = allocate['status_supplier'] + self['Status-Receiver'] = allocate['status_receiver'] + self['Status Supplier – Created Date'] = allocate['status_supplier_created'] + self['Status Receiver – Created Date'] = allocate['status_receiver_created'] + self['Trade-Weight'] = allocate['trade_weight'] + self['Allocate-Start'] = allocate['start'] + self['Allocate-User-Code'] = allocate['finalUserCode'] + self['Allocate-NumUsers'] = allocate['numEndUsers'] self['UsageTimeAllocate'] = allocate['usageTimeAllocate'] self['Type'] = allocate['type'] self['LiveCreate'] = allocate['liveCreate'] diff --git a/tests/test_metrics.py b/tests/test_metrics.py index aca7808c..46c2a20c 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -136,7 +136,11 @@ def test_metrics_action_status(user: UserClient, user2: UserClient): item='actions/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - import pdb; pdb.set_trace() + # import pdb; pdb.set_trace() + head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Supplier;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' + body = '93652;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Status;;foo@foo.com;Receiver;;;Use;;' + assert head in csv_str + assert body in csv_str @pytest.mark.mvp @@ -156,6 +160,7 @@ def test_complet_metrics(user: UserClient, user2: UserClient): res=Lot, item='{}/devices'.format(lot['id']), query=devices) + import pdb; pdb.set_trace() # request_post = { # 'type': 'Trade', # 'devices': [span1['device']['id'], snap2['device']['id']], From 0eed8330cef4fdcde30aa85f9a57de7835f70acd Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 15 Oct 2021 15:04:58 +0200 Subject: [PATCH 04/48] adding metrics for documents --- ereuse_devicehub/resources/action/models.py | 11 +++++++ ereuse_devicehub/resources/device/metrics.py | 33 ++++++++++++++++--- ereuse_devicehub/resources/device/models.py | 2 +- .../resources/documents/documents.py | 18 ++++++++++ tests/test_metrics.py | 2 +- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 853fd49b..f2df237d 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -49,6 +49,7 @@ from ereuse_devicehub.resources.enums import AppearanceRange, BatteryHealth, Bio from ereuse_devicehub.resources.models import STR_SM_SIZE, Thing from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.tradedocument.models import TradeDocument +from ereuse_devicehub.resources.device.metrics import TradeMetrics class JoinedTableMixin: @@ -1633,6 +1634,16 @@ class Trade(JoinedTableMixin, ActionWithMultipleTradeDocuments): cascade=CASCADE_OWN), primaryjoin='Trade.lot_id == Lot.id') + def get_metrics(self): + """ + This method get a list of values for calculate a metrics from a spreadsheet + """ + metrics = [] + for doc in self.documents: + m = TradeMetrics(document=doc, Trade=self) + metrics.append(m.get_metrics()) + return metrics + def __repr__(self) -> str: return '<{0.t} {0.id} executed by {0.author}>'.format(self) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 68a790b4..80840b87 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -1,12 +1,10 @@ import copy -class Metrics: +class MetricsMix: """we want get the data metrics of one device""" - def __init__(self, device): - self.hid = device.hid - self.devicehub_id = device.devicehub_id + def __init__(self, *args, **kwargs): self.actions = copy.copy(device.actions) self.actions.sort(key=lambda x: x.created) self.rows = [] @@ -44,6 +42,22 @@ class Metrics: 'start': self.act.created, 'usageTimeAllocate': 0} + def get_metrics(self): + """ + This method get a list of values for calculate a metrics from a spreadsheet + """ + return self.rows + + +class Metrics(MetricsMix): + """we want get the data metrics of one device""" + + def __init__(self, *args, **kwargs): + device = kwargs.pop('device') + super().__init__(*args, **kwargs) + self.hid = device.hid + self.devicehub_id = device.devicehub_id + def get_action_status(self): """ Mark the status of one device. @@ -176,3 +190,14 @@ class Metrics: continue return self.rows + + +class TradeMetrics(MetricsMix): + """we want get the data metrics of one device""" + + def __init__(self, *args, **kwargs): + document = kwargs.pop('document') + super().__init__(*args, **kwargs) + self.hid = document.hash + self.devicehub_id = '' + diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index d940534d..2322326a 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -506,7 +506,7 @@ class Device(Thing): """ This method get a list of values for calculate a metrics from a spreadsheet """ - metrics = Metrics(self) + metrics = Metrics(device=self) return metrics.get_metrics() def __lt__(self, other): diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index f6de8884..41606d0b 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -159,13 +159,31 @@ class ActionsDocumentView(DeviceView): data = StringIO() cw = csv.writer(data, delimiter=';', lineterminator="\n", quotechar='"') first = True + devs_id = [] for device in query: + devs_id.append(device.id) for allocate in device.get_metrics(): d = ActionRow(allocate) if first: cw.writerow(d.keys()) first = False cw.writerow(d.values()) + from ereuse_devicehub.resources.action.models import Trade + from ereuse_devicehub.resources.device.models import Device + # import pdb; pdb.set_trace() + query_trade = Trade.query.filter(Trade.devices.any(Device.id.in_(devs_id))).all() + doc_metrics = [] + + for trade in query_trade: + doc_metrics.extend(trade.get_metrics()) + + for data_row in doc_metrics: + row = ActionRow(data_row) + if first: + cw.writerow(row.keys()) + first = False + cw.writerow(row.values()) + bfile = data.getvalue().encode('utf-8') output = make_response(bfile) insert_hash(bfile) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 46c2a20c..70c728d2 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -160,7 +160,7 @@ def test_complet_metrics(user: UserClient, user2: UserClient): res=Lot, item='{}/devices'.format(lot['id']), query=devices) - import pdb; pdb.set_trace() + # import pdb; pdb.set_trace() # request_post = { # 'type': 'Trade', # 'devices': [span1['device']['id'], snap2['device']['id']], From 87f30a1391521a463cd5a13394d3ae2cd10a5d2e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 19 Oct 2021 18:19:25 +0200 Subject: [PATCH 05/48] adding metrics for tradeDocuments --- ereuse_devicehub/resources/action/models.py | 2 +- ereuse_devicehub/resources/device/metrics.py | 52 ++++++- .../resources/documents/device_row.py | 2 + .../resources/documents/documents.py | 21 ++- tests/test_metrics.py | 129 ++++++++++++++---- 5 files changed, 156 insertions(+), 50 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index ce6e4e70..fbc05234 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1640,7 +1640,7 @@ class Trade(JoinedTableMixin, ActionWithMultipleTradeDocuments): metrics = [] for doc in self.documents: m = TradeMetrics(document=doc, Trade=self) - metrics.append(m.get_metrics()) + metrics.extend(m.get_metrics()) return metrics def __repr__(self) -> str: diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 80840b87..62500b8d 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -5,7 +5,6 @@ class MetricsMix: """we want get the data metrics of one device""" def __init__(self, *args, **kwargs): - self.actions = copy.copy(device.actions) self.actions.sort(key=lambda x: x.created) self.rows = [] self.lifetime = 0 @@ -53,10 +52,11 @@ class Metrics(MetricsMix): """we want get the data metrics of one device""" def __init__(self, *args, **kwargs): - device = kwargs.pop('device') + self.device = kwargs.pop('device') + self.actions = copy.copy(self.device.actions) super().__init__(*args, **kwargs) - self.hid = device.hid - self.devicehub_id = device.devicehub_id + self.hid = self.device.hid + self.devicehub_id = self.device.devicehub_id def get_action_status(self): """ @@ -196,8 +196,46 @@ class TradeMetrics(MetricsMix): """we want get the data metrics of one device""" def __init__(self, *args, **kwargs): - document = kwargs.pop('document') - super().__init__(*args, **kwargs) - self.hid = document.hash + self.document = kwargs.pop('document') + self.actions = copy.copy(self.document.actions) + self.hid = self.document.file_hash self.devicehub_id = '' + super().__init__(*args, **kwargs) + def get_metrics(self): + self.last_trade = next(x for x in self.actions if x.t == 'Trade') + self.act = self.last_trade + row = self.get_template_row() + + row['type'] = 'Trade-Document' + row['action_type'] = 'Trade-Document' + if self.document.weight: + row['type'] = 'Trade-Container' + row['action_type'] = 'Trade-Document' + + row['document_name'] = self.document.file_name + row['trade_supplier'] = self.last_trade.user_from.email + row['trade_receiver'] = self.last_trade.user_to.email + row['trade_confirmed'] = self.get_confirms() + row['self.status_receiver'] = '' + row['self.status_supplier'] = '' + row['trade_weight'] = self.document.weight + if self.last_trade.author == self.last_trade.user_from: + row['action_create_by'] = 'Supplier' + elif self.last_trade.author == self.last_trade.user_to: + row['action_create_by'] = 'Receiver' + + self.rows.append(row) + + return self.rows + + def get_confirms(self): + """ + if the action is one trade action, is possible than have a list of confirmations. + Get the doble confirm for to know if this trade is confirmed or not. + """ + if hasattr(self.last_trade, 'acceptances'): + accept = self.last_trade.acceptances[-1] + if accept.t == 'Confirm' and accept.user == self.last_trade.user_to: + return True + return False diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index 36c93819..fe021c3d 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -414,6 +414,8 @@ def none2str(string): return '' return format(string) + + def get_action(component, action): """ Filter one action from a component or return None """ result = [a for a in component.actions if a.type == action] diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index 41606d0b..4e25c007 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -32,6 +32,8 @@ from ereuse_devicehub.resources.documents.device_row import (DeviceRow, StockRow InternalStatsRow) from ereuse_devicehub.resources.lot import LotView from ereuse_devicehub.resources.lot.models import Lot +from ereuse_devicehub.resources.action.models import Trade +from ereuse_devicehub.resources.device.models import Device from ereuse_devicehub.resources.hash_reports import insert_hash, ReportHash, verify_hash @@ -168,21 +170,16 @@ class ActionsDocumentView(DeviceView): cw.writerow(d.keys()) first = False cw.writerow(d.values()) - from ereuse_devicehub.resources.action.models import Trade - from ereuse_devicehub.resources.device.models import Device - # import pdb; pdb.set_trace() query_trade = Trade.query.filter(Trade.devices.any(Device.id.in_(devs_id))).all() - doc_metrics = [] for trade in query_trade: - doc_metrics.extend(trade.get_metrics()) - - for data_row in doc_metrics: - row = ActionRow(data_row) - if first: - cw.writerow(row.keys()) - first = False - cw.writerow(row.values()) + data_rows = trade.get_metrics() + for row in data_rows: + d = ActionRow(row) + if first: + cw.writerow(d.keys()) + first = False + cw.writerow(d.values()) bfile = data.getvalue().encode('utf-8') output = make_response(bfile) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 70c728d2..c8641e3f 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -3,6 +3,8 @@ import pytest from ereuse_devicehub.client import UserClient from ereuse_devicehub.resources.action import models as ma from ereuse_devicehub.resources.documents import documents +from ereuse_devicehub.resources.lot.models import Lot +from ereuse_devicehub.resources.tradedocument.models import TradeDocument from tests import conftest from tests.conftest import file, yaml2json, json_encode @@ -21,8 +23,7 @@ def test_simple_metrics(user: UserClient): "finalUserCode": "abcdefjhi", "devices": [device_id], "description": "aaa", "startTime": "2020-11-01T02:00:00+00:00", - "endTime": "2020-12-01T02:00:00+00:00" - } + "endTime": "2020-12-01T02:00:00+00:00"} # Create Allocate user.post(res=ma.Allocate, data=post_request) @@ -66,8 +67,7 @@ def test_second_hdd_metrics(user: UserClient): "finalUserCode": "abcdefjhi", "devices": [device_id], "description": "aaa", "startTime": "2020-11-01T02:00:00+00:00", - "endTime": "2020-12-01T02:00:00+00:00" - } + "endTime": "2020-12-01T02:00:00+00:00"} # Create Allocate user.post(res=ma.Allocate, data=post_request) @@ -110,8 +110,7 @@ def test_metrics_with_live_null(user: UserClient): "finalUserCode": "abcdefjhi", "devices": [device_id], "description": "aaa", "startTime": "2020-11-01T02:00:00+00:00", - "endTime": "2020-12-01T02:00:00+00:00" - } + "endTime": "2020-12-01T02:00:00+00:00"} # Create Allocate user.post(res=ma.Allocate, data=post_request) @@ -125,18 +124,16 @@ def test_metrics_with_live_null(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_metrics_action_status(user: UserClient, user2: UserClient): - """ Checks one standard query of metrics """ + """ Checks one standard query of metrics.""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') snap, _ = user.post(json_encode(lenovo), res=ma.Snapshot) action = {'type': ma.Use.t, 'devices': [snap['device']['id']]} action_use, _ = user.post(action, res=ma.Action) - # res, _ = user.get("/metrics/") csv_str, _ = user.get(res=documents.DocumentDef.t, item='actions/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - # import pdb; pdb.set_trace() head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Supplier;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' body = '93652;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Status;;foo@foo.com;Receiver;;;Use;;' assert head in csv_str @@ -145,8 +142,8 @@ def test_metrics_action_status(user: UserClient, user2: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) -def test_complet_metrics(user: UserClient, user2: UserClient): - """ Checks one standard query of metrics """ +def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): + """ Checks one standard query of metrics in a trade enviroment.""" # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') acer = yaml2json('acer.happy.battery.snapshot') @@ -154,28 +151,100 @@ def test_complet_metrics(user: UserClient, user2: UserClient): snap2, _ = user.post(json_encode(acer), res=ma.Snapshot) lot, _ = user.post({'name': 'MyLot'}, res=Lot) devices = [('id', snap1['device']['id']), - ('id', snap2['device']['id']) - ] + ('id', snap2['device']['id'])] lot, _ = user.post({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices) - # import pdb; pdb.set_trace() - # request_post = { - # 'type': 'Trade', - # 'devices': [span1['device']['id'], snap2['device']['id']], - # 'userFromEmail': user2.email, - # 'userToEmail': user.email, - # 'price': 10, - # 'date': "2020-12-01T02:00:00+00:00", - # 'lot': lot['id'], - # 'confirms': True, - # } + request_post = { + 'type': 'Trade', + 'devices': [snap1['device']['id'], snap2['device']['id']], + 'userFromEmail': user.email, + 'userToEmail': user2.email, + 'price': 10, + 'date': "2020-12-01T02:00:00+00:00", + 'lot': lot['id'], + 'confirms': True, + } - # user.post(res=models.Action, data=request_post) + user.post(res=ma.Action, data=request_post) - # ============================== - # Check metrics - metrics = {'allocateds': 1, 'live': 1} - res, _ = user.get("/metrics/") - assert res == metrics + action = {'type': ma.Refurbish.t, 'devices': [snap1['device']['id']]} + action_use, _ = user.post(action, res=ma.Action) + csv_str, _ = user.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + + body1_lenovo = '93652;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;Refurbish;Use;' + body2_lenovo = ';;0;0;Trade;0;0\n' + + body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;0;' + body2_acer = ';;0;0;Trade;0;4692.0\n' + + assert body1_lenovo in csv_str + assert body2_lenovo in csv_str + assert body1_acer in csv_str + assert body2_acer in csv_str + + # User2 mark this device as Refurbish + action = {'type': ma.Refurbish.t, 'devices': [snap1['device']['id']]} + action_use2, _ = user2.post(action, res=ma.Action) + csv_str, _ = user.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + + body2_lenovo = ';Refurbish;0;0;Trade;0;0\n' + body2_acer = ';Refurbish;0;0;Trade;0;4692.0\n' + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_metrics_action_status_for_containers(user: UserClient, user2: UserClient): + """ Checks one standard query of metrics for a container.""" + # Insert computer + lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') + snap, _ = user.post(json_encode(lenovo), res=ma.Snapshot) + lot, _ = user.post({'name': 'MyLot'}, res=Lot) + devices = [('id', snap['device']['id'])] + lot, _ = user.post({}, + res=Lot, + item='{}/devices'.format(lot['id']), + query=devices) + request_post = { + 'type': 'Trade', + 'devices': [snap['device']['id']], + 'userFromEmail': user.email, + 'userToEmail': user2.email, + 'price': 10, + 'date': "2020-12-01T02:00:00+00:00", + 'lot': lot['id'], + 'confirms': True, + } + + user.post(res=ma.Action, data=request_post) + + request_post = { + 'filename': 'test.pdf', + 'hash': 'bbbbbbbb', + 'url': 'http://www.ereuse.org/', + 'weight': 150, + 'lot': lot['id'] + } + tradedocument, _ = user.post(res=TradeDocument, data=request_post) + action = {'type': ma.Recycling.t, 'devices': [], 'documents': [tradedocument['id']]} + action, _ = user.post(action, res=ma.Action) + trade = TradeDocument.query.one() + + assert str(trade.actions[-1].id) == action['id'] + + csv_str, _ = user.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + + body1 = '\n;bbbbbbbb;test.pdf;Trade-Document;foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;150.0;' + body2 = ';;0;0;Trade-Container;0;0\n' + assert body1 in csv_str + assert body2 in csv_str From f099a579fbbb77d25875e0bd39346e932c205767 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 19 Oct 2021 19:25:17 +0200 Subject: [PATCH 06/48] fixing rows --- ereuse_devicehub/resources/device/metrics.py | 13 +++++++------ ereuse_devicehub/resources/documents/device_row.py | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 62500b8d..eaa72f04 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -38,7 +38,8 @@ class MetricsMix: 'numEndUsers': 0, 'liveCreate': 0, 'usageTimeHdd': self.lifetime, - 'start': self.act.created, + 'created': self.act.created, + 'start': '', 'usageTimeAllocate': 0} def get_metrics(self): @@ -211,14 +212,14 @@ class TradeMetrics(MetricsMix): row['action_type'] = 'Trade-Document' if self.document.weight: row['type'] = 'Trade-Container' - row['action_type'] = 'Trade-Document' + row['action_type'] = 'Trade-Container' row['document_name'] = self.document.file_name row['trade_supplier'] = self.last_trade.user_from.email row['trade_receiver'] = self.last_trade.user_to.email row['trade_confirmed'] = self.get_confirms() - row['self.status_receiver'] = '' - row['self.status_supplier'] = '' + row['status_receiver'] = '' + row['status_supplier'] = '' row['trade_weight'] = self.document.weight if self.last_trade.author == self.last_trade.user_from: row['action_create_by'] = 'Supplier' @@ -234,8 +235,8 @@ class TradeMetrics(MetricsMix): if the action is one trade action, is possible than have a list of confirmations. Get the doble confirm for to know if this trade is confirmed or not. """ - if hasattr(self.last_trade, 'acceptances'): - accept = self.last_trade.acceptances[-1] + if hasattr(self.last_trade, 'acceptances_document'): + accept = self.last_trade.acceptances_document[-1] if accept.t == 'Confirm' and accept.user == self.last_trade.user_to: return True return False diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index fe021c3d..de550d91 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -440,6 +440,7 @@ class ActionRow(OrderedDict): self['Status Supplier – Created Date'] = allocate['status_supplier_created'] self['Status Receiver – Created Date'] = allocate['status_receiver_created'] self['Trade-Weight'] = allocate['trade_weight'] + self['Action-Create'] = allocate['created'] self['Allocate-Start'] = allocate['start'] self['Allocate-User-Code'] = allocate['finalUserCode'] self['Allocate-NumUsers'] = allocate['numEndUsers'] From 7c6b20597b4787ff3d0f5e0f20c637949ee2d9d1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 20 Oct 2021 14:53:33 +0200 Subject: [PATCH 07/48] fixing supplier permitions --- .../resources/documents/documents.py | 20 +++---- tests/test_metrics.py | 59 +++++++++++++++++-- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/ereuse_devicehub/resources/documents/documents.py b/ereuse_devicehub/resources/documents/documents.py index 4e25c007..bb7a4834 100644 --- a/ereuse_devicehub/resources/documents/documents.py +++ b/ereuse_devicehub/resources/documents/documents.py @@ -3,11 +3,9 @@ import enum import uuid import time import datetime -import pathlib from collections import OrderedDict from io import StringIO from typing import Callable, Iterable, Tuple -from decouple import config import boltons import flask @@ -92,7 +90,6 @@ class DocumentView(DeviceView): res = flask.make_response(template) return res - @staticmethod def erasure(query: db.Query): def erasures(): @@ -153,7 +150,7 @@ class DevicesDocumentView(DeviceView): class ActionsDocumentView(DeviceView): @cache(datetime.timedelta(minutes=1)) def find(self, args: dict): - query = (x for x in self.query(args) if x.owner_id == g.user.id) + query = (x for x in self.query(args)) return self.generate_post_csv(query) def generate_post_csv(self, query): @@ -200,11 +197,11 @@ class LotsDocumentView(LotView): cw = csv.writer(data) first = True for lot in query: - l = LotRow(lot) + _lot = LotRow(lot) if first: - cw.writerow(l.keys()) + cw.writerow(_lot.keys()) first = False - cw.writerow(l.values()) + cw.writerow(_lot.values()) bfile = data.getvalue().encode('utf-8') output = make_response(bfile) insert_hash(bfile) @@ -290,7 +287,7 @@ class StampsView(View): ok = '100% coincidence. The attached file contains data 100% existing in \ to our backend' result = ('Bad', bad) - mime = ['text/csv', 'application/pdf', 'text/plain','text/markdown', + mime = ['text/csv', 'application/pdf', 'text/plain', 'text/markdown', 'image/jpeg', 'image/png', 'text/html', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.oasis.opendocument.spreadsheet', @@ -319,9 +316,9 @@ class InternalStatsView(DeviceView): create = '{}-{}'.format(ac.created.year, ac.created.month) user = ac.author.email - if not user in d: - d[user] = {} - if not create in d[user]: + if user not in d: + d[user] = {} + if create not in d[user]: d[user][create] = [] d[user][create].append(ac) @@ -449,4 +446,3 @@ class DocumentDef(Resource): auth=app.auth) wbconf_view = app.auth.requires_auth(wbconf_view) self.add_url_rule('/wbconf/', view_func=wbconf_view, methods=get) - diff --git a/tests/test_metrics.py b/tests/test_metrics.py index c8641e3f..afeeba8b 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -134,7 +134,7 @@ def test_metrics_action_status(user: UserClient, user2: UserClient): item='actions/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Supplier;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' + head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Supplier;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Action-Create;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' body = '93652;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Status;;foo@foo.com;Receiver;;;Use;;' assert head in csv_str assert body in csv_str @@ -244,7 +244,56 @@ def test_metrics_action_status_for_containers(user: UserClient, user2: UserClien accept='text/csv', query=[('filter', {'type': ['Computer']})]) - body1 = '\n;bbbbbbbb;test.pdf;Trade-Document;foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;150.0;' - body2 = ';;0;0;Trade-Container;0;0\n' - assert body1 in csv_str - assert body2 in csv_str + body1 = ';bbbbbbbb;test.pdf;Trade-Container;foo@foo.com;foo2@foo.com;Supplier;False;;;;;150.0;' + body2 = ';;0;0;Trade-Container;0;0' + assert len(csv_str.split('\n')) == 4 + assert body1 in csv_str.split('\n')[-2] + assert body2 in csv_str.split('\n')[-2] + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_visual_metrics_for_old_owners(user: UserClient, user2: UserClient): + """ Checks if one old owner can see the metrics in a trade enviroment.""" + # Insert computer + lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') + snap1, _ = user.post(json_encode(lenovo), res=ma.Snapshot) + lot, _ = user.post({'name': 'MyLot'}, res=Lot) + devices = [('id', snap1['device']['id'])] + lot, _ = user.post({}, + res=Lot, + item='{}/devices'.format(lot['id']), + query=devices) + request_post = { + 'type': 'Trade', + 'devices': [snap1['device']['id']], + 'userFromEmail': user.email, + 'userToEmail': user2.email, + 'price': 10, + 'date': "2020-12-01T02:00:00+00:00", + 'lot': lot['id'], + 'confirms': True, + } + trade, _ = user.post(res=ma.Action, data=request_post) + + request_confirm = { + 'type': 'Confirm', + 'action': trade['id'], + 'devices': [snap1['device']['id']] + } + user2.post(res=ma.Action, data=request_confirm) + + action = {'type': ma.Refurbish.t, 'devices': [snap1['device']['id']]} + action_use, _ = user.post(action, res=ma.Action) + csv_supplier, _ = user.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + csv_receiver, _ = user2.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + body = ';;0;0;Trade;0;0\n' + + assert body in csv_receiver + assert body in csv_supplier From 2ade5a14d4ded3e7ae127743f15397f7d87071c0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 22 Oct 2021 14:19:42 +0200 Subject: [PATCH 08/48] adding tag when there are a new device --- ereuse_devicehub/resources/device/models.py | 60 +++++++++++---------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 2322326a..38552e9a 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -9,9 +9,7 @@ from typing import Dict, List, Set from boltons import urlutils from citext import CIText -from flask_sqlalchemy import event from ereuse_utils.naming import HID_CONVERSION_DOC, Naming -from flask import g from more_itertools import unique_everseen from sqlalchemy import BigInteger, Boolean, Column, Enum as DBEnum, Float, ForeignKey, Integer, \ Sequence, SmallInteger, Unicode, inspect, text @@ -41,7 +39,12 @@ def create_code(context): _id = Device.query.order_by(Device.id.desc()).first() or 1 if not _id == 1: _id = _id.id + 1 - return hashcode.encode(_id) + code = hashcode.encode(_id) + + from ereuse_devicehub.resources.tag.model import Tag + tag = Tag(device_id=_id, id=code) + db.session.add(tag) + return code class Device(Thing): @@ -231,7 +234,7 @@ class Device(Thing): :return a list of actions: """ hide_actions = ['Price', 'EreusePrice'] - actions = [ac for ac in self.actions if not ac.t in hide_actions] + actions = [ac for ac in self.actions if ac.t not in hide_actions] actions.reverse() return actions @@ -288,7 +291,7 @@ class Device(Thing): status_actions = [ac.t for ac in states.Status.actions()] history = [] for ac in self.actions: - if not ac.t in status_actions: + if ac.t not in status_actions: continue if not history: history.append(ac) @@ -318,27 +321,27 @@ class Device(Thing): # return the correct status of trade depending of the user - ##### CASES ##### - ## User1 == owner of trade (This user have automatic Confirmation) - ## ======================= - ## if the last action is => only allow to do - ## ========================================== - ## Confirmation not User1 => Revoke - ## Confirmation User1 => Revoke - ## Revoke not User1 => ConfirmRevoke - ## Revoke User1 => RevokePending - ## RevokeConfirmation => RevokeConfirmed - ## - ## - ## User2 == Not owner of trade - ## ======================= - ## if the last action is => only allow to do - ## ========================================== - ## Confirmation not User2 => Confirm - ## Confirmation User2 => Revoke - ## Revoke not User2 => ConfirmRevoke - ## Revoke User2 => RevokePending - ## RevokeConfirmation => RevokeConfirmed + # #### CASES ##### + # User1 == owner of trade (This user have automatic Confirmation) + # ======================= + # if the last action is => only allow to do + # ========================================== + # Confirmation not User1 => Revoke + # Confirmation User1 => Revoke + # Revoke not User1 => ConfirmRevoke + # Revoke User1 => RevokePending + # RevokeConfirmation => RevokeConfirmed + # + # + # User2 == Not owner of trade + # ======================= + # if the last action is => only allow to do + # ========================================== + # Confirmation not User2 => Confirm + # Confirmation User2 => Revoke + # Revoke not User2 => ConfirmRevoke + # Revoke User2 => RevokePending + # RevokeConfirmation => RevokeConfirmed ac = self.last_action_trading if not ac: @@ -427,8 +430,8 @@ class Device(Thing): # 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 + # action = self.last_action_of(Receive) + # return action.agent_to @property def working(self): @@ -1166,4 +1169,3 @@ class Manufacturer(db.Model): listener_reset_field_updated_in_actual_time(Device) - From 6091f31c17cec694ced7921fc3081061d576af3a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 22 Oct 2021 19:26:27 +0200 Subject: [PATCH 09/48] adding event instead of reuse create_code function --- ereuse_devicehub/resources/device/models.py | 25 ++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 38552e9a..ebf1d858 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -36,14 +36,15 @@ from ereuse_devicehub.resources.device.metrics import Metrics def create_code(context): - _id = Device.query.order_by(Device.id.desc()).first() or 1 - if not _id == 1: + # import pdb; pdb.set_trace() + _id = Device.query.order_by(Device.id.desc()).first() or 3 + if not _id == 3: _id = _id.id + 1 code = hashcode.encode(_id) - from ereuse_devicehub.resources.tag.model import Tag - tag = Tag(device_id=_id, id=code) - db.session.add(tag) + # from ereuse_devicehub.resources.tag.model import Tag + # tag = Tag(device_id=_id, id=code) + # db.session.add(tag) return code @@ -1169,3 +1170,17 @@ class Manufacturer(db.Model): listener_reset_field_updated_in_actual_time(Device) + + +def create_code_tag(mapper, connection, device): + """ + This function create a new tag every time than one device is create. + this tag is the same of devicehub_id. + """ + from ereuse_devicehub.resources.tag.model import Tag + tag = Tag(device_id=device.id, id=device.devicehub_id) + db.session.add(tag) + + +from flask_sqlalchemy import event +event.listen(Device, 'after_update', create_code_tag, propagate=True) From 9faa1697a71ea593e7f0ae3037be1ef6dc6fd976 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 22 Oct 2021 21:14:10 +0200 Subject: [PATCH 10/48] fixing event device --- ereuse_devicehub/resources/device/models.py | 10 ++-------- tests/test_action.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index ebf1d858..187dfb9c 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -36,16 +36,10 @@ from ereuse_devicehub.resources.device.metrics import Metrics def create_code(context): - # import pdb; pdb.set_trace() _id = Device.query.order_by(Device.id.desc()).first() or 3 if not _id == 3: _id = _id.id + 1 - code = hashcode.encode(_id) - - # from ereuse_devicehub.resources.tag.model import Tag - # tag = Tag(device_id=_id, id=code) - # db.session.add(tag) - return code + return hashcode.encode(_id) class Device(Thing): @@ -1183,4 +1177,4 @@ def create_code_tag(mapper, connection, device): from flask_sqlalchemy import event -event.listen(Device, 'after_update', create_code_tag, propagate=True) +event.listen(Device, 'after_insert', create_code_tag, propagate=True) diff --git a/tests/test_action.py b/tests/test_action.py index 825bdb0a..888541f3 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -260,10 +260,10 @@ def test_generic_action(action_model_state: Tuple[models.Action, states.Trading] @pytest.mark.parametrize('action_model', (pytest.param(ams, id=ams.__class__.__name__) for ams in [ - models.Recycling, - models.Use, - models.Refurbish, - models.Management + models.Recycling, + models.Use, + models.Refurbish, + models.Management ])) def test_simple_status_actions(action_model: models.Action, user: UserClient, user2: UserClient): """Simple test of status action.""" @@ -281,10 +281,10 @@ def test_simple_status_actions(action_model: models.Action, user: UserClient, us @pytest.mark.parametrize('action_model', (pytest.param(ams, id=ams.__class__.__name__) for ams in [ - models.Recycling, - models.Use, - models.Refurbish, - models.Management + models.Recycling, + models.Use, + models.Refurbish, + models.Management ])) def test_outgoinlot_status_actions(action_model: models.Action, user: UserClient, user2: UserClient): """Test of status actions in outgoinlot.""" From 1bfb80de520b2621b66b7d76281b5ae86c34d41c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 22 Oct 2021 22:34:32 +0200 Subject: [PATCH 11/48] fixing tests --- tests/test_device.py | 17 ++++++++++++----- tests/test_device_find.py | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/test_device.py b/tests/test_device.py index 9dcfd53f..4f366c51 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -309,9 +309,10 @@ def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str): # they are not the same tags though # tag is a transient obj and db_tag the one from the db # they have the same pk though - assert tag != db_tag, 'They are not the same tags though' - assert db_tag.id == tag.id assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db' + assert tag != db_tag, 'They are not the same tags though' + for tag in pc.tags: + assert tag.id in ['foo', pc.devicehub_id] @pytest.mark.mvp @@ -346,8 +347,10 @@ def test_sync_execute_register_tag_linked_same_device(): pc.tags.add(Tag(id='foo')) db_pc = Sync().execute_register(pc) assert db_pc.id == orig_pc.id - assert len(db_pc.tags) == 1 - assert next(iter(db_pc.tags)).id == 'foo' + assert len(db_pc.tags) == 2 + # import pdb; pdb.set_trace() + for tag in db_pc.tags: + assert tag.id in ['foo', db_pc.devicehub_id] @pytest.mark.mvp @@ -399,13 +402,14 @@ def test_sync_execute_register_mismatch_between_tags_and_hid(): @pytest.mark.usefixtures(conftest.app_context.__name__) def test_get_device(user: UserClient): """Checks GETting a d.Desktop with its components.""" + g.user = User.query.one() pc = d.Desktop(model='p1mo', manufacturer='p1ma', serial_number='p1s', chassis=ComputerChassis.Tower, owner_id=user.user['id']) pc.components = OrderedSet([ - d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', + d.NetworkAdapter(model='c1mo', manufacturer='c1ma', serial_number='c1s', owner_id=user.user['id']), d.GraphicCard(model='c2mo', manufacturer='c2ma', memory=1500, owner_id=user.user['id']) ]) @@ -437,6 +441,7 @@ def test_get_device(user: UserClient): @pytest.mark.usefixtures(conftest.app_context.__name__) def test_get_devices(app: Devicehub, user: UserClient): """Checks GETting multiple devices.""" + g.user = User.query.one() pc = d.Desktop(model='p1mo', manufacturer='p1ma', serial_number='p1s', @@ -604,6 +609,7 @@ def test_device_public(user: UserClient, client: Client): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_computer_accessory_model(user: UserClient): + g.user = User.query.one() sai = d.SAI(owner_id=user.user['id']) db.session.add(sai) keyboard = d.Keyboard(layout=Layouts.ES, owner_id=user.user['id']) @@ -616,6 +622,7 @@ def test_computer_accessory_model(user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_networking_model(user: UserClient): + g.user = User.query.one() router = d.Router(speed=1000, wireless=True, owner_id=user.user['id']) db.session.add(router) switch = d.Switch(speed=1000, wireless=False, owner_id=user.user['id']) diff --git a/tests/test_device_find.py b/tests/test_device_find.py index 306dae32..7407f3f8 100644 --- a/tests/test_device_find.py +++ b/tests/test_device_find.py @@ -183,7 +183,7 @@ def test_device_query(user: UserClient): pc = next(d for d in i['items'] if d['type'] == 'Desktop') assert len(pc['actions']) == 4 assert len(pc['components']) == 3 - assert not pc['tags'] + assert pc['tags'][0]['id'] == pc['devicehubID'] @pytest.mark.mvp @@ -201,10 +201,10 @@ def test_device_query_permitions(user: UserClient, user2: UserClient): user2.post(json_encode(basic_snapshot), res=Snapshot) i2, _ = user2.get(res=Device) pc2 = next(d for d in i2['items'] if d['type'] == 'Desktop') - + assert pc1['id'] != pc2['id'] assert pc1['hid'] == pc2['hid'] - + @pytest.mark.mvp def test_device_search_all_devices_token_if_empty(app: Devicehub, user: UserClient): From 1c2f6ba92c7bc7053aec5435941995955f776ea4 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 23 Oct 2021 13:02:10 +0200 Subject: [PATCH 12/48] fixing tests --- ereuse_devicehub/resources/device/models.py | 2 +- tests/files/basic.csv | 2 +- tests/files/proposal_extended_csv_report.csv | 4 ++-- tests/test_documents.py | 9 +++------ tests/test_lot.py | 3 +++ tests/test_metrics.py | 4 ++-- tests/test_snapshot.py | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 187dfb9c..473ca640 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -6,6 +6,7 @@ from fractions import Fraction from itertools import chain from operator import attrgetter from typing import Dict, List, Set +from flask_sqlalchemy import event from boltons import urlutils from citext import CIText @@ -1176,5 +1177,4 @@ def create_code_tag(mapper, connection, device): db.session.add(tag) -from flask_sqlalchemy import event event.listen(Device, 'after_insert', create_code_tag, propagate=True) diff --git a/tests/files/basic.csv b/tests/files/basic.csv index 45750ae9..253838e9 100644 --- a/tests/files/basic.csv +++ b/tests/files/basic.csv @@ -1,2 +1,2 @@ DHID;DocumentID;Public Link;Lots;Tag 1 Type;Tag 1 ID;Tag 1 Organization;Tag 2 Type;Tag 2 ID;Tag 2 Organization;Tag 3 Type;Tag 3 ID;Tag 3 Organization;Device Hardware ID;Device Type;Device Chassis;Device Serial Number;Device Model;Device Manufacturer;Registered in;Registered (process);Updated in (software);Updated in (web);Physical state;Trading state;Processor;RAM (MB);Data Storage Size (MB);Processor 1;Processor 1 Manufacturer;Processor 1 Model;Processor 1 Serial Number;Processor 1 Number of cores;Processor 1 Speed (GHz);Benchmark Processor 1 (points);Benchmark ProcessorSysbench Processor 1 (points);Processor 2;Processor 2 Manufacturer;Processor 2 Model;Processor 2 Serial Number;Processor 2 Number of cores;Processor 2 Speed (GHz);Benchmark Processor 2 (points);Benchmark ProcessorSysbench Processor 2 (points);RamModule 1;RamModule 1 Manufacturer;RamModule 1 Model;RamModule 1 Serial Number;RamModule 1 Size (MB);RamModule 1 Speed (MHz);RamModule 2;RamModule 2 Manufacturer;RamModule 2 Model;RamModule 2 Serial Number;RamModule 2 Size (MB);RamModule 2 Speed (MHz);RamModule 3;RamModule 3 Manufacturer;RamModule 3 Model;RamModule 3 Serial Number;RamModule 3 Size (MB);RamModule 3 Speed (MHz);RamModule 4;RamModule 4 Manufacturer;RamModule 4 Model;RamModule 4 Serial Number;RamModule 4 Size (MB);RamModule 4 Speed (MHz);DataStorage 1;DataStorage 1 Manufacturer;DataStorage 1 Model;DataStorage 1 Serial Number;DataStorage 1 Size (MB);Erasure DataStorage 1;Erasure DataStorage 1 Serial Number;Erasure DataStorage 1 Size (MB);Erasure DataStorage 1 Software;Erasure DataStorage 1 Result;Erasure DataStorage 1 Certificate URL;Erasure DataStorage 1 Type;Erasure DataStorage 1 Method;Erasure DataStorage 1 Elapsed (hours);Erasure DataStorage 1 Date;Erasure DataStorage 1 Steps;Erasure DataStorage 1 Steps Start Time;Erasure DataStorage 1 Steps End Time;Benchmark DataStorage 1 Read Speed (MB/s);Benchmark DataStorage 1 Writing speed (MB/s);Test DataStorage 1 Software;Test DataStorage 1 Type;Test DataStorage 1 Result;Test DataStorage 1 Power on (hours used);Test DataStorage 1 Lifetime remaining (percentage);DataStorage 2;DataStorage 2 Manufacturer;DataStorage 2 Model;DataStorage 2 Serial Number;DataStorage 2 Size (MB);Erasure DataStorage 2;Erasure DataStorage 2 Serial Number;Erasure DataStorage 2 Size (MB);Erasure DataStorage 2 Software;Erasure DataStorage 2 Result;Erasure DataStorage 2 Certificate URL;Erasure DataStorage 2 Type;Erasure DataStorage 2 Method;Erasure DataStorage 2 Elapsed (hours);Erasure DataStorage 2 Date;Erasure DataStorage 2 Steps;Erasure DataStorage 2 Steps Start Time;Erasure DataStorage 2 Steps End Time;Benchmark DataStorage 2 Read Speed (MB/s);Benchmark DataStorage 2 Writing speed (MB/s);Test DataStorage 2 Software;Test DataStorage 2 Type;Test DataStorage 2 Result;Test DataStorage 2 Power on (hours used);Test DataStorage 2 Lifetime remaining (percentage);DataStorage 3;DataStorage 3 Manufacturer;DataStorage 3 Model;DataStorage 3 Serial Number;DataStorage 3 Size (MB);Erasure DataStorage 3;Erasure DataStorage 3 Serial Number;Erasure DataStorage 3 Size (MB);Erasure DataStorage 3 Software;Erasure DataStorage 3 Result;Erasure DataStorage 3 Certificate URL;Erasure DataStorage 3 Type;Erasure DataStorage 3 Method;Erasure DataStorage 3 Elapsed (hours);Erasure DataStorage 3 Date;Erasure DataStorage 3 Steps;Erasure DataStorage 3 Steps Start Time;Erasure DataStorage 3 Steps End Time;Benchmark DataStorage 3 Read Speed (MB/s);Benchmark DataStorage 3 Writing speed (MB/s);Test DataStorage 3 Software;Test DataStorage 3 Type;Test DataStorage 3 Result;Test DataStorage 3 Power on (hours used);Test DataStorage 3 Lifetime remaining (percentage);DataStorage 4;DataStorage 4 Manufacturer;DataStorage 4 Model;DataStorage 4 Serial Number;DataStorage 4 Size (MB);Erasure DataStorage 4;Erasure DataStorage 4 Serial Number;Erasure DataStorage 4 Size (MB);Erasure DataStorage 4 Software;Erasure DataStorage 4 Result;Erasure DataStorage 4 Certificate URL;Erasure DataStorage 4 Type;Erasure DataStorage 4 Method;Erasure DataStorage 4 Elapsed (hours);Erasure DataStorage 4 Date;Erasure DataStorage 4 Steps;Erasure DataStorage 4 Steps Start Time;Erasure DataStorage 4 Steps End Time;Benchmark DataStorage 4 Read Speed (MB/s);Benchmark DataStorage 4 Writing speed (MB/s);Test DataStorage 4 Software;Test DataStorage 4 Type;Test DataStorage 4 Result;Test DataStorage 4 Power on (hours used);Test DataStorage 4 Lifetime remaining (percentage);Motherboard 1;Motherboard 1 Manufacturer;Motherboard 1 Model;Motherboard 1 Serial Number;Display 1;Display 1 Manufacturer;Display 1 Model;Display 1 Serial Number;GraphicCard 1;GraphicCard 1 Manufacturer;GraphicCard 1 Model;GraphicCard 1 Serial Number;GraphicCard 1 Memory (MB);GraphicCard 2;GraphicCard 2 Manufacturer;GraphicCard 2 Model;GraphicCard 2 Serial Number;GraphicCard 2 Memory (MB);NetworkAdapter 1;NetworkAdapter 1 Manufacturer;NetworkAdapter 1 Model;NetworkAdapter 1 Serial Number;NetworkAdapter 2;NetworkAdapter 2 Manufacturer;NetworkAdapter 2 Model;NetworkAdapter 2 Serial Number;SoundCard 1;SoundCard 1 Manufacturer;SoundCard 1 Model;SoundCard 1 Serial Number;SoundCard 2;SoundCard 2 Manufacturer;SoundCard 2 Model;SoundCard 2 Serial Number;Device Rate;Device Range;Processor Rate;Processor Range;RAM Rate;RAM Range;Data Storage Rate;Data Storage Range;Price;Benchmark RamSysbench (points) -93652;;http://localhost/devices/93652;;;;;;;;;;;desktop-d1mr-d1ml-d1s;Desktop;Microtower;d1s;d1ml;d1mr;Mon Aug 2 10:25:31 2021;Workbench 11.0;2021-08-02 10:25:31.457986+02:00;;;;p1ml;0;0;Processor 6: model p1ml, S/N p1s;p1mr;p1ml;p1s;;1.6;2410.0;;;;;;;;;;RamModule 5: model rm1ml, S/N rm1s;rm1mr;rm1ml;rm1s;;1333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GraphicCard 4: model gc1ml, S/N gc1s;gc1mr;gc1ml;gc1s;;;;;;;;;;;;;;;;;;;;;;;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;; +O48N2;;http://localhost/devices/O48N2;;named;O48N2;FooOrg;;;;;;;desktop-d1mr-d1ml-d1s;Desktop;Microtower;d1s;d1ml;d1mr;Mon Aug 2 10:25:31 2021;Workbench 11.0;2021-08-02 10:25:31.457986+02:00;;;;p1ml;0;0;Processor 6: model p1ml, S/N p1s;p1mr;p1ml;p1s;;1.6;2410.0;;;;;;;;;;RamModule 5: model rm1ml, S/N rm1s;rm1mr;rm1ml;rm1s;;1333;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GraphicCard 4: model gc1ml, S/N gc1s;gc1mr;gc1ml;gc1s;;;;;;;;;;;;;;;;;;;;;;;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;1.0;VERY_LOW;; diff --git a/tests/files/proposal_extended_csv_report.csv b/tests/files/proposal_extended_csv_report.csv index 2aacace8..67f8bf27 100644 --- a/tests/files/proposal_extended_csv_report.csv +++ b/tests/files/proposal_extended_csv_report.csv @@ -1,3 +1,3 @@ DHID;DocumentID;Public Link;Lots;Tag 1 Type;Tag 1 ID;Tag 1 Organization;Tag 2 Type;Tag 2 ID;Tag 2 Organization;Tag 3 Type;Tag 3 ID;Tag 3 Organization;Device Hardware ID;Device Type;Device Chassis;Device Serial Number;Device Model;Device Manufacturer;Registered in;Registered (process);Updated in (software);Updated in (web);Physical state;Trading state;Processor;RAM (MB);Data Storage Size (MB);Processor 1;Processor 1 Manufacturer;Processor 1 Model;Processor 1 Serial Number;Processor 1 Number of cores;Processor 1 Speed (GHz);Benchmark Processor 1 (points);Benchmark ProcessorSysbench Processor 1 (points);Processor 2;Processor 2 Manufacturer;Processor 2 Model;Processor 2 Serial Number;Processor 2 Number of cores;Processor 2 Speed (GHz);Benchmark Processor 2 (points);Benchmark ProcessorSysbench Processor 2 (points);RamModule 1;RamModule 1 Manufacturer;RamModule 1 Model;RamModule 1 Serial Number;RamModule 1 Size (MB);RamModule 1 Speed (MHz);RamModule 2;RamModule 2 Manufacturer;RamModule 2 Model;RamModule 2 Serial Number;RamModule 2 Size (MB);RamModule 2 Speed (MHz);RamModule 3;RamModule 3 Manufacturer;RamModule 3 Model;RamModule 3 Serial Number;RamModule 3 Size (MB);RamModule 3 Speed (MHz);RamModule 4;RamModule 4 Manufacturer;RamModule 4 Model;RamModule 4 Serial Number;RamModule 4 Size (MB);RamModule 4 Speed (MHz);DataStorage 1;DataStorage 1 Manufacturer;DataStorage 1 Model;DataStorage 1 Serial Number;DataStorage 1 Size (MB);Erasure DataStorage 1;Erasure DataStorage 1 Serial Number;Erasure DataStorage 1 Size (MB);Erasure DataStorage 1 Software;Erasure DataStorage 1 Result;Erasure DataStorage 1 Certificate URL;Erasure DataStorage 1 Type;Erasure DataStorage 1 Method;Erasure DataStorage 1 Elapsed (hours);Erasure DataStorage 1 Date;Erasure DataStorage 1 Steps;Erasure DataStorage 1 Steps Start Time;Erasure DataStorage 1 Steps End Time;Benchmark DataStorage 1 Read Speed (MB/s);Benchmark DataStorage 1 Writing speed (MB/s);Test DataStorage 1 Software;Test DataStorage 1 Type;Test DataStorage 1 Result;Test DataStorage 1 Power on (hours used);Test DataStorage 1 Lifetime remaining (percentage);DataStorage 2;DataStorage 2 Manufacturer;DataStorage 2 Model;DataStorage 2 Serial Number;DataStorage 2 Size (MB);Erasure DataStorage 2;Erasure DataStorage 2 Serial Number;Erasure DataStorage 2 Size (MB);Erasure DataStorage 2 Software;Erasure DataStorage 2 Result;Erasure DataStorage 2 Certificate URL;Erasure DataStorage 2 Type;Erasure DataStorage 2 Method;Erasure DataStorage 2 Elapsed (hours);Erasure DataStorage 2 Date;Erasure DataStorage 2 Steps;Erasure DataStorage 2 Steps Start Time;Erasure DataStorage 2 Steps End Time;Benchmark DataStorage 2 Read Speed (MB/s);Benchmark DataStorage 2 Writing speed (MB/s);Test DataStorage 2 Software;Test DataStorage 2 Type;Test DataStorage 2 Result;Test DataStorage 2 Power on (hours used);Test DataStorage 2 Lifetime remaining (percentage);DataStorage 3;DataStorage 3 Manufacturer;DataStorage 3 Model;DataStorage 3 Serial Number;DataStorage 3 Size (MB);Erasure DataStorage 3;Erasure DataStorage 3 Serial Number;Erasure DataStorage 3 Size (MB);Erasure DataStorage 3 Software;Erasure DataStorage 3 Result;Erasure DataStorage 3 Certificate URL;Erasure DataStorage 3 Type;Erasure DataStorage 3 Method;Erasure DataStorage 3 Elapsed (hours);Erasure DataStorage 3 Date;Erasure DataStorage 3 Steps;Erasure DataStorage 3 Steps Start Time;Erasure DataStorage 3 Steps End Time;Benchmark DataStorage 3 Read Speed (MB/s);Benchmark DataStorage 3 Writing speed (MB/s);Test DataStorage 3 Software;Test DataStorage 3 Type;Test DataStorage 3 Result;Test DataStorage 3 Power on (hours used);Test DataStorage 3 Lifetime remaining (percentage);DataStorage 4;DataStorage 4 Manufacturer;DataStorage 4 Model;DataStorage 4 Serial Number;DataStorage 4 Size (MB);Erasure DataStorage 4;Erasure DataStorage 4 Serial Number;Erasure DataStorage 4 Size (MB);Erasure DataStorage 4 Software;Erasure DataStorage 4 Result;Erasure DataStorage 4 Certificate URL;Erasure DataStorage 4 Type;Erasure DataStorage 4 Method;Erasure DataStorage 4 Elapsed (hours);Erasure DataStorage 4 Date;Erasure DataStorage 4 Steps;Erasure DataStorage 4 Steps Start Time;Erasure DataStorage 4 Steps End Time;Benchmark DataStorage 4 Read Speed (MB/s);Benchmark DataStorage 4 Writing speed (MB/s);Test DataStorage 4 Software;Test DataStorage 4 Type;Test DataStorage 4 Result;Test DataStorage 4 Power on (hours used);Test DataStorage 4 Lifetime remaining (percentage);Motherboard 1;Motherboard 1 Manufacturer;Motherboard 1 Model;Motherboard 1 Serial Number;Display 1;Display 1 Manufacturer;Display 1 Model;Display 1 Serial Number;GraphicCard 1;GraphicCard 1 Manufacturer;GraphicCard 1 Model;GraphicCard 1 Serial Number;GraphicCard 1 Memory (MB);GraphicCard 2;GraphicCard 2 Manufacturer;GraphicCard 2 Model;GraphicCard 2 Serial Number;GraphicCard 2 Memory (MB);NetworkAdapter 1;NetworkAdapter 1 Manufacturer;NetworkAdapter 1 Model;NetworkAdapter 1 Serial Number;NetworkAdapter 2;NetworkAdapter 2 Manufacturer;NetworkAdapter 2 Model;NetworkAdapter 2 Serial Number;SoundCard 1;SoundCard 1 Manufacturer;SoundCard 1 Model;SoundCard 1 Serial Number;SoundCard 2;SoundCard 2 Manufacturer;SoundCard 2 Model;SoundCard 2 Serial Number;Device Rate;Device Range;Processor Rate;Processor Range;RAM Rate;RAM Range;Data Storage Rate;Data Storage Range;Price;Benchmark RamSysbench (points) -93652;;http://localhost/devices/93652;;named;foo;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b;Laptop;Netbook;b8oaas048285;1001pxd;asustek computer inc.;Mon Aug 2 10:27:27 2021;Workbench 11.0a2;2021-08-02 10:27:27.772331+02:00;;;;intel atom cpu n455 @ 2.66ghz;1024;238475;Processor 6: model intel atom cpu n455 @ 2.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 2.66ghz;;1;2.667;6666.24;164.0803;;;;;;;;;RamModule 10: model None, S/N None;;;;1024;667;;;;;;;;;;;;;;;;;;;HardDrive 11: model hts54322, S/N e2024242cv86mm;hitachi;hts54322;e2024242cv86mm;238475;harddrive-hitachi-hts54322-e2024242cv86mm;e2024242cv86mm;238475;Workbench 11.0a2;Success;;EraseBasic;Shred;1:16:49;2021-08-02 10:27:27.163611+02:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0a2;Short;Failure;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 12: model 1001pxd, S/N eee0123456720;asustek computer inc.;1001pxd;eee0123456720;;;;;GraphicCard 7: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 4: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c9;NetworkAdapter 5: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7b;SoundCard 8: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;;;;;1.75;LOW;1.55;LOW;1.53;LOW;3.76;HIGH;52.50 €;15.7188 -J2MA2;;http://localhost/devices/J2MA2;;;;;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c;Laptop;Netbook;b8oaas048287;1001pxd;asustek computer inc.;Mon Aug 2 10:27:27 2021;Workbench 11.0b11;2021-08-02 10:27:27.528832+02:00;;;;intel atom cpu n455 @ 1.66ghz;2048;558558;Processor 17: model intel atom cpu n455 @ 1.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 1.66ghz;;1;1.667;6666.24;164.0803;;;;;;;;;RamModule 20: model None, S/N None;;;;1024;667;RamModule 21: model 48594d503131325336344350362d53362020, S/N 4f43487b;hynix semiconductor;48594d503131325336344350362d53362020;4f43487b;1024;667;;;;;;;;;;;;;HardDrive 22: model hts54322, S/N e2024242cv86hj;hitachi;hts54322;e2024242cv86hj;238475;harddrive-hitachi-hts54322-e2024242cv86hj;e2024242cv86hj;238475;Workbench 11.0b11;Success;;EraseBasic;Shred;1:16:49;2021-08-02 10:27:27.458348+02:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0b11;Extended;Failure;;;DataStorage 23: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160041;datastorage-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160041;Workbench 11.0b11;Failure;;EraseBasic;Shred;0:45:36;2021-08-02 10:27:27.460573+02:00;✓ – StepRandom 0:45:36;2019-10-23 09:49:54.410830+02:00;2019-10-23 10:35:31.400587+02:00;41.6;17.3;Workbench 11.0b11;Short;Success;5293;195 days, 12:00:00;SolidStateDrive 24: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160042;solidstatedrive-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160042;Workbench 11.0b11;Success;;EraseSectors;Badblocks;1:46:03;2021-08-02 10:27:27.464663+02:00;✓ – StepRandom 0:46:03,✓ – StepZero 1:00:00;2019-08-19 18:48:19.690458+02:00,2019-08-19 19:34:22.690458+02:00;2019-08-19 19:34:22.930562+02:00,2019-08-19 20:34:22.930562+02:00;41.1;17.1;Workbench 11.0b11;Short;Success;5231;194 days, 17:00:00;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 25: model 1001pxd, S/N eee0123456789;asustek computer inc.;1001pxd;eee0123456789;;"auo ""auo""";auo lcd monitor;;GraphicCard 18: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 15: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c8;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c8;NetworkAdapter 16: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7c;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7c;SoundCard 9: model usb 2.0 uvc vga webcam, S/N 0x0001;azurewave;usb 2.0 uvc vga webcam;0x0001;SoundCard 19: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;1.72;LOW;1.31;LOW;1.99;LOW;3.97;HIGH;51.60 €;15.7188 +O48N2;;http://localhost/devices/O48N2;;named;O48N2;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048285-14:da:e9:42:f6:7b;Laptop;Netbook;b8oaas048285;1001pxd;asustek computer inc.;Mon Aug 2 10:27:27 2021;Workbench 11.0a2;2021-08-02 10:27:27.772331+02:00;;;;intel atom cpu n455 @ 2.66ghz;1024;238475;Processor 6: model intel atom cpu n455 @ 2.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 2.66ghz;;1;2.667;6666.24;164.0803;;;;;;;;;RamModule 10: model None, S/N None;;;;1024;667;;;;;;;;;;;;;;;;;;;HardDrive 11: model hts54322, S/N e2024242cv86mm;hitachi;hts54322;e2024242cv86mm;238475;harddrive-hitachi-hts54322-e2024242cv86mm;e2024242cv86mm;238475;Workbench 11.0a2;Success;;EraseBasic;Shred;1:16:49;2021-08-02 10:27:27.163611+02:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0a2;Short;Failure;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 12: model 1001pxd, S/N eee0123456720;asustek computer inc.;1001pxd;eee0123456720;;;;;GraphicCard 7: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 4: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c9;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c9;NetworkAdapter 5: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7b;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7b;SoundCard 8: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;;;;;1.75;LOW;1.55;LOW;1.53;LOW;3.76;HIGH;52.50 €;15.7188 +J2MA2;;http://localhost/devices/J2MA2;;named;J2MA2;FooOrg;;;;;;;laptop-asustek_computer_inc-1001pxd-b8oaas048287-14:da:e9:42:f6:7c;Laptop;Netbook;b8oaas048287;1001pxd;asustek computer inc.;Mon Aug 2 10:27:27 2021;Workbench 11.0b11;2021-08-02 10:27:27.528832+02:00;;;;intel atom cpu n455 @ 1.66ghz;2048;558558;Processor 17: model intel atom cpu n455 @ 1.66ghz, S/N None;intel corp.;intel atom cpu n455 @ 1.66ghz;;1;1.667;6666.24;164.0803;;;;;;;;;RamModule 20: model None, S/N None;;;;1024;667;RamModule 21: model 48594d503131325336344350362d53362020, S/N 4f43487b;hynix semiconductor;48594d503131325336344350362d53362020;4f43487b;1024;667;;;;;;;;;;;;;HardDrive 22: model hts54322, S/N e2024242cv86hj;hitachi;hts54322;e2024242cv86hj;238475;harddrive-hitachi-hts54322-e2024242cv86hj;e2024242cv86hj;238475;Workbench 11.0b11;Success;;EraseBasic;Shred;1:16:49;2021-08-02 10:27:27.458348+02:00;✓ – StepRandom 1:16:49;2018-07-03 11:15:22.257059+02:00;2018-07-03 12:32:11.843190+02:00;66.2;21.8;Workbench 11.0b11;Extended;Failure;;;DataStorage 23: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160041;datastorage-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160041;Workbench 11.0b11;Failure;;EraseBasic;Shred;0:45:36;2021-08-02 10:27:27.460573+02:00;✓ – StepRandom 0:45:36;2019-10-23 09:49:54.410830+02:00;2019-10-23 10:35:31.400587+02:00;41.6;17.3;Workbench 11.0b11;Short;Success;5293;195 days, 12:00:00;SolidStateDrive 24: model wdc wd1600bevt-2, S/N wd-wx11a80w7430;western digital;wdc wd1600bevt-2;wd-wx11a80w7430;160042;solidstatedrive-western_digital-wdc_wd1600bevt-2-wd-wx11a80w7430;wd-wx11a80w7430;160042;Workbench 11.0b11;Success;;EraseSectors;Badblocks;1:46:03;2021-08-02 10:27:27.464663+02:00;✓ – StepRandom 0:46:03,✓ – StepZero 1:00:00;2019-08-19 18:48:19.690458+02:00,2019-08-19 19:34:22.690458+02:00;2019-08-19 19:34:22.930562+02:00,2019-08-19 20:34:22.930562+02:00;41.1;17.1;Workbench 11.0b11;Short;Success;5231;194 days, 17:00:00;;;;;;;;;;;;;;;;;;;;;;;;;;Motherboard 25: model 1001pxd, S/N eee0123456789;asustek computer inc.;1001pxd;eee0123456789;;"auo ""auo""";auo lcd monitor;;GraphicCard 18: model atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller, S/N None;intel corporation;atom processor d4xx/d5xx/n4xx/n5xx integrated graphics controller;;256;;;;;;NetworkAdapter 15: model ar9285 wireless network adapter, S/N 74:2f:68:8b:fd:c8;qualcomm atheros;ar9285 wireless network adapter;74:2f:68:8b:fd:c8;NetworkAdapter 16: model ar8152 v2.0 fast ethernet, S/N 14:da:e9:42:f6:7c;qualcomm atheros;ar8152 v2.0 fast ethernet;14:da:e9:42:f6:7c;SoundCard 9: model usb 2.0 uvc vga webcam, S/N 0x0001;azurewave;usb 2.0 uvc vga webcam;0x0001;SoundCard 19: model nm10/ich7 family high definition audio controller, S/N None;intel corporation;nm10/ich7 family high definition audio controller;;1.72;LOW;1.31;LOW;1.99;LOW;3.97;HIGH;51.60 €;15.7188 diff --git a/tests/test_documents.py b/tests/test_documents.py index 240fa738..9e86acfe 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -219,7 +219,7 @@ def test_export_basic_snapshot(user: UserClient): item='devices/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - + f = StringIO(csv_str) obj_csv = csv.reader(f, f, delimiter=';', quotechar='"') export_csv = list(obj_csv) @@ -251,13 +251,13 @@ def test_check_insert_hash(app: Devicehub, user: UserClient, client: Client): assert ReportHash.query.filter_by(hash3=hash3).count() == 1 result, status = client.get(res=documents.DocumentDef.t, item='check/', query=[('hash', hash3)]) assert status.status_code == 200 - assert result == True + assert result ff = open('/tmp/test.csv', 'w') ff.write(csv_str) ff.close() - a= open('/tmp/test.csv').read() + a = open('/tmp/test.csv').read() assert hash3 == hashlib.sha3_256(a.encode('utf-8')).hexdigest() @@ -268,10 +268,7 @@ def test_export_extended(app: Devicehub, user: UserClient): snapshot2, _ = user.post(file('complete.export.snapshot'), res=Snapshot, status=201) with app.app_context(): # Create a pc with a tag - tag = Tag(id='foo', owner_id=user.user['id']) - # pc = Desktop(serial_number='sn1', chassis=ComputerChassis.Tower, owner_id=user.user['id']) pc = d.Device.query.filter_by(id=snapshot1['device']['id']).first() - pc.tags.add(tag) db.session.add(pc) db.session.commit() diff --git a/tests/test_lot.py b/tests/test_lot.py index e71f9d6d..3f1f0731 100644 --- a/tests/test_lot.py +++ b/tests/test_lot.py @@ -361,6 +361,7 @@ def test_lot_post_add_remove_device_view(app: Devicehub, user: UserClient): """ # todo check with components with app.app_context(): + g.user = User.query.one() device = Desktop(serial_number='foo', model='bar', manufacturer='foobar', @@ -391,9 +392,11 @@ def test_lot_post_add_remove_device_view(app: Devicehub, user: UserClient): @pytest.mark.mvp @pytest.mark.usefixtures(conftest.app_context.__name__) def test_lot_error_add_device_from_other_user(user: UserClient): + # TODO """Tests adding a device to a lot using POST and removing it with DELETE. """ + g.user = User.query.one() user2 = User(email='baz@baz.cxm', password='baz') user2.individuals.add(Person(name='Tommy')) db.session.add(user2) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index afeeba8b..6b403c4a 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -135,7 +135,7 @@ def test_metrics_action_status(user: UserClient, user2: UserClient): accept='text/csv', query=[('filter', {'type': ['Computer']})]) head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Supplier;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Action-Create;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' - body = '93652;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Status;;foo@foo.com;Receiver;;;Use;;' + body = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Status;;foo@foo.com;Receiver;;;Use;;' assert head in csv_str assert body in csv_str @@ -176,7 +176,7 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): accept='text/csv', query=[('filter', {'type': ['Computer']})]) - body1_lenovo = '93652;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;Refurbish;Use;' + body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;Refurbish;Use;' body2_lenovo = ';;0;0;Trade;0;0\n' body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;0;' diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index eaeca85c..a31a6c4e 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -37,7 +37,7 @@ from tests import conftest @pytest.mark.mvp @pytest.mark.usefixtures('auth_app_context') -# cayop + # import pdb; pdb.set_trace() def test_snapshot_model(): """Tests creating a Snapshot with its relationships ensuring correct DB mapping. @@ -318,7 +318,7 @@ def test_snapshot_tag_inner_tag(user: UserClient, tag_id: str, app: Devicehub): snapshot_and_check(user, b, action_types=(RateComputer.t, BenchmarkProcessor.t, VisualTest.t)) with app.app_context(): - tag = Tag.query.one() # type: Tag + tag = Tag.query.all()[0] # type: Tag assert tag.device_id == 3, 'Tag should be linked to the first device' @@ -358,7 +358,7 @@ def test_snapshot_different_properties_same_tags(user: UserClient, tag_id: str): def test_snapshot_upload_twice_uuid_error(user: UserClient): pc1 = file('basic.snapshot') user.post(pc1, res=Snapshot) - user.post(pc1, res=Snapshot, status=UniqueViolation) + user.post(pc1, res=Snapshot, status=400) @pytest.mark.mvp From 7ef31a3ba374dd5950abbacd6f3eb55f357d8a13 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 23 Oct 2021 13:41:26 +0200 Subject: [PATCH 13/48] fixing tests --- tests/test_device.py | 1 - tests/test_snapshot.py | 1 - tests/test_tag.py | 20 ++++++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/test_device.py b/tests/test_device.py index 4f366c51..3ffef3a9 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -348,7 +348,6 @@ def test_sync_execute_register_tag_linked_same_device(): db_pc = Sync().execute_register(pc) assert db_pc.id == orig_pc.id assert len(db_pc.tags) == 2 - # import pdb; pdb.set_trace() for tag in db_pc.tags: assert tag.id in ['foo', db_pc.devicehub_id] diff --git a/tests/test_snapshot.py b/tests/test_snapshot.py index a31a6c4e..130413c8 100644 --- a/tests/test_snapshot.py +++ b/tests/test_snapshot.py @@ -37,7 +37,6 @@ from tests import conftest @pytest.mark.mvp @pytest.mark.usefixtures('auth_app_context') - # import pdb; pdb.set_trace() def test_snapshot_model(): """Tests creating a Snapshot with its relationships ensuring correct DB mapping. diff --git a/tests/test_tag.py b/tests/test_tag.py index 67d59ccc..ce618e0b 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -2,6 +2,7 @@ import pathlib import pytest import requests_mock +from flask import g from boltons.urlutils import URL from ereuse_utils.session import DevicehubClient from pytest import raises @@ -11,6 +12,7 @@ from teal.marshmallow import ValidationError from ereuse_devicehub.client import UserClient, Client from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub +from ereuse_devicehub.resources.user.models import User from ereuse_devicehub.resources.action.models import Snapshot from ereuse_devicehub.resources.agent.models import Organization from ereuse_devicehub.resources.device.models import Desktop, Device @@ -19,7 +21,7 @@ from ereuse_devicehub.resources.tag import Tag from ereuse_devicehub.resources.tag.view import CannotCreateETag, LinkedToAnotherDevice, \ TagNotLinked from tests import conftest -from tests.conftest import file, yaml2json, json_encode +from tests.conftest import yaml2json, json_encode @pytest.mark.mvp @@ -41,6 +43,7 @@ def test_create_tag(user: UserClient): @pytest.mark.usefixtures(conftest.app_context.__name__) def test_create_tag_with_device(user: UserClient): """Creates a tag specifying linked with one device.""" + g.user = User.query.one() pc = Desktop(serial_number='sn1', chassis=ComputerChassis.Tower, owner_id=user.user['id']) db.session.add(pc) db.session.commit() @@ -60,13 +63,14 @@ def test_create_tag_with_device(user: UserClient): def test_delete_tags(user: UserClient, client: Client): """Delete a named tag.""" # Delete Tag Named + g.user = User.query.one() pc = Desktop(serial_number='sn1', chassis=ComputerChassis.Tower, owner_id=user.user['id']) db.session.add(pc) db.session.commit() tag = Tag(id='bar', owner_id=user.user['id'], device_id=pc.id) db.session.add(tag) db.session.commit() - tag = Tag.query.one() + tag = Tag.query.all()[-1] assert tag.id == 'bar' # Is not possible delete one tag linked to one device res, _ = user.delete(res=Tag, item=tag.id, status=422) @@ -88,12 +92,12 @@ def test_delete_tags(user: UserClient, client: Client): tag = Tag(id='bar-1', org=org, provider=URL('http://foo.bar'), owner_id=user.user['id']) db.session.add(tag) db.session.commit() - tag = Tag.query.one() + tag = Tag.query.all()[-1] assert tag.id == 'bar-1' res, _ = user.delete(res=Tag, item=tag.id, status=422) msg = 'This tag {} is unnamed tag. It is imposible delete.'.format(tag.id) assert msg in res['message'] - tag = Tag.query.one() + tag = Tag.query.all()[-1] assert tag.id == 'bar-1' @@ -182,6 +186,7 @@ def test_tag_get_device_from_tag_endpoint(app: Devicehub, user: UserClient): """Checks getting a linked device from a tag endpoint""" with app.app_context(): # Create a pc with a tag + g.user = User.query.one() tag = Tag(id='foo-bar', owner_id=user.user['id']) pc = Desktop(serial_number='sn1', chassis=ComputerChassis.Tower, owner_id=user.user['id']) pc.tags.add(tag) @@ -213,6 +218,7 @@ def test_tag_get_device_from_tag_endpoint_multiple_tags(app: Devicehub, user: Us system should not return any of both (to be deterministic) so it should raise an exception. """ + g.user = User.query.all()[0] db.session.add(Tag(id='foo', secondary='bar', owner_id=user.user['id'])) db.session.commit() @@ -276,6 +282,7 @@ def test_tag_manual_link_search(app: Devicehub, user: UserClient): Checks search has the term. """ with app.app_context(): + g.user = User.query.one() db.session.add(Tag('foo-bar', secondary='foo-sec', owner_id=user.user['id'])) desktop = Desktop(serial_number='foo', chassis=ComputerChassis.AllInOne, owner_id=user.user['id']) db.session.add(desktop) @@ -284,7 +291,7 @@ def test_tag_manual_link_search(app: Devicehub, user: UserClient): devicehub_id = desktop.devicehub_id user.put({}, res=Tag, item='foo-bar/device/{}'.format(desktop_id), status=204) device, _ = user.get(res=Device, item=devicehub_id) - assert device['tags'][0]['id'] == 'foo-bar' + assert device['tags'][-1]['id'] == 'foo-bar' # Device already linked # Just returns an OK to conform to PUT as anything changes @@ -412,6 +419,7 @@ def test_get_tag_permissions(app: Devicehub, user: UserClient, user2: UserClient """Creates a tag specifying a custom organization.""" with app.app_context(): # Create a pc with a tag + g.user = User.query.all()[0] tag = Tag(id='foo-bar', owner_id=user.user['id']) pc = Desktop(serial_number='sn1', chassis=ComputerChassis.Tower, owner_id=user.user['id']) pc.tags.add(tag) @@ -424,5 +432,5 @@ def test_get_tag_permissions(app: Devicehub, user: UserClient, user2: UserClient computer2, res2 = user2.get(url, None) assert res.status_code == 200 assert res2.status_code == 200 - assert len(computer['items']) == 1 + assert len(computer['items']) == 2 assert len(computer2['items']) == 0 From 0b8304b729600742400bc641d8c7a4c76976c40a Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 23 Oct 2021 14:02:49 +0200 Subject: [PATCH 14/48] fixing test --- tests/test_tag.py | 4 ++-- tests/test_workbench.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_tag.py b/tests/test_tag.py index ce618e0b..3264750d 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -330,8 +330,8 @@ def test_tag_secondary_workbench_link_find(user: UserClient): s['device']['tags'] = [{'id': 'foo', 'secondary': 'bar', 'type': 'Tag'}] snapshot, _ = user.post(json_encode(s), res=Snapshot) device, _ = user.get(res=Device, item=snapshot['device']['devicehubID']) - assert device['tags'][0]['id'] == 'foo' - assert device['tags'][0]['secondary'] == 'bar' + assert device['tags'][-1]['id'] == 'foo' + assert device['tags'][-1]['secondary'] == 'bar' r, _ = user.get(res=Device, query=[('search', 'foo'), ('filter', {'type': ['Computer']})]) assert len(r['items']) == 1 diff --git a/tests/test_workbench.py b/tests/test_workbench.py index 8dd2e65f..e668e8f3 100644 --- a/tests/test_workbench.py +++ b/tests/test_workbench.py @@ -184,7 +184,7 @@ def test_snapshot_real_eee_1001pxd_with_rate(user: UserClient): assert pc['serialNumber'] == 'b8oaas048286' assert pc['manufacturer'] == 'asustek computer inc.' assert pc['hid'] == 'laptop-asustek_computer_inc-1001pxd-b8oaas048286-14:da:e9:42:f6:7c' - assert pc['tags'] == [] + assert len(pc['tags']) == 1 assert pc['networkSpeeds'] == [100, 0], 'Although it has WiFi we do not know the speed' assert pc['rate'] rate = pc['rate'] From 2dd1a3cfd5a1c131c05bc4b92557565fd8525a8b Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 23 Oct 2021 14:44:09 +0200 Subject: [PATCH 15/48] fixed random tag order --- tests/test_tag.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_tag.py b/tests/test_tag.py index 3264750d..f852a206 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -291,7 +291,7 @@ def test_tag_manual_link_search(app: Devicehub, user: UserClient): devicehub_id = desktop.devicehub_id user.put({}, res=Tag, item='foo-bar/device/{}'.format(desktop_id), status=204) device, _ = user.get(res=Device, item=devicehub_id) - assert device['tags'][-1]['id'] == 'foo-bar' + assert 'foo-bar' in [x['id'] for x in device['tags']] # Device already linked # Just returns an OK to conform to PUT as anything changes @@ -330,8 +330,8 @@ def test_tag_secondary_workbench_link_find(user: UserClient): s['device']['tags'] = [{'id': 'foo', 'secondary': 'bar', 'type': 'Tag'}] snapshot, _ = user.post(json_encode(s), res=Snapshot) device, _ = user.get(res=Device, item=snapshot['device']['devicehubID']) - assert device['tags'][-1]['id'] == 'foo' - assert device['tags'][-1]['secondary'] == 'bar' + assert 'foo' in [x['id'] for x in device['tags']] + assert 'bar' in [x.get('secondary') for x in device['tags']] r, _ = user.get(res=Device, query=[('search', 'foo'), ('filter', {'type': ['Computer']})]) assert len(r['items']) == 1 From 3531f607da2fb8ec33c60d64703f49f580f336d0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Sat, 23 Oct 2021 15:01:50 +0200 Subject: [PATCH 16/48] fixing other orther of tags --- tests/test_workbench.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_workbench.py b/tests/test_workbench.py index e668e8f3..9998decc 100644 --- a/tests/test_workbench.py +++ b/tests/test_workbench.py @@ -67,7 +67,7 @@ def test_workbench_server_condensed(user: UserClient): assert device['rate']['type'] == RateComputer.t # TODO JN why haven't same order in actions on each execution? assert device['actions'][2]['type'] == BenchmarkProcessor.t or device['actions'][2]['type'] == BenchmarkRamSysbench.t - assert device['tags'][0]['id'] == 'tag1' + assert 'tag1' in [x['id'] for x in device['tags']] @pytest.mark.xfail(reason='Functionality not yet developed.') From 118825ed772d5a0567e9626f7c69567e59b24161 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 25 Oct 2021 10:43:28 +0200 Subject: [PATCH 17/48] testing bug confirmed in metrics --- tests/test_metrics.py | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 6b403c4a..aeffa538 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -297,3 +297,51 @@ def test_visual_metrics_for_old_owners(user: UserClient, user2: UserClient): assert body in csv_receiver assert body in csv_supplier + assert csv_receiver == csv_supplier + + +@pytest.mark.mvp +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_bug_trade_confirmed(user: UserClient, user2: UserClient): + """When the receiber do a Trade, then the confirmation is wrong.""" + # Insert computer + lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') + snap1, _ = user.post(json_encode(lenovo), res=ma.Snapshot) + lot, _ = user.post({'name': 'MyLot'}, res=Lot) + devices = [('id', snap1['device']['id'])] + lot, _ = user.post({}, + res=Lot, + item='{}/devices'.format(lot['id']), + query=devices) + request_post = { + 'type': 'Trade', + 'devices': [snap1['device']['id']], + 'userFromEmail': user2.email, + 'userToEmail': user.email, + 'price': 10, + 'date': "2020-12-01T02:00:00+00:00", + 'lot': lot['id'], + 'confirms': True, + } + trade, _ = user.post(res=ma.Action, data=request_post) + + csv_not_confirmed, _ = user.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + request_confirm = { + 'type': 'Confirm', + 'action': trade['id'], + 'devices': [snap1['device']['id']] + } + user2.post(res=ma.Action, data=request_confirm) + csv_confirmed, _ = user2.get(res=documents.DocumentDef.t, + item='actions/', + accept='text/csv', + query=[('filter', {'type': ['Computer']})]) + + body_not_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;False;" + body_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;True;" + + assert body_not_confirmed in csv_not_confirmed + assert body_confirmed in csv_confirmed From 15fa4546d118907f1b6cdff731c981f4c1677697 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 25 Oct 2021 12:20:16 +0200 Subject: [PATCH 18/48] fixing general case for devices --- ereuse_devicehub/resources/device/metrics.py | 6 ++---- tests/test_metrics.py | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index eaa72f04..898fc5d8 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -137,10 +137,8 @@ class Metrics(MetricsMix): if the action is one trade action, is possible than have a list of confirmations. Get the doble confirm for to know if this trade is confirmed or not. """ - if hasattr(self.act, 'acceptances'): - accept = self.act.acceptances[-1] - if accept.t == 'Confirm' and accept.user == self.act.user_to: - return True + if self.device.trading == 'TradeConfirmed': + return True return False def get_trade(self): diff --git a/tests/test_metrics.py b/tests/test_metrics.py index aeffa538..efdb26e4 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -304,7 +304,6 @@ def test_visual_metrics_for_old_owners(user: UserClient, user2: UserClient): @pytest.mark.usefixtures(conftest.app_context.__name__) def test_bug_trade_confirmed(user: UserClient, user2: UserClient): """When the receiber do a Trade, then the confirmation is wrong.""" - # Insert computer lenovo = yaml2json('desktop-9644w8n-lenovo-0169622.snapshot') snap1, _ = user.post(json_encode(lenovo), res=ma.Snapshot) lot, _ = user.post({'name': 'MyLot'}, res=Lot) From 5cce2f4efb90dd8b0e23d7ca9cde6c9932f04f4e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 25 Oct 2021 13:24:22 +0200 Subject: [PATCH 19/48] change some sintaxis --- ereuse_devicehub/resources/action/views/trade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index af44cedb..16f2572b 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -66,7 +66,7 @@ class TradeView(): # check than the user than want to do the action is one of the users # involved in the action - if not g.user in [self.trade.user_from, self.trade.user_to]: + if g.user not in [self.trade.user_from, self.trade.user_to]: txt = "You do not participate in this trading" raise ValidationError(txt) From 5861d2fd6ff79920ff2e6d727cf0f953baab720e Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 26 Oct 2021 16:21:05 +0200 Subject: [PATCH 20/48] fixing session in listener --- ereuse_devicehub/resources/device/models.py | 31 +++++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 473ca640..6cccc8b9 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1167,14 +1167,27 @@ class Manufacturer(db.Model): listener_reset_field_updated_in_actual_time(Device) +# def create_code_tag(mapper, connection, device): +# """ +# This function create a new tag every time than one device is create. +# this tag is the same of devicehub_id. +# """ +# from ereuse_devicehub.resources.tag.model import Tag +# tag = Tag(device_id=device.id, id=device.devicehub_id) +# import pdb; pdb.set_trace() +# db.session.add(tag) + + +# event.listen(Device, 'after_insert', create_code_tag, propagate=True) + + +@event.listens_for(Device, 'after_insert') def create_code_tag(mapper, connection, device): - """ - This function create a new tag every time than one device is create. - this tag is the same of devicehub_id. - """ - from ereuse_devicehub.resources.tag.model import Tag - tag = Tag(device_id=device.id, id=device.devicehub_id) - db.session.add(tag) + print(device.devicehub_id) - -event.listen(Device, 'after_insert', create_code_tag, propagate=True) + @event.listens_for(Session, 'after_flush', one=True) + def create_code_tag_after_fush(session, context): + from ereuse_devicehub.resources.tag.model import Tag + tag = Tag(device_id=device.id, id=device.devicehub_id) + # import pdb; pdb.set_trace() + session.add(tag) From 03238acb9fe8c71b7b0b460911ac522cbf9e2370 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 26 Oct 2021 16:35:41 +0200 Subject: [PATCH 21/48] fixing session in listener --- ereuse_devicehub/resources/device/models.py | 31 ++++++--------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 6cccc8b9..473ca640 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1167,27 +1167,14 @@ class Manufacturer(db.Model): listener_reset_field_updated_in_actual_time(Device) -# def create_code_tag(mapper, connection, device): -# """ -# This function create a new tag every time than one device is create. -# this tag is the same of devicehub_id. -# """ -# from ereuse_devicehub.resources.tag.model import Tag -# tag = Tag(device_id=device.id, id=device.devicehub_id) -# import pdb; pdb.set_trace() -# db.session.add(tag) - - -# event.listen(Device, 'after_insert', create_code_tag, propagate=True) - - -@event.listens_for(Device, 'after_insert') def create_code_tag(mapper, connection, device): - print(device.devicehub_id) + """ + This function create a new tag every time than one device is create. + this tag is the same of devicehub_id. + """ + from ereuse_devicehub.resources.tag.model import Tag + tag = Tag(device_id=device.id, id=device.devicehub_id) + db.session.add(tag) - @event.listens_for(Session, 'after_flush', one=True) - def create_code_tag_after_fush(session, context): - from ereuse_devicehub.resources.tag.model import Tag - tag = Tag(device_id=device.id, id=device.devicehub_id) - # import pdb; pdb.set_trace() - session.add(tag) + +event.listen(Device, 'after_insert', create_code_tag, propagate=True) From 283f869b4d24e04bbcc625e90173edea83df8cd8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 28 Oct 2021 12:19:49 +0200 Subject: [PATCH 22/48] drop remove --- ereuse_devicehub/resources/action/models.py | 8 +-- .../resources/action/views/trade.py | 3 +- ereuse_devicehub/resources/device/models.py | 59 ++++++++++++++++++- ereuse_devicehub/resources/lot/views.py | 14 +++-- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index fbc05234..5679decd 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1583,11 +1583,11 @@ class Revoke(Confirm): """Users can revoke one confirmation of one action trade""" -class ConfirmRevoke(Confirm): - """Users can confirm and accept one action revoke""" +# class ConfirmRevoke(Confirm): +# """Users can confirm and accept one action revoke""" - def __repr__(self) -> str: - return '<{0.t} {0.id} accepted by {0.user}>'.format(self) +# def __repr__(self) -> str: +# return '<{0.t} {0.id} accepted by {0.user}>'.format(self) class Trade(JoinedTableMixin, ActionWithMultipleTradeDocuments): diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 16f2572b..9d330ace 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -219,8 +219,9 @@ class RevokeView(ConfirmMixin): if not data['devices']: raise ValidationError('Devices not exist.') + lot = data['action'].lot for dev in data['devices']: - if not dev.trading == 'TradeConfirmed': + if not dev.trading(lot) == 'TradeConfirmed': txt = 'Some of devices do not have enough to confirm for to do a revoke' ValidationError(txt) ### End check ### diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 473ca640..ce021b55 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -301,11 +301,66 @@ class Device(Thing): return history - @property - def trading(self): + def trading(self, lot): """The trading state, or None if no Trade action has ever been performed to this device. This extract the posibilities for to do""" + if not hasattr(lot, 'trade'): + return + Status = {0: 'Trade', + 1: 'Confirm', + 2: 'TradeConfirmed', + 3: 'Revoke', + 4: 'RevokeConfirmed'} + + trade = lot.trade + user_from = trade.user_from + user_to = trade.user_to + user_from_confirm = False + user_to_confirm = False + user_from_revoke = False + user_to_revoke = False + status = 0 + confirms = {} + revokes = {} + # acceptances = copy.copy(trade.acceptances) + # acceptances = sorted(acceptances, key=lambda x: x.created) + + if not hasattr(ac, 'acceptances'): + return Status[status] + + for ac in trade.acceptances: + if ac.user not in [user_from, user_to]: + continue + + if ac.t == 'Confirm': + if ac.user == user_from: + user_from_confirm = True + elif ac.user == user_to: + user_to_confirm = True + + if ac.t == 'Revoke': + if ac.user == user_from: + user_from_revoke = True + elif ac.user == user_to: + user_to_revoke= True + + confirms = [user_from_confirm, user_to_confirm] + revokes = [user_from_revoke, user_to_revoke] + + if any(confirms): + status = 1 + if all(confirms): + status = 2 + + if any(revokes): + status = 3 + if all(revokes): + status = 4 + + def trading2(self): + """The trading state, or None if no Trade action has + ever been performed to this device. This extract the posibilities for to do""" # trade = 'Trade' confirm = 'Confirm' need_confirm = 'NeedConfirmation' diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index fcbca827..83b3b7c5 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -280,7 +280,7 @@ def delete_from_trade(lot: Lot, ids: Set[int]): # then can be revoked and deleted of the lot # Confirm of dev.trading mean that there are only one confirmation # and the first user than put this device in trade is the actual g.user - if dev.trading == 'Confirm': + if dev.trading(lot) == 'Confirm': without_confirms.add(dev) dev.reset_owner() @@ -293,12 +293,16 @@ def delete_from_trade(lot: Lot, ids: Set[int]): without_confirms = devices if without_confirms: - confirm_revoke = ConfirmRevoke( - action=revoke, - user=g.user, + phantom = lot.trade.user_to + if lot.trade.user_to == g.user: + phantom = lot.trade.user_from + + phantom_revoke = Revoke( + action=lot.trade, + user=phantom, devices=without_confirms ) - db.session.add(confirm_revoke) + db.session.add(phantom_revoke) lot.devices.difference_update(without_confirms) lot.trade.devices = lot.devices From c34cbb5c26c3e35b1bb2a55cac11aca4dbe9bf60 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Nov 2021 12:47:23 +0100 Subject: [PATCH 23/48] fixing metrics --- ereuse_devicehub/resources/device/metrics.py | 24 ++++++++++---------- tests/test_metrics.py | 13 ++++++++--- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 898fc5d8..dcb1d3b8 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -65,26 +65,26 @@ class Metrics(MetricsMix): If exist one trade before this action, then modify the trade action else, create one row new. """ - self.status_receiver = self.act.type - self.status_supplier = '' - if self.act.author != self.act.rol_user: - # It is neccesary exist one trade action before + if not self.last_trade: + # If not exist one trade, the status is of the Receive + self.action_create_by = 'Receiver' + self.status_receiver = self.act.type + self.status_supplier = '' + row = self.get_template_row() + row['status_receiver_created'] = self.act.created + self.rows.append(row) + return + + if self.last_trade['trade_supplier'] == self.act.rol_user.email: self.last_trade['status_supplier'] = self.act.type self.last_trade['status_supplier_created'] = self.act.created return - self.action_create_by = 'Receiver' - if self.last_trade: - # if exist one trade action before + if self.last_trade['trade_receiver'] == self.act.rol_user.email: self.last_trade['status_receiver'] = self.act.type self.last_trade['status_receiver_created'] = self.act.created return - # If not exist any trade action for this device - row = self.get_template_row() - row['status_receiver_created'] = self.act.created - self.rows.append(row) - def get_snapshot(self): """ If there are one snapshot get the last lifetime for to do a calcul of time of use. diff --git a/tests/test_metrics.py b/tests/test_metrics.py index efdb26e4..e8db619d 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -156,6 +156,10 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): res=Lot, item='{}/devices'.format(lot['id']), query=devices) + + action = {'type': ma.Refurbish.t, 'devices': [snap1['device']['id']]} + user.post(action, res=ma.Action) + request_post = { 'type': 'Trade', 'devices': [snap1['device']['id'], snap2['device']['id']], @@ -169,19 +173,22 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): user.post(res=ma.Action, data=request_post) - action = {'type': ma.Refurbish.t, 'devices': [snap1['device']['id']]} + action = {'type': ma.Use.t, 'devices': [snap1['device']['id']]} action_use, _ = user.post(action, res=ma.Action) csv_str, _ = user.get(res=documents.DocumentDef.t, item='actions/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;Refurbish;Use;' + body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;' + body1_lenovo += 'foo2@foo.com;Supplier;False;Refurbish;Use;' body2_lenovo = ';;0;0;Trade;0;0\n' - body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;0;' + body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;' + body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;0;' body2_acer = ';;0;0;Trade;0;4692.0\n' + # import pdb; pdb.set_trace() assert body1_lenovo in csv_str assert body2_lenovo in csv_str assert body1_acer in csv_str From 34def7bd70423ef10841ae462b9371938fe8a3c8 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Tue, 2 Nov 2021 14:25:49 +0100 Subject: [PATCH 24/48] fixint trading fuction --- ereuse_devicehub/resources/action/__init__.py | 5 -- ereuse_devicehub/resources/action/schemas.py | 79 +++---------------- .../resources/action/views/trade.py | 55 ++++++------- .../resources/action/views/views.py | 6 +- ereuse_devicehub/resources/device/models.py | 11 ++- ereuse_devicehub/resources/device/states.py | 1 - ereuse_devicehub/resources/lot/views.py | 2 +- 7 files changed, 47 insertions(+), 112 deletions(-) diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index e70bd18b..331d4dec 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -280,11 +280,6 @@ class ConfirmDef(ActionDef): SCHEMA = schemas.Confirm -class ConfirmRevokeDef(ActionDef): - VIEW = None - SCHEMA = schemas.ConfirmRevoke - - class RevokeDef(ActionDef): VIEW = None SCHEMA = schemas.Revoke diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 7c594375..bd81590a 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -442,14 +442,15 @@ class ActionStatus(Action): if not 'devices' in data.keys(): data['devices'] = [] - @post_load - def put_rol_user(self, data: dict): - for dev in data['devices']: - if dev.trading in [None, 'Revoke', 'ConfirmRevoke']: - return data - trade = [ac for ac in dev.actions if ac.t == 'Trade'][-1] - if trade.user_to != g.user: - data['rol_user'] = trade.user_to + # @post_load + # def put_rol_user(self, data: dict): + # TODO we need rebuild this functin + # for dev in data['devices']: + # if dev.trading in [None, 'Revoke']: + # return data + # trade = [ac for ac in dev.actions if ac.t == 'Trade'][-1] + # if trade.user_to != g.user: + # data['rol_user'] = trade.user_to class Recycling(ActionStatus): @@ -635,7 +636,7 @@ class RevokeDocument(ActionWithMultipleDocuments): class ConfirmRevokeDocument(ActionWithMultipleDocuments): - __doc__ = m.ConfirmRevoke.__doc__ + __doc__ = m.ConfirmRevokeDocument.__doc__ action = NestedOn('Action', only_query='id') @validates_schema @@ -662,66 +663,6 @@ class ConfirmRevokeDocument(ActionWithMultipleDocuments): data['action'] = doc.actions[-1] -class ConfirmRevoke(ActionWithMultipleDevices): - __doc__ = m.ConfirmRevoke.__doc__ - action = NestedOn('Action', only_query='id') - - @validates_schema - def validate_revoke(self, data: dict): - for dev in data['devices']: - # if device not exist in the Trade, then this query is wrong - if not dev in data['action'].devices: - txt = "Device {} not exist in the trade".format(dev.devicehub_id) - raise ValidationError(txt) - - for doc in data.get('documents', []): - # if document not exist in the Trade, then this query is wrong - if not doc in data['action'].documents: - txt = "Document {} not exist in the trade".format(doc.file_name) - raise ValidationError(txt) - - @validates_schema - def validate_docs(self, data): - """Check if there are or no one before confirmation, - This is not checked in the view becouse the list of documents is inmutable - - """ - if not data['devices'] == OrderedSet(): - return - - documents = [] - for doc in data['documents']: - actions = copy.copy(doc.actions) - actions.reverse() - for ac in actions: - if ac == data['action']: - # If document have the last action the action for confirm - documents.append(doc) - break - - if ac.t == 'Revoke' and not ac.user == g.user: - # If document is revoke before you can Confirm now - # and revoke is an action of one other user - documents.append(doc) - break - - if ac.t == ConfirmRevoke.t and ac.user == g.user: - # If document is confirmed we don't need confirmed again - break - - if ac.t == Confirm.t: - # if onwer of trade confirm again before than this user Confirm the - # revoke, then is not possible confirm the revoke - # - # If g.user confirm the trade before do a ConfirmRevoke - # then g.user can not to do the ConfirmRevoke more - break - - if not documents: - txt = 'No there are documents with revoke for confirm' - raise ValidationError(txt) - - class Trade(ActionWithMultipleDevices): __doc__ = m.Trade.__doc__ date = DateTime(data_key='date', required=False) diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 9d330ace..601d2b17 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -3,7 +3,7 @@ from sqlalchemy.util import OrderedSet from teal.marshmallow import ValidationError from ereuse_devicehub.db import db -from ereuse_devicehub.resources.action.models import (Trade, Confirm, ConfirmRevoke, +from ereuse_devicehub.resources.action.models import (Trade, Confirm, Revoke, RevokeDocument, ConfirmDocument, ConfirmRevokeDocument) from ereuse_devicehub.resources.user.models import User @@ -231,42 +231,43 @@ class RevokeView(ConfirmMixin): self.model = delete_from_trade(lot, ids) -class ConfirmRevokeView(ConfirmMixin): - """Handler for manager the Confirmation register from post +# class ConfirmRevokeView(ConfirmMixin): +# """Handler for manager the Confirmation register from post - request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': action_revoke.id, - 'devices': [device_id] - } +# request_confirm_revoke = { +# 'type': 'ConfirmRevoke', +# 'action': action_revoke.id, +# 'devices': [device_id] +# } - """ +# """ - Model = ConfirmRevoke +# Model = ConfirmRevoke - def validate(self, data): - """All devices need to have the status of revoke.""" +# def validate(self, data): +# """All devices need to have the status of revoke.""" - if not data['action'].type == 'Revoke': - txt = 'Error: this action is not a revoke action' - ValidationError(txt) +# if not data['action'].type == 'Revoke': +# txt = 'Error: this action is not a revoke action' +# ValidationError(txt) - for dev in data['devices']: - if not dev.trading == 'Revoke': - txt = 'Some of devices do not have revoke to confirm' - ValidationError(txt) +# lot = data['action'].lot +# for dev in data['devices']: +# if not dev.trading(lot) == 'Revoke': +# txt = 'Some of devices do not have revoke to confirm' +# ValidationError(txt) - devices = OrderedSet(data['devices']) - data['devices'] = devices +# devices = OrderedSet(data['devices']) +# data['devices'] = devices - # Change the owner for every devices - # data['action'] == 'Revoke' +# # Change the owner for every devices +# # data['action'] == 'Revoke' - trade = data['action'].action - for dev in devices: - dev.reset_owner() +# trade = data['action'].action +# for dev in devices: +# dev.reset_owner() - trade.lot.devices.difference_update(devices) +# trade.lot.devices.difference_update(devices) class ConfirmDocumentMixin(): diff --git a/ereuse_devicehub/resources/action/views/views.py b/ereuse_devicehub/resources/action/views/views.py index 415effb8..82e3f5e0 100644 --- a/ereuse_devicehub/resources/action/views/views.py +++ b/ereuse_devicehub/resources/action/views/views.py @@ -15,7 +15,7 @@ from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.action.models import (Action, Snapshot, VisualTest, InitTransfer, Live, Allocate, Deallocate, - Trade, Confirm, ConfirmRevoke, Revoke) + Trade, Confirm, Revoke) from ereuse_devicehub.resources.action.views import trade as trade_view from ereuse_devicehub.resources.action.views.snapshot import SnapshotView, save_json, move_json from ereuse_devicehub.resources.action.views.documents import ErasedView @@ -235,10 +235,6 @@ class ActionView(View): revoke = trade_view.RevokeView(json, resource_def, self.schema) return revoke.post() - if json['type'] == ConfirmRevoke.t: - confirm_revoke = trade_view.ConfirmRevokeView(json, resource_def, self.schema) - return confirm_revoke.post() - if json['type'] == 'RevokeDocument': revoke = trade_view.RevokeDocumentView(json, resource_def, self.schema) return revoke.post() diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index ce021b55..95040dd0 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -323,13 +323,14 @@ class Device(Thing): status = 0 confirms = {} revokes = {} - # acceptances = copy.copy(trade.acceptances) - # acceptances = sorted(acceptances, key=lambda x: x.created) - if not hasattr(ac, 'acceptances'): + if not hasattr(trade, 'acceptances'): return Status[status] - for ac in trade.acceptances: + acceptances = copy.copy(trade.acceptances) + acceptances = sorted(acceptances, key=lambda x: x.created) + + for ac in acceptances: if ac.user not in [user_from, user_to]: continue @@ -358,6 +359,8 @@ class Device(Thing): if all(revokes): status = 4 + return Status[status] + def trading2(self): """The trading state, or None if no Trade action has ever been performed to this device. This extract the posibilities for to do""" diff --git a/ereuse_devicehub/resources/device/states.py b/ereuse_devicehub/resources/device/states.py index 5177f701..3cfefe4b 100644 --- a/ereuse_devicehub/resources/device/states.py +++ b/ereuse_devicehub/resources/device/states.py @@ -37,7 +37,6 @@ class Trading(State): Trade = e.Trade Confirm = e.Confirm Revoke = e.Revoke - ConfirmRevoke = e.ConfirmRevoke Cancelled = e.CancelTrade Sold = e.Sell Donated = e.Donate diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 83b3b7c5..d41f2008 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -13,7 +13,7 @@ from teal.resource import View from ereuse_devicehub.db import db from ereuse_devicehub.query import things_response from ereuse_devicehub.resources.device.models import Device, Computer -from ereuse_devicehub.resources.action.models import Trade, Confirm, Revoke, ConfirmRevoke +from ereuse_devicehub.resources.action.models import Trade, Confirm, Revoke from ereuse_devicehub.resources.lot.models import Lot, Path From b233b7bb75d582a6b99c6bc6111d9746317cadc9 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 3 Nov 2021 10:37:15 +0100 Subject: [PATCH 25/48] fixed --- ereuse_devicehub/resources/device/metrics.py | 24 +++++++++++++++----- tests/test_metrics.py | 17 ++++++++++---- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index dcb1d3b8..bbc2f470 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -10,7 +10,7 @@ class MetricsMix: self.lifetime = 0 self.last_trade = None self.action_create_by = 'Receiver' - self.status_receiver = 'Use' + self.status_receiver = '' self.status_supplier = '' self.act = None self.end_users = 0 @@ -63,7 +63,7 @@ class Metrics(MetricsMix): """ Mark the status of one device. If exist one trade before this action, then modify the trade action - else, create one row new. + else, create one new row. """ if not self.last_trade: # If not exist one trade, the status is of the Receive @@ -71,20 +71,32 @@ class Metrics(MetricsMix): self.status_receiver = self.act.type self.status_supplier = '' row = self.get_template_row() + row['status_supplier_created'] = '' row['status_receiver_created'] = self.act.created self.rows.append(row) return - if self.last_trade['trade_supplier'] == self.act.rol_user.email: + # if self.last_trade['trade_supplier'] == self.act.rol_user.email: + # self.last_trade['status_supplier'] = self.act.type + # self.last_trade['status_supplier_created'] = self.act.created + # return + + # if self.last_trade['trade_receiver'] == self.act.rol_user.email: + # self.last_trade['status_receiver'] = self.act.type + # self.last_trade['status_receiver_created'] = self.act.created + # return + + if self.last_trade['trade_supplier'] == self.act.author.email: self.last_trade['status_supplier'] = self.act.type self.last_trade['status_supplier_created'] = self.act.created return - if self.last_trade['trade_receiver'] == self.act.rol_user.email: + if self.last_trade['trade_receiver'] == self.act.author.email: self.last_trade['status_receiver'] = self.act.type self.last_trade['status_receiver_created'] = self.act.created return + def get_snapshot(self): """ If there are one snapshot get the last lifetime for to do a calcul of time of use. @@ -153,8 +165,8 @@ class Metrics(MetricsMix): row['action_type'] = 'Trade' row['trade_supplier'] = self.act.user_from.email row['trade_receiver'] = self.act.user_to.email - row['self.status_receiver'] = self.status_receiver - row['self.status_supplier'] = self.status_supplier + row['status_receiver'] = '' + row['status_supplier'] = '' row['trade_confirmed'] = self.get_confirms() self.rows.append(row) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index e8db619d..191c988f 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -181,11 +181,11 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): query=[('filter', {'type': ['Computer']})]) body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;' - body1_lenovo += 'foo2@foo.com;Supplier;False;Refurbish;Use;' + body1_lenovo += 'foo2@foo.com;Supplier;False;Use;;' body2_lenovo = ';;0;0;Trade;0;0\n' body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;' - body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;False;;Use;;;0;' + body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;False;;;;;0;' body2_acer = ';;0;0;Trade;0;4692.0\n' # import pdb; pdb.set_trace() @@ -195,15 +195,22 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): assert body2_acer in csv_str # User2 mark this device as Refurbish - action = {'type': ma.Refurbish.t, 'devices': [snap1['device']['id']]} + action = {'type': ma.Use.t, 'devices': [snap1['device']['id']]} action_use2, _ = user2.post(action, res=ma.Action) csv_str, _ = user.get(res=documents.DocumentDef.t, item='actions/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - body2_lenovo = ';Refurbish;0;0;Trade;0;0\n' - body2_acer = ';Refurbish;0;0;Trade;0;4692.0\n' + body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;' + body1_lenovo += 'foo2@foo.com;Supplier;False;Use;Use;' + body2_lenovo = ';;0;0;Trade;0;0\n' + body2_acer = ';;0;0;Trade;0;4692.0\n' + + assert body1_lenovo in csv_str + assert body2_lenovo in csv_str + assert body2_acer in csv_str + @pytest.mark.mvp From 6de83ce4d2b1d281541c836776de6868ca308f00 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 4 Nov 2021 11:58:15 +0100 Subject: [PATCH 26/48] Fixing order of actions_multiple devices --- .../1bb2b5e0fae7_change_action_device.py | 56 +++++++++++++++++++ ereuse_devicehub/resources/action/models.py | 17 ++++++ ereuse_devicehub/resources/device/metrics.py | 23 ++++---- ereuse_devicehub/resources/device/models.py | 11 +++- .../resources/documents/device_row.py | 2 +- tests/test_metrics.py | 2 +- 6 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py diff --git a/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py b/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py new file mode 100644 index 00000000..2f3a4ce0 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py @@ -0,0 +1,56 @@ +""" +change action_device + +Revision ID: 1bb2b5e0fae7 +Revises: a0978ac6cf4a +Create Date: 2021-11-04 10:32:49.116399 + +""" +import sqlalchemy as sa +from alembic import context +from alembic import op +from sqlalchemy.dialects import postgresql + + +# revision identifiers, used by Alembic. +revision = '1bb2b5e0fae7' +down_revision = 'a0978ac6cf4a' +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_data(): + con = op.get_bind() + + values = f"action_id, {get_inv()}.action.created" + table = f"{get_inv()}.action_device" + joins = f"inner join {get_inv()}.action" + on = f"on {get_inv()}.action_device.action_id = {get_inv()}.action.id" + sql = f"select {values} from {table} {joins} {on}" + + actions_devs = con.execute(sql) + for a in actions_devs: + action_id = a.action_id + created = a.created + sql = f"update {get_inv()}.action_device set created='{created}' where action_id='{action_id}';" + con.execute(sql) + + +def upgrade(): + op.add_column('action_device', + sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'), + nullable=False, comment='When Devicehub created this.'), + schema=f'{get_inv()}') + + upgrade_data() + + +def downgrade(): + op.drop_column('action_device', 'created', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index fbc05234..5cd678db 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -304,6 +304,23 @@ class ActionDevice(db.Model): device_id = Column(BigInteger, ForeignKey(Device.id), primary_key=True) action_id = Column(UUID(as_uuid=True), ForeignKey(ActionWithMultipleDevices.id), primary_key=True) + device = relationship(Device, + backref=backref('actions_device', + lazy=True), + primaryjoin=Device.id == device_id) + action = relationship(Action, + backref=backref('actions_device', + lazy=True), + primaryjoin=Action.id == action_id) + created = db.Column(db.TIMESTAMP(timezone=True), + nullable=False, + index=True, + server_default=db.text('CURRENT_TIMESTAMP')) + created.comment = """When Devicehub created this.""" + + def __init__(self, **kwargs) -> None: + self.created = kwargs.get('created', datetime.now(timezone.utc)) + super().__init__(**kwargs) class ActionWithMultipleTradeDocuments(ActionWithMultipleDevices): diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index bbc2f470..a9c84a44 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -5,7 +5,7 @@ class MetricsMix: """we want get the data metrics of one device""" def __init__(self, *args, **kwargs): - self.actions.sort(key=lambda x: x.created) + # self.actions.sort(key=lambda x: x.created) self.rows = [] self.lifetime = 0 self.last_trade = None @@ -15,6 +15,7 @@ class MetricsMix: self.act = None self.end_users = 0 self.final_user_code = '' + self.trades = {} def get_template_row(self): """ @@ -76,16 +77,7 @@ class Metrics(MetricsMix): self.rows.append(row) return - # if self.last_trade['trade_supplier'] == self.act.rol_user.email: - # self.last_trade['status_supplier'] = self.act.type - # self.last_trade['status_supplier_created'] = self.act.created - # return - - # if self.last_trade['trade_receiver'] == self.act.rol_user.email: - # self.last_trade['status_receiver'] = self.act.type - # self.last_trade['status_receiver_created'] = self.act.created - # return - + # import pdb; pdb.set_trace() if self.last_trade['trade_supplier'] == self.act.author.email: self.last_trade['status_supplier'] = self.act.type self.last_trade['status_supplier_created'] = self.act.created @@ -96,7 +88,6 @@ class Metrics(MetricsMix): self.last_trade['status_receiver_created'] = self.act.created return - def get_snapshot(self): """ If there are one snapshot get the last lifetime for to do a calcul of time of use. @@ -109,6 +100,7 @@ class Metrics(MetricsMix): """ If the action is one Allocate, need modify the row base. """ + self.action_create_by = 'Receiver' self.end_users = self.act.end_users self.final_user_code = self.act.final_user_code row = self.get_template_row() @@ -124,6 +116,7 @@ class Metrics(MetricsMix): """ If the action is one Live, need modify the row base. """ + self.action_create_by = 'Receiver' row = self.get_template_row() row['type'] = 'Live' row['finalUserCode'] = self.final_user_code @@ -139,6 +132,7 @@ class Metrics(MetricsMix): """ If the action is one Dellocate, need modify the row base. """ + self.action_create_by = 'Receiver' row = self.get_template_row() row['type'] = 'Deallocate' row['start'] = self.act.start_time @@ -159,15 +153,18 @@ class Metrics(MetricsMix): """ if self.act.author == self.act.user_from: self.action_create_by = 'Supplier' + self.status_receiver = '' + row = self.get_template_row() self.last_trade = row row['type'] = 'Trade' row['action_type'] = 'Trade' row['trade_supplier'] = self.act.user_from.email row['trade_receiver'] = self.act.user_to.email - row['status_receiver'] = '' + row['status_receiver'] = self.status_receiver row['status_supplier'] = '' row['trade_confirmed'] = self.get_confirms() + self.trades[self.act.created] = row self.rows.append(row) def get_metrics(self): diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 473ca640..d30df4f8 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -171,7 +171,16 @@ class Device(Thing): Actions are returned by descending ``created`` time. """ - return sorted(chain(self.actions_multiple, self.actions_one), key=lambda x: x.created) + actions_multiple = copy.copy(self.actions_multiple) + actions_one = copy.copy(self.actions_one) + + for ac in actions_multiple: + ac.real_created = ac.actions_device[0].created + + for ac in actions_one: + ac.real_created = ac.created + + return sorted(chain(actions_multiple, actions_one), key=lambda x: x.real_created) @property def problems(self): diff --git a/ereuse_devicehub/resources/documents/device_row.py b/ereuse_devicehub/resources/documents/device_row.py index de550d91..26eecd21 100644 --- a/ereuse_devicehub/resources/documents/device_row.py +++ b/ereuse_devicehub/resources/documents/device_row.py @@ -435,7 +435,7 @@ class ActionRow(OrderedDict): self['Action-User-LastOwner-Receiver'] = allocate['trade_receiver'] self['Action-Create-By'] = allocate['action_create_by'] self['Trade-Confirmed'] = allocate['trade_confirmed'] - self['Status-Supplier'] = allocate['status_supplier'] + self['Status-Created-By-Supplier-About-Reciber'] = allocate['status_supplier'] self['Status-Receiver'] = allocate['status_receiver'] self['Status Supplier – Created Date'] = allocate['status_supplier_created'] self['Status Receiver – Created Date'] = allocate['status_receiver_created'] diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 191c988f..6ad7a516 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -134,7 +134,7 @@ def test_metrics_action_status(user: UserClient, user2: UserClient): item='actions/', accept='text/csv', query=[('filter', {'type': ['Computer']})]) - head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Supplier;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Action-Create;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' + head = 'DHID;Hid;Document-Name;Action-Type;Action-User-LastOwner-Supplier;Action-User-LastOwner-Receiver;Action-Create-By;Trade-Confirmed;Status-Created-By-Supplier-About-Reciber;Status-Receiver;Status Supplier – Created Date;Status Receiver – Created Date;Trade-Weight;Action-Create;Allocate-Start;Allocate-User-Code;Allocate-NumUsers;UsageTimeAllocate;Type;LiveCreate;UsageTimeHdd\n' body = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Status;;foo@foo.com;Receiver;;;Use;;' assert head in csv_str assert body in csv_str From 56df40c81a8a2a3f29cc9f64b6cf800bc5e8d208 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 4 Nov 2021 13:27:25 +0100 Subject: [PATCH 27/48] fixing actions for computer --- ereuse_devicehub/resources/device/models.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index d30df4f8..d088d4ed 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -644,7 +644,13 @@ class Computer(Device): @property def actions(self) -> list: - return sorted(chain(super().actions, self.actions_parent)) + actions = copy.copy(super().actions) + actions_parent = copy.copy(self.actions_parent) + for ac in actions_parent: + ac.real_created = ac.created + + return sorted(chain(actions, actions_parent), key=lambda x: x.real_created) + # return sorted(chain(super().actions, self.actions_parent)) @property def ram_size(self) -> int: From 5ebf4f48b501d3c3ea92e1d5aa78e42358cce1a5 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 5 Nov 2021 12:35:10 +0100 Subject: [PATCH 28/48] adding trade in status actions --- .../versions/1bb2b5e0fae7_change_action_device.py | 13 +++++++++++++ ereuse_devicehub/resources/action/models.py | 10 ++++++++++ ereuse_devicehub/resources/action/schemas.py | 1 + ereuse_devicehub/resources/device/metrics.py | 9 +++++++-- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py b/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py index 2f3a4ce0..d03df285 100644 --- a/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py +++ b/ereuse_devicehub/migrations/versions/1bb2b5e0fae7_change_action_device.py @@ -49,8 +49,21 @@ def upgrade(): nullable=False, comment='When Devicehub created this.'), schema=f'{get_inv()}') + op.add_column('action_status', + sa.Column('trade_id', postgresql.UUID(as_uuid=True), nullable=True), + schema=f'{get_inv()}') + + op.create_foreign_key("fk_action_status_trade", + "action_status", "trade", + ["trade_id"], ["id"], + ondelete="SET NULL", + source_schema=f'{get_inv()}', + referent_schema=f'{get_inv()}') + upgrade_data() def downgrade(): + op.drop_constraint("fk_action_status_trade", "action_status", type_="foreignkey", schema=f'{get_inv()}') op.drop_column('action_device', 'created', schema=f'{get_inv()}') + op.drop_column('action_status', 'trade_id', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index 5cd678db..e1449afb 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -1377,6 +1377,16 @@ class ActionStatus(JoinedTableMixin, ActionWithMultipleTradeDocuments): default=lambda: g.user.id) rol_user = db.relationship(User, primaryjoin=rol_user_id == User.id) rol_user_comment = """The user that .""" + trade_id = db.Column(UUID(as_uuid=True), + db.ForeignKey('trade.id'), + nullable=True) + trade = db.relationship('Trade', + backref=backref('status_changes', + uselist=True, + lazy=True, + order_by=lambda: Action.end_time, + collection_class=list), + primaryjoin='ActionStatus.trade_id == Trade.id') class Recycling(ActionStatus): diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 7c594375..f6740c38 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -450,6 +450,7 @@ class ActionStatus(Action): trade = [ac for ac in dev.actions if ac.t == 'Trade'][-1] if trade.user_to != g.user: data['rol_user'] = trade.user_to + data['trade'] = trade class Recycling(ActionStatus): diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index a9c84a44..5495cc5e 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -77,7 +77,6 @@ class Metrics(MetricsMix): self.rows.append(row) return - # import pdb; pdb.set_trace() if self.last_trade['trade_supplier'] == self.act.author.email: self.last_trade['status_supplier'] = self.act.type self.last_trade['status_supplier_created'] = self.act.created @@ -88,6 +87,10 @@ class Metrics(MetricsMix): self.last_trade['status_receiver_created'] = self.act.created return + # import pdb; pdb.set_trace() + # necesitamos poder poner un cambio de estado de un trade mas antiguo que last_trade + # lo mismo con confirm + def get_snapshot(self): """ If there are one snapshot get the last lifetime for to do a calcul of time of use. @@ -164,7 +167,9 @@ class Metrics(MetricsMix): row['status_receiver'] = self.status_receiver row['status_supplier'] = '' row['trade_confirmed'] = self.get_confirms() - self.trades[self.act.created] = row + # import pdb; pdb.set_trace() + created = self.act.actions_device[0].created + self.trades[created] = row self.rows.append(row) def get_metrics(self): From 6bf1354109b18aec9e937bd12c2de13a821ce945 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 5 Nov 2021 13:00:01 +0100 Subject: [PATCH 29/48] fixing change status next trade --- ereuse_devicehub/resources/device/metrics.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 5495cc5e..4ecd9eda 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -66,7 +66,7 @@ class Metrics(MetricsMix): If exist one trade before this action, then modify the trade action else, create one new row. """ - if not self.last_trade: + if self.act.trade not in self.trades: # If not exist one trade, the status is of the Receive self.action_create_by = 'Receiver' self.status_receiver = self.act.type @@ -77,14 +77,16 @@ class Metrics(MetricsMix): self.rows.append(row) return - if self.last_trade['trade_supplier'] == self.act.author.email: - self.last_trade['status_supplier'] = self.act.type - self.last_trade['status_supplier_created'] = self.act.created + trade = self.trades[self.act.trade] + + if trade['trade_supplier'] == self.act.author.email: + trade['status_supplier'] = self.act.type + trade['status_supplier_created'] = self.act.created return - if self.last_trade['trade_receiver'] == self.act.author.email: - self.last_trade['status_receiver'] = self.act.type - self.last_trade['status_receiver_created'] = self.act.created + if trade['trade_receiver'] == self.act.author.email: + trade['status_receiver'] = self.act.type + trade['status_receiver_created'] = self.act.created return # import pdb; pdb.set_trace() @@ -167,9 +169,7 @@ class Metrics(MetricsMix): row['status_receiver'] = self.status_receiver row['status_supplier'] = '' row['trade_confirmed'] = self.get_confirms() - # import pdb; pdb.set_trace() - created = self.act.actions_device[0].created - self.trades[created] = row + self.trades[self.act] = row self.rows.append(row) def get_metrics(self): From f8be48d5241e9ac8eef42ed1a2bfd3052b72c1d6 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 5 Nov 2021 13:10:23 +0100 Subject: [PATCH 30/48] fixing schema --- ereuse_devicehub/resources/action/schemas.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index f6740c38..1836568d 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -439,7 +439,7 @@ class ActionStatus(Action): @pre_load def put_devices(self, data: dict): - if not 'devices' in data.keys(): + if 'devices' not in data.keys(): data['devices'] = [] @post_load @@ -447,10 +447,16 @@ class ActionStatus(Action): for dev in data['devices']: if dev.trading in [None, 'Revoke', 'ConfirmRevoke']: return data - trade = [ac for ac in dev.actions if ac.t == 'Trade'][-1] + + trades = [ac for ac in dev.actions if ac.t == 'Trade'] + if not trades: + return data + + trade = trades[-1] + if trade.user_to != g.user: data['rol_user'] = trade.user_to - data['trade'] = trade + data['trade'] = trade class Recycling(ActionStatus): From c7ced04e9dec5c4f460d50d9530a34355e5ebab1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 8 Nov 2021 17:33:22 +0100 Subject: [PATCH 31/48] fixing bug for documents --- ereuse_devicehub/resources/device/metrics.py | 22 +++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 4ecd9eda..3365e6cc 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -233,9 +233,9 @@ class TradeMetrics(MetricsMix): row['status_receiver'] = '' row['status_supplier'] = '' row['trade_weight'] = self.document.weight - if self.last_trade.author == self.last_trade.user_from: + if self.document.owner == self.last_trade.user_from: row['action_create_by'] = 'Supplier' - elif self.last_trade.author == self.last_trade.user_to: + elif self.document.owner == self.last_trade.user_to: row['action_create_by'] = 'Receiver' self.rows.append(row) @@ -247,8 +247,20 @@ class TradeMetrics(MetricsMix): if the action is one trade action, is possible than have a list of confirmations. Get the doble confirm for to know if this trade is confirmed or not. """ - if hasattr(self.last_trade, 'acceptances_document'): - accept = self.last_trade.acceptances_document[-1] - if accept.t == 'Confirm' and accept.user == self.last_trade.user_to: + trade = None + confirmations = [] + confirms = [] + for ac in self.document.actions: + if ac.t == 'Trade': + trade = ac + elif ac.t == 'ConfirmDocument': + confirms.append(ac.author) + confirmations.append(ac) + elif ac.t in ['RevokeDocument', 'ConfirmDocumentRevoke']: + confirmations.append(ac) + + if confirmations and confirmations[-1].t == 'ConfirmDocument': + if trade.user_from in confirms and trade.user_to in confirms: return True + return False From 9dc79a59dc421ac4baa12409c42747e6c6082de0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Wed, 10 Nov 2021 18:59:44 +0100 Subject: [PATCH 32/48] fixing revokeView and reset_owner --- ...22d230d2850_adding_author_action_device.py | 43 +++++ ereuse_devicehub/resources/action/__init__.py | 5 + ereuse_devicehub/resources/action/models.py | 8 + ereuse_devicehub/resources/action/schemas.py | 9 +- .../resources/action/views/trade.py | 26 ++- .../resources/action/views/views.py | 4 + ereuse_devicehub/resources/device/metrics.py | 4 +- ereuse_devicehub/resources/device/models.py | 168 +++++++++--------- ereuse_devicehub/resources/device/schemas.py | 9 +- ereuse_devicehub/resources/lot/views.py | 1 + tests/test_action.py | 22 ++- 11 files changed, 188 insertions(+), 111 deletions(-) create mode 100644 ereuse_devicehub/migrations/versions/d22d230d2850_adding_author_action_device.py diff --git a/ereuse_devicehub/migrations/versions/d22d230d2850_adding_author_action_device.py b/ereuse_devicehub/migrations/versions/d22d230d2850_adding_author_action_device.py new file mode 100644 index 00000000..ed58f669 --- /dev/null +++ b/ereuse_devicehub/migrations/versions/d22d230d2850_adding_author_action_device.py @@ -0,0 +1,43 @@ +"""adding author action_device + +Revision ID: d22d230d2850 +Revises: 1bb2b5e0fae7 +Create Date: 2021-11-10 17:37:12.304853 + +""" +import sqlalchemy as sa +from alembic import context +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'd22d230d2850' +down_revision = '1bb2b5e0fae7' +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.add_column('action_device', + sa.Column('author_id', + postgresql.UUID(), + nullable=True), + schema=f'{get_inv()}') + op.create_foreign_key("fk_action_device_author", + "action_device", "user", + ["author_id"], ["id"], + ondelete="SET NULL", + source_schema=f'{get_inv()}', + referent_schema='common') + + +def downgrade(): + op.drop_constraint("fk_action_device_author", "device", type_="foreignkey", schema=f'{get_inv()}') + op.drop_column('action_device', 'author_id', schema=f'{get_inv()}') diff --git a/ereuse_devicehub/resources/action/__init__.py b/ereuse_devicehub/resources/action/__init__.py index 331d4dec..0d89f557 100644 --- a/ereuse_devicehub/resources/action/__init__.py +++ b/ereuse_devicehub/resources/action/__init__.py @@ -285,6 +285,11 @@ class RevokeDef(ActionDef): SCHEMA = schemas.Revoke +class ConfirmRevokeDef(ActionDef): + VIEW = None + SCHEMA = schemas.ConfirmRevoke + + class TradeDef(ActionDef): VIEW = None SCHEMA = schemas.Trade diff --git a/ereuse_devicehub/resources/action/models.py b/ereuse_devicehub/resources/action/models.py index b2fb2c18..e4e8c3b6 100644 --- a/ereuse_devicehub/resources/action/models.py +++ b/ereuse_devicehub/resources/action/models.py @@ -317,6 +317,14 @@ class ActionDevice(db.Model): index=True, server_default=db.text('CURRENT_TIMESTAMP')) created.comment = """When Devicehub created this.""" + author_id = Column(UUID(as_uuid=True), + ForeignKey(User.id), + nullable=False, + default=lambda: g.user.id) + # todo compute the org + author = relationship(User, + backref=backref('authored_actions_device', lazy=True, collection_class=set), + primaryjoin=author_id == User.id) def __init__(self, **kwargs) -> None: self.created = kwargs.get('created', datetime.now(timezone.utc)) diff --git a/ereuse_devicehub/resources/action/schemas.py b/ereuse_devicehub/resources/action/schemas.py index 0202a3a3..1f7f3fef 100644 --- a/ereuse_devicehub/resources/action/schemas.py +++ b/ereuse_devicehub/resources/action/schemas.py @@ -445,16 +445,13 @@ class ActionStatus(Action): @post_load def put_rol_user(self, data: dict): for dev in data['devices']: - if dev.trading in [None, 'Revoke']: - return data - trades = [ac for ac in dev.actions if ac.t == 'Trade'] if not trades: return data trade = trades[-1] - if trade.user_to != g.user: + if trade.user_from == g.user: data['rol_user'] = trade.user_to data['trade'] = trade @@ -588,6 +585,10 @@ class Revoke(ActionWithMultipleDevices): raise ValidationError(txt) +class ConfirmRevoke(Revoke): + pass + + class ConfirmDocument(ActionWithMultipleDocuments): __doc__ = m.Confirm.__doc__ action = NestedOn('Action', only_query='id') diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 601d2b17..4aac48d4 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -220,15 +220,29 @@ class RevokeView(ConfirmMixin): raise ValidationError('Devices not exist.') lot = data['action'].lot + + revokeConfirmed = [] for dev in data['devices']: - if not dev.trading(lot) == 'TradeConfirmed': - txt = 'Some of devices do not have enough to confirm for to do a revoke' - ValidationError(txt) + if dev.trading(lot) == 'RevokeConfirmed': + # this device is revoked before + revokeConfirmed.append(dev) ### End check ### - ids = {d.id for d in data['devices']} - lot = data['action'].lot - self.model = delete_from_trade(lot, ids) + devices = {d for d in data['devices'] if d not in revokeConfirmed} + # self.model = delete_from_trade(lot, devices) + # TODO @cayop we dont need delete_from_trade + + drop_of_lot = [] + # import pdb; pdb.set_trace() + for dev in devices: + # import pdb; pdb.set_trace() + if dev.trading_for_web(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: + drop_of_lot.append(dev) + dev.reset_owner() + + self.model = Revoke(action=lot.trade, user=g.user, devices=devices) + db.session.add(self.model) + lot.devices.difference_update(OrderedSet(drop_of_lot)) # class ConfirmRevokeView(ConfirmMixin): diff --git a/ereuse_devicehub/resources/action/views/views.py b/ereuse_devicehub/resources/action/views/views.py index 82e3f5e0..88c95438 100644 --- a/ereuse_devicehub/resources/action/views/views.py +++ b/ereuse_devicehub/resources/action/views/views.py @@ -235,6 +235,10 @@ class ActionView(View): revoke = trade_view.RevokeView(json, resource_def, self.schema) return revoke.post() + if json['type'] == 'ConfirmRevoke': + revoke = trade_view.RevokeView(json, resource_def, self.schema) + return revoke.post() + if json['type'] == 'RevokeDocument': revoke = trade_view.RevokeDocumentView(json, resource_def, self.schema) return revoke.post() diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index 3365e6cc..e60312a2 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -89,7 +89,6 @@ class Metrics(MetricsMix): trade['status_receiver_created'] = self.act.created return - # import pdb; pdb.set_trace() # necesitamos poder poner un cambio de estado de un trade mas antiguo que last_trade # lo mismo con confirm @@ -148,7 +147,8 @@ class Metrics(MetricsMix): if the action is one trade action, is possible than have a list of confirmations. Get the doble confirm for to know if this trade is confirmed or not. """ - if self.device.trading == 'TradeConfirmed': + # import pdb; pdb.set_trace() + if self.device.trading(self.act.lot) == 'TradeConfirmed': return True return False diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index b0d09848..842c009d 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -310,6 +310,80 @@ class Device(Thing): return history + @property + def tradings(self): + return {str(x.id): self.trading_for_web(x.lot) for x in self.actions if x.t == 'Trade'} + + def trading_for_web(self, lot): + """The trading state, or None if no Trade action has + ever been performed to this device. This extract the posibilities for to do. + This method is performed for show in the web.""" + if not hasattr(lot, 'trade'): + return + + Status = {0: 'Trade', + 1: 'Confirm', + 2: 'NeedConfirmation', + 3: 'TradeConfirmed', + 4: 'Revoke', + 5: 'NeedConfirmRevoke', + 6: 'RevokeConfirmed'} + + trade = lot.trade + user_from = trade.user_from + user_to = trade.user_to + user_from_confirm = False + user_to_confirm = False + user_from_revoke = False + user_to_revoke = False + status = 0 + + if not hasattr(trade, 'acceptances'): + return Status[status] + + for ac in self.actions: + if ac.t not in ['Confirm', 'Revoke']: + continue + + if ac.user not in [user_from, user_to]: + continue + + if ac.t == 'Confirm' and ac.action == trade: + if ac.user == user_from: + user_from_confirm = True + elif ac.user == user_to: + user_to_confirm = True + + if ac.t == 'Revoke' and ac.action == trade: + if ac.user == user_from: + user_from_revoke = True + elif ac.user == user_to: + user_to_revoke = True + + confirms = [user_from_confirm, user_to_confirm] + revokes = [user_from_revoke, user_to_revoke] + + if any(confirms): + status = 1 + if user_to_confirm and user_from == g.user: + status = 2 + if user_from_confirm and user_to == g.user: + status = 2 + + if all(confirms): + status = 3 + + if any(revokes): + status = 4 + if user_to_revoke and user_from == g.user: + status = 5 + if user_from_revoke and user_to == g.user: + status = 5 + if all(revokes): + status = 6 + + return Status[status] + def trading(self, lot): """The trading state, or None if no Trade action has ever been performed to this device. This extract the posibilities for to do""" @@ -330,30 +404,28 @@ class Device(Thing): user_from_revoke = False user_to_revoke = False status = 0 - confirms = {} - revokes = {} if not hasattr(trade, 'acceptances'): return Status[status] - acceptances = copy.copy(trade.acceptances) - acceptances = sorted(acceptances, key=lambda x: x.created) + for ac in self.actions: + if ac.t not in ['Confirm', 'Revoke']: + continue - for ac in acceptances: if ac.user not in [user_from, user_to]: continue - if ac.t == 'Confirm': + if ac.t == 'Confirm' and ac.action == trade: if ac.user == user_from: user_from_confirm = True elif ac.user == user_to: user_to_confirm = True - if ac.t == 'Revoke': + if ac.t == 'Revoke' and ac.action == trade: if ac.user == user_from: user_from_revoke = True elif ac.user == user_to: - user_to_revoke= True + user_to_revoke = True confirms = [user_from_confirm, user_to_confirm] revokes = [user_from_revoke, user_to_revoke] @@ -370,75 +442,6 @@ class Device(Thing): return Status[status] - def trading2(self): - """The trading state, or None if no Trade action has - ever been performed to this device. This extract the posibilities for to do""" - # trade = 'Trade' - confirm = 'Confirm' - need_confirm = 'NeedConfirmation' - double_confirm = 'TradeConfirmed' - revoke = 'Revoke' - revoke_pending = 'RevokePending' - confirm_revoke = 'ConfirmRevoke' - # revoke_confirmed = 'RevokeConfirmed' - - # return the correct status of trade depending of the user - - # #### CASES ##### - # User1 == owner of trade (This user have automatic Confirmation) - # ======================= - # if the last action is => only allow to do - # ========================================== - # Confirmation not User1 => Revoke - # Confirmation User1 => Revoke - # Revoke not User1 => ConfirmRevoke - # Revoke User1 => RevokePending - # RevokeConfirmation => RevokeConfirmed - # - # - # User2 == Not owner of trade - # ======================= - # if the last action is => only allow to do - # ========================================== - # Confirmation not User2 => Confirm - # Confirmation User2 => Revoke - # Revoke not User2 => ConfirmRevoke - # Revoke User2 => RevokePending - # RevokeConfirmation => RevokeConfirmed - - ac = self.last_action_trading - if not ac: - return - - first_owner = self.which_user_put_this_device_in_trace() - - if ac.type == confirm_revoke: - # can to do revoke_confirmed - return confirm_revoke - - if ac.type == revoke: - if ac.user == g.user: - # can todo revoke_pending - return revoke_pending - else: - # can to do confirm_revoke - return revoke - - if ac.type == confirm: - if not first_owner: - return - - if ac.user == first_owner: - if first_owner == g.user: - # can to do revoke - return confirm - else: - # can to do confirm - return need_confirm - else: - # can to do revoke - return double_confirm - @property def revoke(self): """If the actual trading state is an revoke action, this property show @@ -543,15 +546,16 @@ class Device(Thing): def which_user_put_this_device_in_trace(self): """which is the user than put this device in this trade""" actions = copy.copy(self.actions) - actions.sort(key=lambda x: x.created) actions.reverse() - last_ac = None # search the automatic Confirm for ac in actions: if ac.type == 'Trade': - return last_ac.user - if ac.type == 'Confirm': - last_ac = ac + # import pdb; pdb.set_trace() + action_device = [x.device for x in ac.actions_device if x.device == self][0] + if action_device.author: + return action_device.author + + return ac.author def change_owner(self, new_user): """util for change the owner one device""" diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index d9a658fe..bc18b995 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -1,7 +1,7 @@ import datetime from marshmallow import post_load, pre_load, fields as f -from marshmallow.fields import Boolean, Date, DateTime, Float, Integer, List, Str, String, UUID +from marshmallow.fields import Boolean, Date, DateTime, Float, Integer, List, Str, String, UUID, Dict from marshmallow.validate import Length, OneOf, Range from sqlalchemy.util import OrderedSet from stdnum import imei, meid @@ -50,12 +50,11 @@ class Device(Thing): description='The lots where this device is directly under.') rate = NestedOn('Rate', dump_only=True, description=m.Device.rate.__doc__) price = NestedOn('Price', dump_only=True, description=m.Device.price.__doc__) - # trading = EnumField(states.Trading, dump_only=True, description=m.Device.trading.__doc__) - trading = SanitizedStr(dump_only=True, description='') + tradings = Dict(dump_only=True, description='') physical = EnumField(states.Physical, dump_only=True, description=m.Device.physical.__doc__) - traking= EnumField(states.Traking, 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__) - revoke = UUID(dump_only=True) + revoke = UUID(dump_only=True) 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/lot/views.py b/ereuse_devicehub/resources/lot/views.py index d41f2008..12309888 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -305,6 +305,7 @@ def delete_from_trade(lot: Lot, ids: Set[int]): db.session.add(phantom_revoke) lot.devices.difference_update(without_confirms) + # TODO @cayop ?? we dont need this line lot.trade.devices = lot.devices return revoke diff --git a/tests/test_action.py b/tests/test_action.py index 888541f3..86e811e3 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1516,8 +1516,8 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient): 'type': 'Confirm', 'action': trade.id, 'devices': [ - snap1['device']['id'], - snap2['device']['id'], + snap1['device']['id'], + snap2['device']['id'], snap3['device']['id'], snap4['device']['id'], snap5['device']['id'], @@ -1535,7 +1535,7 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient): assert trade.devices[-1].actions[-1].user == trade.user_from assert len(trade.devices[0].actions) == n_actions - # The manager remove one device of the lot and automaticaly + # The manager remove one device of the lot and automaticaly # is create one revoke action device_10 = trade.devices[-1] lot, _ = user.delete({}, @@ -1554,31 +1554,28 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient): # the SCRAP confirms the revoke action request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device_10.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [ snap10['device']['id'] ] } user2.post(res=models.Action, data=request_confirm_revoke) - assert device_10.actions[-1].t == 'ConfirmRevoke' + assert device_10.actions[-1].t == 'Revoke' assert device_10.actions[-2].t == 'Revoke' # assert len(trade.lot.devices) == len(trade.devices) == 9 # assert not device_10 in trade.devices # check validation error request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device_10.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [ snap9['device']['id'] ] } - user2.post(res=models.Action, data=request_confirm_revoke, status=422) - - # The manager add again device_10 # assert len(trade.devices) == 9 lot, _ = user.post({}, @@ -1604,7 +1601,7 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient): assert device_10.actions[-1].user == trade.user_from assert device_10.actions[-2].t == 'Confirm' assert device_10.actions[-2].user == trade.user_to - assert device_10.actions[-3].t == 'ConfirmRevoke' + assert device_10.actions[-3].t == 'Revoke' # assert len(device_10.actions) == 13 @@ -1712,6 +1709,7 @@ def test_confirmRevoke(user: UserClient, user2: UserClient): assert len(trade.devices) == 10 # the SCRAP confirms the revoke action + import pdb; pdb.set_trace() request_confirm_revoke = { 'type': 'ConfirmRevoke', 'action': device_10.actions[-2].id, From 54977d432d481668b59e25cdf1b7342627f07cfe Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 11 Nov 2021 17:06:26 +0100 Subject: [PATCH 33/48] refactory in delete_from_trade function --- .../resources/action/views/trade.py | 67 +------------------ ereuse_devicehub/resources/device/models.py | 19 ++++-- ereuse_devicehub/resources/lot/views.py | 47 ++++++++++++- 3 files changed, 62 insertions(+), 71 deletions(-) diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 4aac48d4..842808ba 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -215,73 +215,12 @@ class RevokeView(ConfirmMixin): def validate(self, data): """All devices need to have the status of DoubleConfirmation.""" - ### check ### - if not data['devices']: + devices = data['devices'] + if not devices: raise ValidationError('Devices not exist.') lot = data['action'].lot - - revokeConfirmed = [] - for dev in data['devices']: - if dev.trading(lot) == 'RevokeConfirmed': - # this device is revoked before - revokeConfirmed.append(dev) - ### End check ### - - devices = {d for d in data['devices'] if d not in revokeConfirmed} - # self.model = delete_from_trade(lot, devices) - # TODO @cayop we dont need delete_from_trade - - drop_of_lot = [] - # import pdb; pdb.set_trace() - for dev in devices: - # import pdb; pdb.set_trace() - if dev.trading_for_web(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: - drop_of_lot.append(dev) - dev.reset_owner() - - self.model = Revoke(action=lot.trade, user=g.user, devices=devices) - db.session.add(self.model) - lot.devices.difference_update(OrderedSet(drop_of_lot)) - - -# class ConfirmRevokeView(ConfirmMixin): -# """Handler for manager the Confirmation register from post - -# request_confirm_revoke = { -# 'type': 'ConfirmRevoke', -# 'action': action_revoke.id, -# 'devices': [device_id] -# } - -# """ - -# Model = ConfirmRevoke - -# def validate(self, data): -# """All devices need to have the status of revoke.""" - -# if not data['action'].type == 'Revoke': -# txt = 'Error: this action is not a revoke action' -# ValidationError(txt) - -# lot = data['action'].lot -# for dev in data['devices']: -# if not dev.trading(lot) == 'Revoke': -# txt = 'Some of devices do not have revoke to confirm' -# ValidationError(txt) - -# devices = OrderedSet(data['devices']) -# data['devices'] = devices - -# # Change the owner for every devices -# # data['action'] == 'Revoke' - -# trade = data['action'].action -# for dev in devices: -# dev.reset_owner() - -# trade.lot.devices.difference_update(devices) + self.model = delete_from_trade(lot, devices) class ConfirmDocumentMixin(): diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 842c009d..e74cad0a 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -1,5 +1,6 @@ import pathlib import copy +import time from flask import g from contextlib import suppress from fractions import Fraction @@ -337,6 +338,7 @@ class Device(Thing): user_from_revoke = False user_to_revoke = False status = 0 + last_action = {'confirm': 0, 'revoke': 0} if not hasattr(trade, 'acceptances'): return Status[status] @@ -351,19 +353,29 @@ class Device(Thing): if ac.t == 'Confirm' and ac.action == trade: if ac.user == user_from: user_from_confirm = True + # import pdb; pdb.set_trace() + last_action['confirm'] = time.mktime(ac.created.timetuple()) + user_from_revoke, user_to_revoke = False, False elif ac.user == user_to: user_to_confirm = True + last_action['confirm'] = time.mktime(ac.created.timetuple()) + user_from_revoke, user_to_revoke = False, False if ac.t == 'Revoke' and ac.action == trade: if ac.user == user_from: user_from_revoke = True + last_action['revoke'] = time.mktime(ac.created.timetuple()) + user_from_confirm, user_to_confirm = False, False elif ac.user == user_to: user_to_revoke = True + last_action['revoke'] = time.mktime(ac.created.timetuple()) + user_from_confirm, user_to_confirm = False, False confirms = [user_from_confirm, user_to_confirm] revokes = [user_from_revoke, user_to_revoke] - if any(confirms): + confirm_vs_revoke = 'confirm' if last_action['confirm'] > last_action['revoke'] else 'revoke' + if any(confirms) and confirm_vs_revoke == 'confirm': status = 1 if user_to_confirm and user_from == g.user: status = 2 @@ -373,7 +385,7 @@ class Device(Thing): if all(confirms): status = 3 - if any(revokes): + if any(revokes) and confirm_vs_revoke == 'revoke': status = 4 if user_to_revoke and user_from == g.user: status = 5 @@ -550,8 +562,7 @@ class Device(Thing): # search the automatic Confirm for ac in actions: if ac.type == 'Trade': - # import pdb; pdb.set_trace() - action_device = [x.device for x in ac.actions_device if x.device == self][0] + action_device = [x for x in ac.actions_device if x.device == self][0] if action_device.author: return action_device.author diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 12309888..6ee86cdf 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -1,4 +1,5 @@ import uuid +from sqlalchemy.util import OrderedSet from collections import deque from enum import Enum from typing import Dict, List, Set, Union @@ -246,7 +247,8 @@ class LotDeviceView(LotBaseChildrenView): return if lot.trade: - return delete_from_trade(lot, ids) + devices = Device.query.filter(Device.id.in_(ids)).all() + return delete_from_trade(lot, devices) if not g.user == lot.owner: txt = 'This is not your lot' @@ -258,7 +260,46 @@ class LotDeviceView(LotBaseChildrenView): lot.devices.difference_update(devices) -def delete_from_trade(lot: Lot, ids: Set[int]): +def delete_from_trade(lot: Lot, devices: List): + users = [lot.trade.user_from.id, lot.trade.user_to.id] + if g.user.id not in users: + # theoretically this case is impossible + txt = 'This is not your trade' + raise ma.ValidationError(txt) + + drop_of_lot = [] + without_confirms = [] + for dev in devices: + if dev.trading_for_web(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: + drop_of_lot.append(dev) + dev.reset_owner() + + if lot.trade.confirm: + drop_of_lot.append(dev) + without_confirms.append(dev) + dev.reset_owner() + + + revoke = Revoke(action=lot.trade, user=g.user, devices=set(devices)) + db.session.add(revoke) + + if without_confirms: + phantom = lot.trade.user_to + if lot.trade.user_to == g.user: + phantom = lot.trade.user_from + + phantom_revoke = Revoke( + action=lot.trade, + user=phantom, + devices=set(without_confirms) + ) + db.session.add(phantom_revoke) + + lot.devices.difference_update(OrderedSet(drop_of_lot)) + return revoke + + +def delete_from_trade2(lot: Lot, ids: Set[int]): users = [lot.trade.user_from.id, lot.trade.user_to.id] if not g.user.id in users: # theoretically this case is impossible @@ -280,7 +321,7 @@ def delete_from_trade(lot: Lot, ids: Set[int]): # then can be revoked and deleted of the lot # Confirm of dev.trading mean that there are only one confirmation # and the first user than put this device in trade is the actual g.user - if dev.trading(lot) == 'Confirm': + if dev.trading(lot) == 'Confirm': without_confirms.add(dev) dev.reset_owner() From cef22f01cee0014829bf5fb336049ad6e68b4f19 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 11 Nov 2021 17:23:45 +0100 Subject: [PATCH 34/48] fixing deletr_from_trade --- ereuse_devicehub/resources/lot/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 6ee86cdf..521696f0 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -269,12 +269,13 @@ def delete_from_trade(lot: Lot, devices: List): drop_of_lot = [] without_confirms = [] + # import pdb; pdb.set_trace() for dev in devices: if dev.trading_for_web(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: drop_of_lot.append(dev) dev.reset_owner() - if lot.trade.confirm: + if not lot.trade.confirm: drop_of_lot.append(dev) without_confirms.append(dev) dev.reset_owner() From 872a0be866345a92148416d8c4e79dd22400bf0f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 11 Nov 2021 22:08:28 +0100 Subject: [PATCH 35/48] rebuild trading function --- ereuse_devicehub/resources/device/metrics.py | 5 +- ereuse_devicehub/resources/device/models.py | 139 ++++++++++++---- ereuse_devicehub/resources/lot/views.py | 1 - tests/test_action.py | 163 +++++++++++-------- tests/test_metrics.py | 11 +- 5 files changed, 210 insertions(+), 109 deletions(-) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index e60312a2..c9576fdf 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -147,10 +147,7 @@ class Metrics(MetricsMix): if the action is one trade action, is possible than have a list of confirmations. Get the doble confirm for to know if this trade is confirmed or not. """ - # import pdb; pdb.set_trace() - if self.device.trading(self.act.lot) == 'TradeConfirmed': - return True - return False + return self.device.trading(self.act.lot) def get_trade(self): """ diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index e74cad0a..0c3d03c7 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -330,6 +330,81 @@ class Device(Thing): 5: 'NeedConfirmRevoke', 6: 'RevokeConfirmed'} + trade = lot.trade + user_from = trade.user_from + user_to = trade.user_to + status = 0 + last_user = None + + if not hasattr(trade, 'acceptances'): + return Status[status] + + for ac in self.actions: + if ac.t not in ['Confirm', 'Revoke']: + continue + + if ac.user not in [user_from, user_to]: + continue + + if ac.t == 'Confirm' and ac.action == trade: + if status in [0, 6]: + status = 1 + last_user = ac.user + if ac.user == user_from and user_to == g.user: + status = 2 + if ac.user == user_to and user_from == g.user: + status = 2 + continue + + if status in [1, 2]: + if last_user != ac.user: + status = 3 + last_user = ac.user + continue + + if status in [4, 5]: + status = 3 + last_user = ac.user + continue + + if ac.t == 'Revoke' and ac.action == trade: + if status == 3: + status = 4 + last_user = ac.user + if ac.user == user_from and user_to == g.user: + status = 5 + if ac.user == user_to and user_from == g.user: + status = 5 + continue + + if status in [4, 5]: + if last_user != ac.user: + status = 6 + last_user = ac.user + continue + + if status in [1, 2]: + status = 6 + last_user = ac.user + continue + + return Status[status] + + def trading_for_web2(self, lot): + """The trading state, or None if no Trade action has + ever been performed to this device. This extract the posibilities for to do. + This method is performed for show in the web.""" + if not hasattr(lot, 'trade'): + return + + Status = {0: 'Trade', + 1: 'Confirm', + 2: 'NeedConfirmation', + 3: 'TradeConfirmed', + 4: 'Revoke', + 5: 'NeedConfirmRevoke', + 6: 'RevokeConfirmed'} + trade = lot.trade user_from = trade.user_from user_to = trade.user_to @@ -353,7 +428,6 @@ class Device(Thing): if ac.t == 'Confirm' and ac.action == trade: if ac.user == user_from: user_from_confirm = True - # import pdb; pdb.set_trace() last_action['confirm'] = time.mktime(ac.created.timetuple()) user_from_revoke, user_to_revoke = False, False elif ac.user == user_to: @@ -398,24 +472,22 @@ class Device(Thing): def trading(self, lot): """The trading state, or None if no Trade action has - ever been performed to this device. This extract the posibilities for to do""" + ever been performed to this device. This extract the posibilities for to do. + This method is performed for show in the web.""" if not hasattr(lot, 'trade'): return Status = {0: 'Trade', - 1: 'Confirm', - 2: 'TradeConfirmed', - 3: 'Revoke', - 4: 'RevokeConfirmed'} + 2: 'NeedConfirmation', + 3: 'TradeConfirmed', + 5: 'NeedConfirmRevoke', + 6: 'RevokeConfirmed'} trade = lot.trade user_from = trade.user_from user_to = trade.user_to - user_from_confirm = False - user_to_confirm = False - user_from_revoke = False - user_to_revoke = False status = 0 + last_user = None if not hasattr(trade, 'acceptances'): return Status[status] @@ -428,29 +500,38 @@ class Device(Thing): continue if ac.t == 'Confirm' and ac.action == trade: - if ac.user == user_from: - user_from_confirm = True - elif ac.user == user_to: - user_to_confirm = True + if status in [0, 6]: + status = 2 + last_user = ac.user + continue + + if status == 2: + if last_user != ac.user: + status = 3 + last_user = ac.user + continue + + if status == 5: + status = 3 + last_user = ac.user + continue if ac.t == 'Revoke' and ac.action == trade: - if ac.user == user_from: - user_from_revoke = True - elif ac.user == user_to: - user_to_revoke = True + if status == 3: + status = 5 + last_user = ac.user + continue - confirms = [user_from_confirm, user_to_confirm] - revokes = [user_from_revoke, user_to_revoke] + if status == 5: + if last_user != ac.user: + status = 6 + last_user = ac.user + continue - if any(confirms): - status = 1 - if all(confirms): - status = 2 - - if any(revokes): - status = 3 - if all(revokes): - status = 4 + if status == 2: + status = 6 + last_user = ac.user + continue return Status[status] diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 521696f0..6a7b7f79 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -269,7 +269,6 @@ def delete_from_trade(lot: Lot, devices: List): drop_of_lot = [] without_confirms = [] - # import pdb; pdb.set_trace() for dev in devices: if dev.trading_for_web(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: drop_of_lot.append(dev) diff --git a/tests/test_action.py b/tests/test_action.py index 86e811e3..4d38131a 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -328,7 +328,7 @@ def test_outgoinlot_status_actions(action_model: models.Action, user: UserClient assert device['actions'][-1]['id'] == action['id'] assert action['author']['id'] == user.user['id'] - assert action['rol_user']['id'] == user.user['id'] + assert action['rol_user']['id'] == user2.user['id'] @pytest.mark.mvp @@ -386,14 +386,14 @@ def test_history_status_actions(user: UserClient, user2: UserClient): assert action['id'] == str(device.status.id) assert device.status.t == models.Recycling.t assert [action['id']] == [str(ac.id) for ac in device.history_status] - + # Case 2 action2 = {'type': models.Refurbish.t, 'devices': [device.id]} action2, _ = user.post(action2, res=models.Action) assert action2['id'] == str(device.status.id) assert device.status.t == models.Refurbish.t assert [action2['id']] == [str(ac.id) for ac in device.history_status] - + # Case 3 lot, _ = user.post({'name': 'MyLot'}, res=Lot) user.post({}, @@ -1709,7 +1709,6 @@ def test_confirmRevoke(user: UserClient, user2: UserClient): assert len(trade.devices) == 10 # the SCRAP confirms the revoke action - import pdb; pdb.set_trace() request_confirm_revoke = { 'type': 'ConfirmRevoke', 'action': device_10.actions[-2].id, @@ -1754,7 +1753,7 @@ def test_trade_case1(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -1770,31 +1769,23 @@ def test_trade_case1(user: UserClient, user2: UserClient): user.post(res=models.Action, data=request_post) trade = models.Trade.query.one() - lot, _ = user.post({}, - res=Lot, - item='{}/devices'.format(lot['id']), - query=devices[-1:]) + lot = trade.lot + device = trade.devices[0] - device1, device2 = trade.devices + assert device.actions[-2].t == 'Trade' + assert device.actions[-1].t == 'Confirm' + assert device.actions[-1].user == trade.user_to - assert device1.actions[-2].t == 'Trade' - assert device1.actions[-1].t == 'Confirm' - assert device1.actions[-1].user == trade.user_to - assert device2.actions[-2].t == 'Trade' - assert device2.actions[-1].t == 'Confirm' - assert device2.actions[-1].user == trade.user_to + user.delete({}, + res=Lot, + item='{}/devices'.format(lot.id), + query=devices[:-1], status=200) - lot, _ = user.delete({}, - res=Lot, - item='{}/devices'.format(lot['id']), - query=devices, status=200) - - assert device1.actions[-2].t == 'Revoke' - assert device1.actions[-1].t == 'ConfirmRevoke' - assert device1.actions[-1].user == trade.user_to - assert device2.actions[-2].t == 'Revoke' - assert device2.actions[-1].t == 'ConfirmRevoke' - assert device2.actions[-1].user == trade.user_to + assert device not in trade.lot.devices + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.actions[-2].t == 'Confirm' + assert device.actions[-1].t == 'Revoke' + assert device.actions[-1].user == trade.user_to @pytest.mark.mvp @@ -1837,6 +1828,7 @@ def test_trade_case2(user: UserClient, user2: UserClient): device1, device2 = trade.devices + # import pdb; pdb.set_trace() assert device1.actions[-2].t == 'Trade' assert device1.actions[-1].t == 'Confirm' assert device1.actions[-1].user == trade.user_to @@ -1853,12 +1845,13 @@ def test_trade_case2(user: UserClient, user2: UserClient): # Normal revoke user.post(res=models.Action, data=request_revoke) - assert device1.actions[-2].t == 'Revoke' - assert device1.actions[-1].t == 'ConfirmRevoke' + assert device1.actions[-2].t == 'Confirm' + assert device1.actions[-1].t == 'Revoke' assert device1.actions[-1].user == trade.user_to - assert device2.actions[-2].t == 'Revoke' - assert device2.actions[-1].t == 'ConfirmRevoke' + assert device2.actions[-2].t == 'Confirm' + assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_to + assert device1.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -1866,7 +1859,6 @@ def test_trade_case2(user: UserClient, user2: UserClient): def test_trade_case3(user: UserClient, user2: UserClient): # the pRp (manatest_usecase_confirmationger) creates a temporary lot lot, _ = user.post({'name': 'MyLot'}, res=Lot) - # The manager add 7 device into the lot snap1, _ = user.post(file('basic.snapshot'), res=models.Snapshot) snap2, _ = user2.post(file('acer.happy.battery.snapshot'), res=models.Snapshot) @@ -1878,7 +1870,7 @@ def test_trade_case3(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:-1]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the CRAP to confirm it request_post = { 'type': 'Trade', @@ -1913,9 +1905,10 @@ def test_trade_case3(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[-1:], status=200) - assert device2.actions[-2].t == 'Revoke' - assert device2.actions[-1].t == 'ConfirmRevoke' + assert device2.actions[-2].t == 'Confirm' + assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_from + assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -1977,9 +1970,10 @@ def test_trade_case4(user: UserClient, user2: UserClient): assert device1.actions[-2].t == 'Trade' assert device1.actions[-1].t == 'Confirm' assert device1.actions[-1].user == trade.user_to - assert device2.actions[-2].t == 'Revoke' - assert device2.actions[-1].t == 'ConfirmRevoke' + assert device2.actions[-2].t == 'Confirm' + assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_from + assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2034,8 +2028,8 @@ def test_trade_case5(user: UserClient, user2: UserClient): assert device2.actions[-1].user == trade.user_from request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device2.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device2.id], } @@ -2043,8 +2037,9 @@ def test_trade_case5(user: UserClient, user2: UserClient): user.post(res=models.Action, data=request_confirm_revoke) assert device2.actions[-2].t == 'Revoke' - assert device2.actions[-1].t == 'ConfirmRevoke' + assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_to + assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2104,8 +2099,8 @@ def test_trade_case6(user: UserClient, user2: UserClient): assert device2.actions[-1].user == trade.user_to request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device2.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device2.id], } @@ -2113,8 +2108,9 @@ def test_trade_case6(user: UserClient, user2: UserClient): user2.post(res=models.Action, data=request_confirm_revoke) assert device2.actions[-2].t == 'Revoke' - assert device2.actions[-1].t == 'ConfirmRevoke' + assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_from + assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2156,6 +2152,7 @@ def test_trade_case7(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_confirm) + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' lot, _ = user.delete({}, res=Lot, @@ -2163,14 +2160,14 @@ def test_trade_case7(user: UserClient, user2: UserClient): query=devices, status=200) request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user2.post(res=models.Action, data=request_confirm_revoke) - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_from assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_to @@ -2180,6 +2177,7 @@ def test_trade_case7(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_to assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2221,6 +2219,7 @@ def test_trade_case8(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_confirm) + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' request_revoke = { 'type': 'Revoke', @@ -2232,14 +2231,14 @@ def test_trade_case8(user: UserClient, user2: UserClient): user.post(res=models.Action, data=request_revoke) request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user2.post(res=models.Action, data=request_confirm_revoke) - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_from assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_to @@ -2249,6 +2248,7 @@ def test_trade_case8(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_to assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2301,6 +2301,7 @@ def test_trade_case9(user: UserClient, user2: UserClient): # Normal revoke user.post(res=models.Action, data=request_confirm) + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' assert device.owner == trade.user_to @@ -2310,8 +2311,8 @@ def test_trade_case9(user: UserClient, user2: UserClient): query=devices[-1:], status=200) request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } @@ -2319,7 +2320,7 @@ def test_trade_case9(user: UserClient, user2: UserClient): assert device.owner == trade.user_from - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_from @@ -2329,6 +2330,7 @@ def test_trade_case9(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_from assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2372,6 +2374,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): device1, device = trade.devices assert device.owner == trade.user_from + # assert device.trading_for_web(trade.lot) == 'Confirm' request_confirm = { 'type': 'Confirm', @@ -2381,6 +2384,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): # Normal confirm user.post(res=models.Action, data=request_confirm) + # assert device.trading_for_web(trade.lot) == 'TradeConfirmed' assert device.owner == trade.user_to @@ -2392,18 +2396,18 @@ def test_trade_case10(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_revoke) + assert device.trading_for_web(trade.lot) == 'Revoke' request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user.post(res=models.Action, data=request_confirm_revoke) assert device.owner == trade.user_from - - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_from @@ -2413,6 +2417,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_from assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2449,6 +2454,7 @@ def test_trade_case11(user: UserClient, user2: UserClient): trade = models.Trade.query.one() device1, device = trade.devices + assert device.trading_for_web(trade.lot) == 'Confirm' request_confirm = { 'type': 'Confirm', @@ -2457,21 +2463,24 @@ def test_trade_case11(user: UserClient, user2: UserClient): } user2.post(res=models.Action, data=request_confirm) + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' lot, _ = user2.delete({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices[-1:], status=200) + assert device.trading_for_web(trade.lot) == 'Revoke' request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user.post(res=models.Action, data=request_confirm_revoke) + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_from @@ -2517,6 +2526,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): trade = models.Trade.query.one() device1, device = trade.devices + assert device.trading_for_web(trade.lot) == 'Confirm' # Normal confirm request_confirm = { @@ -2526,6 +2536,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): } user2.post(res=models.Action, data=request_confirm) + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' request_revoke = { 'type': 'Revoke', @@ -2535,16 +2546,18 @@ def test_trade_case12(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_revoke) + assert device.trading_for_web(trade.lot) == 'Revoke' request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user.post(res=models.Action, data=request_confirm_revoke) + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_from @@ -2595,6 +2608,8 @@ def test_trade_case13(user: UserClient, user2: UserClient): query=devices[-1:]) device1, device = trade.devices + assert device1.trading_for_web(trade.lot) == 'NeedConfirmation' + assert device.trading_for_web(trade.lot) == 'Confirm' request_confirm = { 'type': 'Confirm', @@ -2603,21 +2618,26 @@ def test_trade_case13(user: UserClient, user2: UserClient): } user.post(res=models.Action, data=request_confirm) + assert device1.trading_for_web(trade.lot) == 'Confirm' + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' lot, _ = user.delete({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices[-1:], status=200) + assert device1.trading_for_web(trade.lot) == 'Confirm' + assert device.trading_for_web(trade.lot) == 'Revoke' request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user2.post(res=models.Action, data=request_confirm_revoke) + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_from assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_to @@ -2668,6 +2688,8 @@ def test_trade_case14(user: UserClient, user2: UserClient): query=devices[-1:]) device1, device = trade.devices + assert device1.trading_for_web(trade.lot) == 'NeedConfirmation' + assert device.trading_for_web(trade.lot) == 'Confirm' # Normal confirm request_confirm = { @@ -2677,6 +2699,7 @@ def test_trade_case14(user: UserClient, user2: UserClient): } user.post(res=models.Action, data=request_confirm) + assert device.trading_for_web(trade.lot) == 'TradeConfirmed' request_revoke = { 'type': 'Revoke', @@ -2686,16 +2709,18 @@ def test_trade_case14(user: UserClient, user2: UserClient): # Normal revoke user.post(res=models.Action, data=request_revoke) + assert device.trading_for_web(trade.lot) == 'Revoke' request_confirm_revoke = { - 'type': 'ConfirmRevoke', - 'action': device.actions[-1].id, + 'type': 'Revoke', + 'action': trade.id, 'devices': [device.id], } user2.post(res=models.Action, data=request_confirm_revoke) + assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' - assert device.actions[-1].t == 'ConfirmRevoke' + assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_from assert device.actions[-2].t == 'Revoke' assert device.actions[-2].user == trade.user_to @@ -2716,7 +2741,7 @@ def test_action_web_erase(user: UserClient, client: Client): hash3 = hashlib.sha3_256(bfile.read()).hexdigest() snap, _ = user.post(file('acer.happy.battery.snapshot'), res=models.Snapshot) request = {'type': 'DataWipe', 'devices': [snap['device']['id']], 'name': 'borrado universal', 'severity': 'Info', 'description': 'nada que describir', 'url': 'http://www.google.com/', 'documentId': '33', 'endTime': '2021-07-07T22:00:00.000Z', 'filename': 'Certificado de borrado1.pdf', 'hash': hash3, 'success': 1, 'software': "Blanco"} - + user.post(res=models.Action, data=request) action = models.DataWipe.query.one() for dev in action.devices: diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 6ad7a516..cab985d1 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -181,14 +181,13 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): query=[('filter', {'type': ['Computer']})]) body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;' - body1_lenovo += 'foo2@foo.com;Supplier;False;Use;;' + body1_lenovo += 'foo2@foo.com;Supplier;NeedConfirmation;Use;;' body2_lenovo = ';;0;0;Trade;0;0\n' body1_acer = 'J2MA2;laptop-acer-aohappy-lusea0d010038879a01601-00:26:c7:8e:cb:8c;;Trade;' - body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;False;;;;;0;' + body1_acer += 'foo@foo.com;foo2@foo.com;Supplier;NeedConfirmation;;;;;0;' body2_acer = ';;0;0;Trade;0;4692.0\n' - # import pdb; pdb.set_trace() assert body1_lenovo in csv_str assert body2_lenovo in csv_str assert body1_acer in csv_str @@ -203,7 +202,7 @@ def test_complet_metrics_with_trade(user: UserClient, user2: UserClient): query=[('filter', {'type': ['Computer']})]) body1_lenovo = 'O48N2;desktop-lenovo-9644w8n-0169622-00:1a:6b:5e:7f:10;;Trade;foo@foo.com;' - body1_lenovo += 'foo2@foo.com;Supplier;False;Use;Use;' + body1_lenovo += 'foo2@foo.com;Supplier;NeedConfirmation;Use;Use;' body2_lenovo = ';;0;0;Trade;0;0\n' body2_acer = ';;0;0;Trade;0;4692.0\n' @@ -353,8 +352,8 @@ def test_bug_trade_confirmed(user: UserClient, user2: UserClient): accept='text/csv', query=[('filter', {'type': ['Computer']})]) - body_not_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;False;" - body_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;True;" + body_not_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;NeedConfirmation;" + body_confirmed = "Trade;foo2@foo.com;foo@foo.com;Receiver;TradeConfirmed;" assert body_not_confirmed in csv_not_confirmed assert body_confirmed in csv_confirmed From e326e8ccdf343e185b4131224d7f112caf323ac4 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 11 Nov 2021 22:21:58 +0100 Subject: [PATCH 36/48] fixing revoke when the device is in one future trade --- ereuse_devicehub/resources/lot/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 6a7b7f79..961ab812 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -267,6 +267,12 @@ def delete_from_trade(lot: Lot, devices: List): txt = 'This is not your trade' raise ma.ValidationError(txt) + # we need lock the action revoke for devices than travel for futures trades + for dev in devices: + if dev.owner not in users: + txt = 'This is not your device' + raise ma.ValidationError(txt) + drop_of_lot = [] without_confirms = [] for dev in devices: From 1279180700051758f4e245064df714f54c7c3c2c Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 11 Nov 2021 22:50:07 +0100 Subject: [PATCH 37/48] fixing confirms --- .../resources/action/views/trade.py | 14 ++--- ereuse_devicehub/resources/lot/views.py | 57 +------------------ 2 files changed, 9 insertions(+), 62 deletions(-) diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 842808ba..242b32ba 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -181,17 +181,17 @@ class ConfirmView(ConfirmMixin): then remove the list this device of the list of devices of this action """ real_devices = [] + trade = data['action'] + lot = trade.lot for dev in data['devices']: - ac = dev.last_action_trading - if ac.type == Confirm.t and not ac.user == g.user: - real_devices.append(dev) - - data['devices'] = OrderedSet(real_devices) + if dev.trading(lot) not in ['NeedConfirmation', 'NeedConfirmRevoke']: + raise ValidationError('Some devices not possible confirm.') # Change the owner for every devices for dev in data['devices']: - user_to = data['action'].user_to - dev.change_owner(user_to) + if dev.trading_for_web(lot) == 'NeedConfirmation': + user_to = data['action'].user_to + dev.change_owner(user_to) class RevokeView(ConfirmMixin): diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 961ab812..85a4f7a3 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -261,8 +261,8 @@ class LotDeviceView(LotBaseChildrenView): def delete_from_trade(lot: Lot, devices: List): - users = [lot.trade.user_from.id, lot.trade.user_to.id] - if g.user.id not in users: + users = [lot.trade.user_from, lot.trade.user_to] + if g.user not in users: # theoretically this case is impossible txt = 'This is not your trade' raise ma.ValidationError(txt) @@ -303,56 +303,3 @@ def delete_from_trade(lot: Lot, devices: List): lot.devices.difference_update(OrderedSet(drop_of_lot)) return revoke - - -def delete_from_trade2(lot: Lot, ids: Set[int]): - users = [lot.trade.user_from.id, lot.trade.user_to.id] - if not g.user.id in users: - # theoretically this case is impossible - txt = 'This is not your trade' - raise ma.ValidationError(txt) - - devices = set(Device.query.filter(Device.id.in_(ids)).filter( - Device.owner_id.in_(users))) - - # Now we need to know which devices we need extract of the lot - without_confirms = set() # set of devs without confirms of user2 - - # if the trade need confirmation, then extract all devs than - # have only one confirmation and is from the same user than try to do - # now the revoke action - if lot.trade.confirm: - for dev in devices: - # if have only one confirmation - # then can be revoked and deleted of the lot - # Confirm of dev.trading mean that there are only one confirmation - # and the first user than put this device in trade is the actual g.user - if dev.trading(lot) == 'Confirm': - without_confirms.add(dev) - dev.reset_owner() - - # we need to mark one revoke for every devs - revoke = Revoke(action=lot.trade, user=g.user, devices=devices) - db.session.add(revoke) - - if not lot.trade.confirm: - # if the trade is with phantom account - without_confirms = devices - - if without_confirms: - phantom = lot.trade.user_to - if lot.trade.user_to == g.user: - phantom = lot.trade.user_from - - phantom_revoke = Revoke( - action=lot.trade, - user=phantom, - devices=without_confirms - ) - db.session.add(phantom_revoke) - - lot.devices.difference_update(without_confirms) - # TODO @cayop ?? we dont need this line - lot.trade.devices = lot.devices - - return revoke From 8e47af8e27ba23ca8ea5ad429f3e0bd09ce561a1 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 12 Nov 2021 10:00:43 +0100 Subject: [PATCH 38/48] refactoring trading and trading for web --- .../resources/action/views/trade.py | 4 +- ereuse_devicehub/resources/device/metrics.py | 2 +- ereuse_devicehub/resources/device/models.py | 158 ++---------------- ereuse_devicehub/resources/lot/views.py | 5 +- tests/test_action.py | 1 - 5 files changed, 15 insertions(+), 155 deletions(-) diff --git a/ereuse_devicehub/resources/action/views/trade.py b/ereuse_devicehub/resources/action/views/trade.py index 242b32ba..87a5dc81 100644 --- a/ereuse_devicehub/resources/action/views/trade.py +++ b/ereuse_devicehub/resources/action/views/trade.py @@ -184,12 +184,12 @@ class ConfirmView(ConfirmMixin): trade = data['action'] lot = trade.lot for dev in data['devices']: - if dev.trading(lot) not in ['NeedConfirmation', 'NeedConfirmRevoke']: + if dev.trading(lot, simple=True) not in ['NeedConfirmation', 'NeedConfirmRevoke']: raise ValidationError('Some devices not possible confirm.') # Change the owner for every devices for dev in data['devices']: - if dev.trading_for_web(lot) == 'NeedConfirmation': + if dev.trading(lot) == 'NeedConfirmation': user_to = data['action'].user_to dev.change_owner(user_to) diff --git a/ereuse_devicehub/resources/device/metrics.py b/ereuse_devicehub/resources/device/metrics.py index c9576fdf..f9399f95 100644 --- a/ereuse_devicehub/resources/device/metrics.py +++ b/ereuse_devicehub/resources/device/metrics.py @@ -147,7 +147,7 @@ class Metrics(MetricsMix): if the action is one trade action, is possible than have a list of confirmations. Get the doble confirm for to know if this trade is confirmed or not. """ - return self.device.trading(self.act.lot) + return self.device.trading(self.act.lot, simple=True) def get_trade(self): """ diff --git a/ereuse_devicehub/resources/device/models.py b/ereuse_devicehub/resources/device/models.py index 0c3d03c7..e7297fcd 100644 --- a/ereuse_devicehub/resources/device/models.py +++ b/ereuse_devicehub/resources/device/models.py @@ -313,12 +313,13 @@ class Device(Thing): @property def tradings(self): - return {str(x.id): self.trading_for_web(x.lot) for x in self.actions if x.t == 'Trade'} + return {str(x.id): self.trading(x.lot) for x in self.actions if x.t == 'Trade'} - def trading_for_web(self, lot): + def trading(self, lot, simple=None): """The trading state, or None if no Trade action has ever been performed to this device. This extract the posibilities for to do. - This method is performed for show in the web.""" + This method is performed for show in the web. + If you need to do one simple and generic response you can put simple=True for that.""" if not hasattr(lot, 'trade'): return @@ -348,6 +349,9 @@ class Device(Thing): if ac.t == 'Confirm' and ac.action == trade: if status in [0, 6]: + if simple: + status = 2 + continue status = 1 last_user = ac.user if ac.user == user_from and user_to == g.user: @@ -369,6 +373,9 @@ class Device(Thing): if ac.t == 'Revoke' and ac.action == trade: if status == 3: + if simple: + status = 5 + continue status = 4 last_user = ac.user if ac.user == user_from and user_to == g.user: @@ -390,151 +397,6 @@ class Device(Thing): return Status[status] - def trading_for_web2(self, lot): - """The trading state, or None if no Trade action has - ever been performed to this device. This extract the posibilities for to do. - This method is performed for show in the web.""" - if not hasattr(lot, 'trade'): - return - - Status = {0: 'Trade', - 1: 'Confirm', - 2: 'NeedConfirmation', - 3: 'TradeConfirmed', - 4: 'Revoke', - 5: 'NeedConfirmRevoke', - 6: 'RevokeConfirmed'} - - trade = lot.trade - user_from = trade.user_from - user_to = trade.user_to - user_from_confirm = False - user_to_confirm = False - user_from_revoke = False - user_to_revoke = False - status = 0 - last_action = {'confirm': 0, 'revoke': 0} - - if not hasattr(trade, 'acceptances'): - return Status[status] - - for ac in self.actions: - if ac.t not in ['Confirm', 'Revoke']: - continue - - if ac.user not in [user_from, user_to]: - continue - - if ac.t == 'Confirm' and ac.action == trade: - if ac.user == user_from: - user_from_confirm = True - last_action['confirm'] = time.mktime(ac.created.timetuple()) - user_from_revoke, user_to_revoke = False, False - elif ac.user == user_to: - user_to_confirm = True - last_action['confirm'] = time.mktime(ac.created.timetuple()) - user_from_revoke, user_to_revoke = False, False - - if ac.t == 'Revoke' and ac.action == trade: - if ac.user == user_from: - user_from_revoke = True - last_action['revoke'] = time.mktime(ac.created.timetuple()) - user_from_confirm, user_to_confirm = False, False - elif ac.user == user_to: - user_to_revoke = True - last_action['revoke'] = time.mktime(ac.created.timetuple()) - user_from_confirm, user_to_confirm = False, False - - confirms = [user_from_confirm, user_to_confirm] - revokes = [user_from_revoke, user_to_revoke] - - confirm_vs_revoke = 'confirm' if last_action['confirm'] > last_action['revoke'] else 'revoke' - if any(confirms) and confirm_vs_revoke == 'confirm': - status = 1 - if user_to_confirm and user_from == g.user: - status = 2 - if user_from_confirm and user_to == g.user: - status = 2 - - if all(confirms): - status = 3 - - if any(revokes) and confirm_vs_revoke == 'revoke': - status = 4 - if user_to_revoke and user_from == g.user: - status = 5 - if user_from_revoke and user_to == g.user: - status = 5 - if all(revokes): - status = 6 - - return Status[status] - - def trading(self, lot): - """The trading state, or None if no Trade action has - ever been performed to this device. This extract the posibilities for to do. - This method is performed for show in the web.""" - if not hasattr(lot, 'trade'): - return - - Status = {0: 'Trade', - 2: 'NeedConfirmation', - 3: 'TradeConfirmed', - 5: 'NeedConfirmRevoke', - 6: 'RevokeConfirmed'} - - trade = lot.trade - user_from = trade.user_from - user_to = trade.user_to - status = 0 - last_user = None - - if not hasattr(trade, 'acceptances'): - return Status[status] - - for ac in self.actions: - if ac.t not in ['Confirm', 'Revoke']: - continue - - if ac.user not in [user_from, user_to]: - continue - - if ac.t == 'Confirm' and ac.action == trade: - if status in [0, 6]: - status = 2 - last_user = ac.user - continue - - if status == 2: - if last_user != ac.user: - status = 3 - last_user = ac.user - continue - - if status == 5: - status = 3 - last_user = ac.user - continue - - if ac.t == 'Revoke' and ac.action == trade: - if status == 3: - status = 5 - last_user = ac.user - continue - - if status == 5: - if last_user != ac.user: - status = 6 - last_user = ac.user - continue - - if status == 2: - status = 6 - last_user = ac.user - continue - - return Status[status] - @property def revoke(self): """If the actual trading state is an revoke action, this property show diff --git a/ereuse_devicehub/resources/lot/views.py b/ereuse_devicehub/resources/lot/views.py index 85a4f7a3..dce6af62 100644 --- a/ereuse_devicehub/resources/lot/views.py +++ b/ereuse_devicehub/resources/lot/views.py @@ -231,7 +231,7 @@ class LotDeviceView(LotBaseChildrenView): return devices = set(Device.query.filter(Device.id.in_(ids)).filter( - Device.owner==g.user)) + Device.owner == g.user)) lot.devices.update(devices) @@ -276,7 +276,7 @@ def delete_from_trade(lot: Lot, devices: List): drop_of_lot = [] without_confirms = [] for dev in devices: - if dev.trading_for_web(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: + if dev.trading(lot) in ['NeedConfirmation', 'Confirm', 'NeedConfirmRevoke']: drop_of_lot.append(dev) dev.reset_owner() @@ -285,7 +285,6 @@ def delete_from_trade(lot: Lot, devices: List): without_confirms.append(dev) dev.reset_owner() - revoke = Revoke(action=lot.trade, user=g.user, devices=set(devices)) db.session.add(revoke) diff --git a/tests/test_action.py b/tests/test_action.py index 4d38131a..f37d70e0 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1828,7 +1828,6 @@ def test_trade_case2(user: UserClient, user2: UserClient): device1, device2 = trade.devices - # import pdb; pdb.set_trace() assert device1.actions[-2].t == 'Trade' assert device1.actions[-1].t == 'Confirm' assert device1.actions[-1].user == trade.user_to From 37c410bc3663fd0464c23e31aed4da549410d2ff Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 12 Nov 2021 17:46:39 +0100 Subject: [PATCH 39/48] fixing confirms tests --- tests/test_action.py | 85 ++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/tests/test_action.py b/tests/test_action.py index f37d70e0..0e339c6d 100644 --- a/tests/test_action.py +++ b/tests/test_action.py @@ -1396,6 +1396,7 @@ def test_confirm_revoke(user: UserClient, user2: UserClient): user.post(res=models.Action, data=request_post) trade = models.Trade.query.one() + device = trade.devices[0] request_confirm = { 'type': 'Confirm', @@ -1416,9 +1417,10 @@ def test_confirm_revoke(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_revoke) - # You can not to do one confirmation next of one revoke - user2.post(res=models.Action, data=request_confirm, status=422) - assert len(trade.acceptances) == 3 + # You can to do one confirmation next of one revoke + user2.post(res=models.Action, data=request_confirm) + assert len(trade.acceptances) == 4 + assert device.trading(trade.lot) == "TradeConfirmed" @pytest.mark.mvp @@ -1455,7 +1457,7 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient): item='{}/devices'.format(lot['id']), query=devices[:7]) - # the manager shares the temporary lot with the SCRAP as an incoming lot + # the manager shares the temporary lot with the SCRAP as an incoming lot # for the SCRAP to confirm it request_post = { 'type': 'Trade', @@ -1516,9 +1518,6 @@ def test_usecase_confirmation(user: UserClient, user2: UserClient): 'type': 'Confirm', 'action': trade.id, 'devices': [ - snap1['device']['id'], - snap2['device']['id'], - snap3['device']['id'], snap4['device']['id'], snap5['device']['id'], snap6['device']['id'], @@ -1782,7 +1781,7 @@ def test_trade_case1(user: UserClient, user2: UserClient): query=devices[:-1], status=200) assert device not in trade.lot.devices - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' assert device.actions[-2].t == 'Confirm' assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to @@ -1850,7 +1849,7 @@ def test_trade_case2(user: UserClient, user2: UserClient): assert device2.actions[-2].t == 'Confirm' assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_to - assert device1.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device1.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -1907,7 +1906,7 @@ def test_trade_case3(user: UserClient, user2: UserClient): assert device2.actions[-2].t == 'Confirm' assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_from - assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device2.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -1972,7 +1971,7 @@ def test_trade_case4(user: UserClient, user2: UserClient): assert device2.actions[-2].t == 'Confirm' assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_from - assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device2.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2038,7 +2037,7 @@ def test_trade_case5(user: UserClient, user2: UserClient): assert device2.actions[-2].t == 'Revoke' assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_to - assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device2.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2109,7 +2108,7 @@ def test_trade_case6(user: UserClient, user2: UserClient): assert device2.actions[-2].t == 'Revoke' assert device2.actions[-1].t == 'Revoke' assert device2.actions[-1].user == trade.user_from - assert device2.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device2.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2151,7 +2150,7 @@ def test_trade_case7(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_confirm) - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device.trading(trade.lot) == 'TradeConfirmed' lot, _ = user.delete({}, res=Lot, @@ -2176,7 +2175,7 @@ def test_trade_case7(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_to assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2218,7 +2217,7 @@ def test_trade_case8(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_confirm) - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device.trading(trade.lot) == 'TradeConfirmed' request_revoke = { 'type': 'Revoke', @@ -2247,7 +2246,7 @@ def test_trade_case8(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_to assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2300,7 +2299,7 @@ def test_trade_case9(user: UserClient, user2: UserClient): # Normal revoke user.post(res=models.Action, data=request_confirm) - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device.trading(trade.lot) == 'TradeConfirmed' assert device.owner == trade.user_to @@ -2329,7 +2328,7 @@ def test_trade_case9(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_from assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2373,7 +2372,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): device1, device = trade.devices assert device.owner == trade.user_from - # assert device.trading_for_web(trade.lot) == 'Confirm' + # assert device.trading(trade.lot) == 'Confirm' request_confirm = { 'type': 'Confirm', @@ -2383,7 +2382,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): # Normal confirm user.post(res=models.Action, data=request_confirm) - # assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + # assert device.trading(trade.lot) == 'TradeConfirmed' assert device.owner == trade.user_to @@ -2395,7 +2394,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_revoke) - assert device.trading_for_web(trade.lot) == 'Revoke' + assert device.trading(trade.lot) == 'Revoke' request_confirm_revoke = { 'type': 'Revoke', @@ -2416,7 +2415,7 @@ def test_trade_case10(user: UserClient, user2: UserClient): assert device.actions[-4].user == trade.user_from assert device.actions[-5].t == 'Trade' assert device.actions[-5].author == trade.user_to - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' @pytest.mark.mvp @@ -2453,7 +2452,7 @@ def test_trade_case11(user: UserClient, user2: UserClient): trade = models.Trade.query.one() device1, device = trade.devices - assert device.trading_for_web(trade.lot) == 'Confirm' + assert device.trading(trade.lot) == 'Confirm' request_confirm = { 'type': 'Confirm', @@ -2462,13 +2461,13 @@ def test_trade_case11(user: UserClient, user2: UserClient): } user2.post(res=models.Action, data=request_confirm) - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device.trading(trade.lot) == 'TradeConfirmed' lot, _ = user2.delete({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices[-1:], status=200) - assert device.trading_for_web(trade.lot) == 'Revoke' + assert device.trading(trade.lot) == 'Revoke' request_confirm_revoke = { 'type': 'Revoke', @@ -2477,7 +2476,7 @@ def test_trade_case11(user: UserClient, user2: UserClient): } user.post(res=models.Action, data=request_confirm_revoke) - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to @@ -2525,7 +2524,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): trade = models.Trade.query.one() device1, device = trade.devices - assert device.trading_for_web(trade.lot) == 'Confirm' + assert device.trading(trade.lot) == 'Confirm' # Normal confirm request_confirm = { @@ -2535,7 +2534,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): } user2.post(res=models.Action, data=request_confirm) - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device.trading(trade.lot) == 'TradeConfirmed' request_revoke = { 'type': 'Revoke', @@ -2545,7 +2544,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): # Normal revoke user2.post(res=models.Action, data=request_revoke) - assert device.trading_for_web(trade.lot) == 'Revoke' + assert device.trading(trade.lot) == 'Revoke' request_confirm_revoke = { 'type': 'Revoke', @@ -2554,7 +2553,7 @@ def test_trade_case12(user: UserClient, user2: UserClient): } user.post(res=models.Action, data=request_confirm_revoke) - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_to @@ -2607,8 +2606,8 @@ def test_trade_case13(user: UserClient, user2: UserClient): query=devices[-1:]) device1, device = trade.devices - assert device1.trading_for_web(trade.lot) == 'NeedConfirmation' - assert device.trading_for_web(trade.lot) == 'Confirm' + assert device1.trading(trade.lot) == 'NeedConfirmation' + assert device.trading(trade.lot) == 'Confirm' request_confirm = { 'type': 'Confirm', @@ -2617,15 +2616,15 @@ def test_trade_case13(user: UserClient, user2: UserClient): } user.post(res=models.Action, data=request_confirm) - assert device1.trading_for_web(trade.lot) == 'Confirm' - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device1.trading(trade.lot) == 'Confirm' + assert device.trading(trade.lot) == 'TradeConfirmed' lot, _ = user.delete({}, res=Lot, item='{}/devices'.format(lot['id']), query=devices[-1:], status=200) - assert device1.trading_for_web(trade.lot) == 'Confirm' - assert device.trading_for_web(trade.lot) == 'Revoke' + assert device1.trading(trade.lot) == 'Confirm' + assert device.trading(trade.lot) == 'Revoke' request_confirm_revoke = { 'type': 'Revoke', @@ -2634,7 +2633,7 @@ def test_trade_case13(user: UserClient, user2: UserClient): } user2.post(res=models.Action, data=request_confirm_revoke) - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_from @@ -2687,8 +2686,8 @@ def test_trade_case14(user: UserClient, user2: UserClient): query=devices[-1:]) device1, device = trade.devices - assert device1.trading_for_web(trade.lot) == 'NeedConfirmation' - assert device.trading_for_web(trade.lot) == 'Confirm' + assert device1.trading(trade.lot) == 'NeedConfirmation' + assert device.trading(trade.lot) == 'Confirm' # Normal confirm request_confirm = { @@ -2698,7 +2697,7 @@ def test_trade_case14(user: UserClient, user2: UserClient): } user.post(res=models.Action, data=request_confirm) - assert device.trading_for_web(trade.lot) == 'TradeConfirmed' + assert device.trading(trade.lot) == 'TradeConfirmed' request_revoke = { 'type': 'Revoke', @@ -2708,7 +2707,7 @@ def test_trade_case14(user: UserClient, user2: UserClient): # Normal revoke user.post(res=models.Action, data=request_revoke) - assert device.trading_for_web(trade.lot) == 'Revoke' + assert device.trading(trade.lot) == 'Revoke' request_confirm_revoke = { 'type': 'Revoke', @@ -2717,7 +2716,7 @@ def test_trade_case14(user: UserClient, user2: UserClient): } user2.post(res=models.Action, data=request_confirm_revoke) - assert device.trading_for_web(trade.lot) == 'RevokeConfirmed' + assert device.trading(trade.lot) == 'RevokeConfirmed' assert device.actions[-1].t == 'Revoke' assert device.actions[-1].user == trade.user_from From a19aa66ecce2dc1afefcff77096fb12ad36269dc Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 12 Nov 2021 18:31:19 +0100 Subject: [PATCH 40/48] fixing test_workbench_server_condensed --- tests/test_workbench.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_workbench.py b/tests/test_workbench.py index 9998decc..2eb161a1 100644 --- a/tests/test_workbench.py +++ b/tests/test_workbench.py @@ -66,7 +66,7 @@ def test_workbench_server_condensed(user: UserClient): assert device['rate']['rating'] == 1 assert device['rate']['type'] == RateComputer.t # TODO JN why haven't same order in actions on each execution? - assert device['actions'][2]['type'] == BenchmarkProcessor.t or device['actions'][2]['type'] == BenchmarkRamSysbench.t + assert any([ac['type'] in [BenchmarkProcessor.t, BenchmarkRamSysbench.t] for ac in device['actions']]) assert 'tag1' in [x['id'] for x in device['tags']] From 287ac8d7414605eaa72adaf0dbcb3ab2337e00b0 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 12 Nov 2021 22:16:02 +0100 Subject: [PATCH 41/48] fixing migration of olds confirmRevokes datas --- .../968b79fa7756_upgrade_confirmrevoke.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py diff --git a/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py b/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py new file mode 100644 index 00000000..f1a1603b --- /dev/null +++ b/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py @@ -0,0 +1,52 @@ +"""upgrade confirmrevoke + +Revision ID: 968b79fa7756 +Revises: d22d230d2850 +Create Date: 2021-11-12 19:18:39.135386 + +""" +from alembic import op +from alembic import context +import sqlalchemy as sa +import sqlalchemy_utils +import citext +import teal + + +# revision identifiers, used by Alembic. +revision = '968b79fa7756' +down_revision = 'd22d230d2850' +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(): + con = op.get_bind() + + + confirmsRevokes_sql = f"select * from {get_inv()}.action as action join {get_inv()}.confirm as confirm on action.id=confirm.id where action.type='ConfirmRevoke'" + revokes_sql = f"select confirm.id, confirm.action_id from {get_inv()}.action as action join {get_inv()}.confirm as confirm on action.id=confirm.id where action.type='Revoke'" + confirmsRevokes = [a for a in con.execute(confirmsRevokes_sql)] + revokes = {ac.id: ac.action_id for ac in con.execute(revokes_sql)} + + for ac in confirmsRevokes: + ac_id = ac.id + revoke_id = ac.action_id + trade_id = revokes[revoke_id] + sql_action = f"update {get_inv()}.action set type='Revoke' where type='ConfirmRevoke' and id='{ac_id}'" + sql_confirm = f"update {get_inv()}.confirm set action_id='{trade_id}' where id='{ac_id}'" + con.execute(sql_action) + con.execute(sql_confirm) + + assert 1 == 2 + + + +def downgrade(): + pass From fb5286648db5d99ff891f8f77e55b5812c551474 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 12 Nov 2021 22:24:23 +0100 Subject: [PATCH 42/48] fixing update of migration --- .../migrations/versions/968b79fa7756_upgrade_confirmrevoke.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py b/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py index f1a1603b..cf5455bf 100644 --- a/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py +++ b/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py @@ -39,7 +39,7 @@ def upgrade(): ac_id = ac.id revoke_id = ac.action_id trade_id = revokes[revoke_id] - sql_action = f"update {get_inv()}.action set type='Revoke' where type='ConfirmRevoke' and id='{ac_id}'" + sql_action = f"update {get_inv()}.action set type='Revoke' where id='{ac_id}'" sql_confirm = f"update {get_inv()}.confirm set action_id='{trade_id}' where id='{ac_id}'" con.execute(sql_action) con.execute(sql_confirm) From e447e15aeb143cc4b28e8b17b8511df2a9a15d59 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 12 Nov 2021 22:26:08 +0100 Subject: [PATCH 43/48] fixing update of migration --- .../migrations/versions/968b79fa7756_upgrade_confirmrevoke.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py b/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py index cf5455bf..bd3a995d 100644 --- a/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py +++ b/ereuse_devicehub/migrations/versions/968b79fa7756_upgrade_confirmrevoke.py @@ -44,7 +44,6 @@ def upgrade(): con.execute(sql_action) con.execute(sql_confirm) - assert 1 == 2 From 5510417125dcab2d269f875564543965db8c3752 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 18 Nov 2021 11:48:57 +0100 Subject: [PATCH 44/48] reduce latency for timeout for lots --- ereuse_devicehub/resources/lot/schemas.py | 31 ++++++++++++-- tests/test_device.py | 6 ++- tests/test_lot.py | 50 ++++++++++++----------- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/ereuse_devicehub/resources/lot/schemas.py b/ereuse_devicehub/resources/lot/schemas.py index 5604cc2e..9a5a58aa 100644 --- a/ereuse_devicehub/resources/lot/schemas.py +++ b/ereuse_devicehub/resources/lot/schemas.py @@ -5,14 +5,32 @@ from ereuse_devicehub.marshmallow import NestedOn from ereuse_devicehub.resources.deliverynote import schemas as s_deliverynote from ereuse_devicehub.resources.device import schemas as s_device from ereuse_devicehub.resources.action import schemas as s_action -from ereuse_devicehub.resources.tradedocument import schemas as s_document from ereuse_devicehub.resources.enums import TransferState from ereuse_devicehub.resources.lot import models as m from ereuse_devicehub.resources.models import STR_SIZE from ereuse_devicehub.resources.schemas import Thing -class Lot(Thing): +TRADE_VALUES = ( + 'id', + 'user_from.email', + 'user_to.email', + 'user_from.id', + 'user_to.id', + 'user_to.code', + 'user_from.code' +) + + +DOCUMENTS_VALUES = ( + 'id', + 'file_name', + 'total_weight', + 'trading' +) + + +class Old_Lot(Thing): id = f.UUID(dump_only=True) name = SanitizedStr(validate=f.validate.Length(max=STR_SIZE), required=True) description = SanitizedStr(description=m.Lot.description.comment) @@ -29,4 +47,11 @@ class Lot(Thing): receiver_address = SanitizedStr(validate=f.validate.Length(max=42)) deliverynote = NestedOn(s_deliverynote.Deliverynote, dump_only=True) documents = NestedOn('TradeDocument', many=True, dump_only=True) - trade = NestedOn(s_action.Trade, dump_only=True) + + +class Lot(Thing): + id = f.UUID(dump_only=True) + name = SanitizedStr(validate=f.validate.Length(max=STR_SIZE), required=True) + description = SanitizedStr(description=m.Lot.description.comment) + trade = f.Nested(s_action.Trade, dump_only=True, only=TRADE_VALUES) + documents = f.Nested('TradeDocument', many=True, dump_only=True, only=DOCUMENTS_VALUES) diff --git a/tests/test_device.py b/tests/test_device.py index 3ffef3a9..7ea400a0 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -506,7 +506,8 @@ def test_get_devices_permissions(app: Devicehub, user: UserClient, user2: UserCl @pytest.mark.mvp -def test_get_devices_unassigned(app: Devicehub, user: UserClient): +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_get_devices_unassigned(user: UserClient): """Checks GETting multiple devices.""" user.post(file('asus-eee-1000h.snapshot.11'), res=m.Snapshot) @@ -529,7 +530,8 @@ def test_get_devices_unassigned(app: Devicehub, user: UserClient): res=Lot, item='{}/devices'.format(my_lot['id']), query=[('id', device_id)]) - assert lot['devices'][0]['id'] == device_id, 'Lot contains device' + lot = Lot.query.filter_by(id=lot['id']).one() + assert next(iter(lot.devices)).id == device_id url = '/devices/?filter={"type":["Computer"]}&unassign=0' diff --git a/tests/test_lot.py b/tests/test_lot.py index 3f1f0731..44889825 100644 --- a/tests/test_lot.py +++ b/tests/test_lot.py @@ -313,7 +313,6 @@ def test_post_get_lot(user: UserClient): assert l['name'] == 'Foo' l, _ = user.get(res=Lot, item=l['id']) assert l['name'] == 'Foo' - assert not l['children'] def test_lot_post_add_children_view_ui_tree_normal(user: UserClient): @@ -355,38 +354,40 @@ def test_lot_post_add_children_view_ui_tree_normal(user: UserClient): @pytest.mark.mvp -def test_lot_post_add_remove_device_view(app: Devicehub, user: UserClient): +@pytest.mark.usefixtures(conftest.app_context.__name__) +def test_lot_post_add_remove_device_view(user: UserClient): """Tests adding a device to a lot using POST and removing it with DELETE. """ # todo check with components - with app.app_context(): - g.user = User.query.one() - device = Desktop(serial_number='foo', - model='bar', - manufacturer='foobar', - chassis=ComputerChassis.Lunchbox, - owner_id=user.user['id']) - db.session.add(device) - db.session.commit() - device_id = device.id - devicehub_id = device.devicehub_id + g.user = User.query.one() + device = Desktop(serial_number='foo', + model='bar', + manufacturer='foobar', + chassis=ComputerChassis.Lunchbox, + owner_id=user.user['id']) + db.session.add(device) + db.session.commit() + device_id = device.id + devicehub_id = device.devicehub_id parent, _ = user.post(({'name': 'lot'}), res=Lot) lot, _ = user.post({}, res=Lot, item='{}/devices'.format(parent['id']), query=[('id', device_id)]) - assert lot['devices'][0]['id'] == device_id, 'Lot contains device' - device, _ = user.get(res=Device, item=devicehub_id) - assert len(device['lots']) == 1 - assert device['lots'][0]['id'] == lot['id'], 'Device is inside lot' + lot = Lot.query.filter_by(id=lot['id']).one() + assert list(lot.devices)[0].id == device_id, 'Lot contains device' + device = Device.query.filter_by(devicehub_id=devicehub_id).one() + assert len(device.lots) == 1 + # assert device['lots'][0]['id'] == lot['id'], 'Device is inside lot' + assert list(device.lots)[0].id == lot.id, 'Device is inside lot' # Remove the device - lot, _ = user.delete(res=Lot, - item='{}/devices'.format(parent['id']), - query=[('id', device_id)], - status=200) - assert not len(lot['devices']) + user.delete(res=Lot, + item='{}/devices'.format(parent['id']), + query=[('id', device_id)], + status=200) + assert not len(lot.devices) @pytest.mark.mvp @@ -416,8 +417,9 @@ def test_lot_error_add_device_from_other_user(user: UserClient): res=Lot, item='{}/devices'.format(parent['id']), query=[('id', device_id)]) - assert lot['devices'] == [], 'Lot contains device' - assert len(lot['devices']) == 0 + lot = Lot.query.filter_by(id=lot['id']).one() + assert list(lot.devices) == [], 'Lot contains device' + assert len(lot.devices) == 0 @pytest.mark.mvp From 63f7adf69c55fde5851c5009535a84bbf1897bf3 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 18 Nov 2021 11:50:29 +0100 Subject: [PATCH 45/48] try to use only_fields for devices but not used --- ereuse_devicehub/resources/device/schemas.py | 74 +++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index bc18b995..f28fba72 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -14,6 +14,7 @@ from ereuse_devicehub.resources import enums from ereuse_devicehub.resources.device import models as m, states from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE from ereuse_devicehub.resources.schemas import Thing, UnitCodes +# from ereuse_devicehub.resources.action.schemas import Action as s_action class Device(Thing): @@ -96,6 +97,77 @@ class Device(Thing): field_names=['actions']) +ACTIONS_VALUE = ( + 'id', + 'type', + 'created' +) + + +TAGS_VALUE = ( + 'id', + 'printable', + 'code', + 'device', + 'type', + 'url' +) + + +class Device2(Thing): + __doc__ = m.Device.__doc__ + id = Integer(description=m.Device.id.comment, dump_only=True) + hid = SanitizedStr(lower=True, description=m.Device.hid.comment) + tags = f.Nested('Tag', + many=True, + collection_class=OrderedSet, + description='A set of tags that identify the device.', + only=TAGS_VALUE) + model = SanitizedStr(lower=True, + validate=Length(max=STR_BIG_SIZE), + description=m.Device.model.comment) + manufacturer = SanitizedStr(lower=True, + validate=Length(max=STR_SIZE), + description=m.Device.manufacturer.comment) + serial_number = SanitizedStr(lower=True, + validate=Length(max=STR_BIG_SIZE), + data_key='serialNumber') + # actions = NestedOn('Action', many=True, dump_only=True, description=m.Device.actions.__doc__) + actions = f.Nested('Action', only=ACTIONS_VALUE, many=True) + # actions = f.Nested(s_actions.Action(only=ACTIONS_VALUE), + # many=True, + # dump_only=True, + # description=m.Device.actions.__doc__) + # actions_one = NestedOn('Action', many=True, load_only=True, collection_class=OrderedSet) + url = URL(dump_only=True, description=m.Device.url.__doc__) + # lots = NestedOn('Lot', + # many=True, + # dump_only=True, + # description='The lots where this device is directly under.') + tradings = Dict(dump_only=True, description='') + traking = EnumField(states.Traking, dump_only=True, description=m.Device.physical.__doc__) + revoke = UUID(dump_only=True) + allocated = Boolean(description=m.Device.allocated.comment) + devicehub_id = SanitizedStr(data_key='devicehubID', + description=m.Device.devicehub_id.comment) + + +COMPONENTS_VALUES = ( + 'type', + 'manufacturer', + 'model' +) + + +class Computer2(Device): + __doc__ = m.Computer.__doc__ + # components = f.Nested(Component(only=COMPONENTS_VALUES), + # many=True, + # dump_only=True, + # collection_class=OrderedSet, + # description='The components that are inside this computer.') + + class Computer(Device): __doc__ = m.Computer.__doc__ components = NestedOn('Component', @@ -128,7 +200,7 @@ class Computer(Device): description=m.Computer.privacy.__doc__) amount = Integer(validate=f.validate.Range(min=0, max=100), description=m.Computer.amount.__doc__) - # author_id = NestedOn(s_user.User,only_query='author_id') + # author_id = NestedOn(s_user.User, only_query='author_id') owner_id = UUID(data_key='ownerID') transfer_state = EnumField(enums.TransferState, description=m.Computer.transfer_state.comment) receiver_id = UUID(data_key='receiverID') From d8382f833138c863f887f44672ba3207e811f2bb Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Thu, 18 Nov 2021 11:52:59 +0100 Subject: [PATCH 46/48] drop assert for lot[devices] in dummy --- ereuse_devicehub/dummy/dummy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py index 04fbdaf3..5b6ab47a 100644 --- a/ereuse_devicehub/dummy/dummy.py +++ b/ereuse_devicehub/dummy/dummy.py @@ -139,7 +139,7 @@ class Dummy: res=Lot, item='{}/devices'.format(lot_user['id']), query=[('id', pc) for pc in itertools.islice(pcs, 1, 4)]) - assert len(lot['devices']) + # assert len(lot['devices']) lot2, _ = user2.post({}, res=Lot, From aa17d4b492c89ae7f080142d89302dd9c2147a08 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 19 Nov 2021 11:34:13 +0100 Subject: [PATCH 47/48] clean code test --- ereuse_devicehub/resources/device/schemas.py | 76 ++------------------ 1 file changed, 4 insertions(+), 72 deletions(-) diff --git a/ereuse_devicehub/resources/device/schemas.py b/ereuse_devicehub/resources/device/schemas.py index f28fba72..0c265d78 100644 --- a/ereuse_devicehub/resources/device/schemas.py +++ b/ereuse_devicehub/resources/device/schemas.py @@ -14,7 +14,6 @@ from ereuse_devicehub.resources import enums from ereuse_devicehub.resources.device import models as m, states from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE from ereuse_devicehub.resources.schemas import Thing, UnitCodes -# from ereuse_devicehub.resources.action.schemas import Action as s_action class Device(Thing): @@ -41,10 +40,13 @@ class Device(Thing): width = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.width.comment) height = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.height.comment) depth = Float(validate=Range(0.1, 5), unit=UnitCodes.m, description=m.Device.depth.comment) + # TODO TimeOut 2. Comment actions and lots if there are time out. actions = NestedOn('Action', many=True, dump_only=True, description=m.Device.actions.__doc__) + # TODO TimeOut 2. Comment actions_one and lots if there are time out. actions_one = NestedOn('Action', many=True, load_only=True, collection_class=OrderedSet) problems = NestedOn('Action', many=True, dump_only=True, description=m.Device.problems.__doc__) url = URL(dump_only=True, description=m.Device.url.__doc__) + # TODO TimeOut 2. Comment actions and lots if there are time out. lots = NestedOn('Lot', many=True, dump_only=True, @@ -97,79 +99,9 @@ class Device(Thing): field_names=['actions']) -ACTIONS_VALUE = ( - 'id', - 'type', - 'created' -) - - -TAGS_VALUE = ( - 'id', - 'printable', - 'code', - 'device', - 'type', - 'url' -) - - -class Device2(Thing): - __doc__ = m.Device.__doc__ - id = Integer(description=m.Device.id.comment, dump_only=True) - hid = SanitizedStr(lower=True, description=m.Device.hid.comment) - tags = f.Nested('Tag', - many=True, - collection_class=OrderedSet, - description='A set of tags that identify the device.', - only=TAGS_VALUE) - model = SanitizedStr(lower=True, - validate=Length(max=STR_BIG_SIZE), - description=m.Device.model.comment) - manufacturer = SanitizedStr(lower=True, - validate=Length(max=STR_SIZE), - description=m.Device.manufacturer.comment) - serial_number = SanitizedStr(lower=True, - validate=Length(max=STR_BIG_SIZE), - data_key='serialNumber') - # actions = NestedOn('Action', many=True, dump_only=True, description=m.Device.actions.__doc__) - actions = f.Nested('Action', only=ACTIONS_VALUE, many=True) - # actions = f.Nested(s_actions.Action(only=ACTIONS_VALUE), - # many=True, - # dump_only=True, - # description=m.Device.actions.__doc__) - # actions_one = NestedOn('Action', many=True, load_only=True, collection_class=OrderedSet) - url = URL(dump_only=True, description=m.Device.url.__doc__) - # lots = NestedOn('Lot', - # many=True, - # dump_only=True, - # description='The lots where this device is directly under.') - tradings = Dict(dump_only=True, description='') - traking = EnumField(states.Traking, dump_only=True, description=m.Device.physical.__doc__) - revoke = UUID(dump_only=True) - allocated = Boolean(description=m.Device.allocated.comment) - devicehub_id = SanitizedStr(data_key='devicehubID', - description=m.Device.devicehub_id.comment) - - -COMPONENTS_VALUES = ( - 'type', - 'manufacturer', - 'model' -) - - -class Computer2(Device): - __doc__ = m.Computer.__doc__ - # components = f.Nested(Component(only=COMPONENTS_VALUES), - # many=True, - # dump_only=True, - # collection_class=OrderedSet, - # description='The components that are inside this computer.') - - class Computer(Device): __doc__ = m.Computer.__doc__ + # TODO TimeOut 1. Comment components if there are time out. components = NestedOn('Component', many=True, dump_only=True, From 0529600c9ba45ee786ac1eab35b5eb506514d0f2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 19 Nov 2021 11:53:42 +0100 Subject: [PATCH 48/48] modify changelog --- CHANGELOG.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7548f9b..016f22d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,36 +13,38 @@ ml). ## [1.0.10-beta] - [bugfix] #168 can to do a trade without devices. -- [addend] #167 new actions of status devices: use, recycling, refurbish and management. +- [added] #167 new actions of status devices: use, recycling, refurbish and management. +- [changes] #177 new structure of trade. +- [bugfix] #184 clean nested of schemas of lot ## [1.0.9-beta] -- [addend] #159 external document as proof of erase of disk -- [addend] #162 adding lot for devices unassigned +- [added] #159 external document as proof of erase of disk +- [added] #162 adding lot for devices unassigned ## [1.0.8-beta] - [bugfix] #161 fixing DataStorage with bigInteger ## [1.0.7-beta] -- [addend] #158 support for encrypted snapshots data -- [addend] #135 adding trade system -- [addend] #140 adding endpoint for download the settings for usb workbench +- [added] #158 support for encrypted snapshots data +- [added] #135 adding trade system +- [added] #140 adding endpoint for download the settings for usb workbench ## [1.0.6-beta] - [bugfix] #143 biginteger instead of integer in TestDataStorage ## [1.0.5-beta] -- [addend] #124 adding endpoint for extract the internal stats of use -- [addend] #122 system for verify all documents that it's produced from devicehub -- [addend] #127 add one code for every named tag -- [addend] #131 add one code for every device +- [added] #124 adding endpoint for extract the internal stats of use +- [added] #122 system for verify all documents that it's produced from devicehub +- [added] #127 add one code for every named tag +- [added] #131 add one code for every device - [bugfix] #138 search device with devicehubId ## [1.0.4-beta] -- [addend] #95 adding endpoint for check the hash of one report -- [addend] #98 adding endpoint for insert a new live -- [addend] #98 adding endpoint for get all licences in one query -- [addend] #102 adding endpoint for download metrics +- [added] #95 adding endpoint for check the hash of one report +- [added] #98 adding endpoint for insert a new live +- [added] #98 adding endpoint for get all licences in one query +- [added] #102 adding endpoint for download metrics - [bugfix] #100 fixing bug of scheme live - [bugfix] #101 fixing bug when 2 users have one device and launch one live - [changes] #114 clean blockchain of all models @@ -51,11 +53,11 @@ ml). - [remove] #114 remove proof system ## [1.0.3-beta] -- [addend] #85 add mac of network adapter to device hid +- [added] #85 add mac of network adapter to device hid - [changed] #94 change form of snapshot manual ## [1.0.2-beta] -- [addend] #87 allocate, deallocate and live actions +- [added] #87 allocate, deallocate and live actions - [fixed] #89 save json on disk only for shapshots -- [addend] #83 add owner_id in all kind of device +- [added] #83 add owner_id in all kind of device - [fixed] #91 The most old time allow is 1970-01-01