resolve conflict

This commit is contained in:
Cayo Puigdefabregas 2021-02-11 13:03:21 +01:00
commit 0535a1f310
29 changed files with 268 additions and 365 deletions

View File

@ -18,6 +18,8 @@ ml).
- [addend] #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
- [remove] #114 remove proof system
## [1.0.3-beta]
- [addend] #85 add mac of network adapter to device hid

View File

@ -9,7 +9,7 @@ from teal.enums import Currency
from teal.utils import import_resource
from ereuse_devicehub.resources import action, agent, deliverynote, inventory, \
lot, proof, tag, user
lot, tag, user
from ereuse_devicehub.resources.device import definitions
from ereuse_devicehub.resources.documents import documents
from ereuse_devicehub.resources.enums import PriceSoftware
@ -26,7 +26,6 @@ class DevicehubConfig(Config):
import_resource(agent),
import_resource(lot),
import_resource(deliverynote),
import_resource(proof),
import_resource(documents),
import_resource(inventory),
import_resource(versions),

View File

@ -65,10 +65,10 @@ class Dummy:
with click_spinner.spinner():
out = runner.invoke('org', 'add', *self.ORG).output
org_id = json.loads(out)['id']
user1 = self.user_client('user@dhub.com', '1234', 'user1', '0xC79F7fE80B5676fe38D8187b79d55F7A61e702b2')
user2 = self.user_client('user2@dhub.com', '1234', 'user2', '0x56EbFdbAA98f52027A9776456e4fcD5d91090818')
user3 = self.user_client('user3@dhub.com', '1234', 'user3', '0xF88618956696aB7e56Cb7bc87d9848E921C4FDaA')
user4 = self.user_client('user4@dhub.com', '1234', 'user4', '0x37be35ae7eced44ca25e4683e98425fc7830a8a5')
user1 = self.user_client('user@dhub.com', '1234', 'user1')
user2 = self.user_client('user2@dhub.com', '1234', 'user2')
user3 = self.user_client('user3@dhub.com', '1234', 'user3')
user4 = self.user_client('user4@dhub.com', '1234', 'user4')
# todo put user's agent into Org
for id in self.TAGS:
@ -188,8 +188,8 @@ class Dummy:
# For netbook: to preapre -> torepair -> to dispose -> disposed
print('⭐ Done.')
def user_client(self, email: str, password: str, name: str, ethereum_address: str):
user = User(email=email, password=password, ethereum_address=ethereum_address)
def user_client(self, email: str, password: str, name: str):
user = User(email=email, password=password)
user.individuals.add(Person(name=name))
db.session.add(user)

View File

@ -0,0 +1,158 @@
"""change deliverynote
Revision ID: eca457d8b2a4
Revises: 0cbd839b09ef
Create Date: 2021-02-03 22:12:41.033661
"""
import citext
import sqlalchemy as sa
from alembic import op
from alembic import context
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = 'eca457d8b2a4'
down_revision = '0cbd839b09ef'
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.drop_column('deliverynote', 'ethereum_address', schema=f'{get_inv()}')
op.alter_column('deliverynote', 'deposit', new_column_name='amount', schema=f'{get_inv()}')
op.alter_column('computer', 'deposit', new_column_name='amount', schema=f'{get_inv()}')
op.alter_column('lot', 'deposit', new_column_name='amount', schema=f'{get_inv()}')
op.drop_column('lot', 'deliverynote_address', schema=f'{get_inv()}')
op.drop_column('computer', 'deliverynote_address', schema=f'{get_inv()}')
op.drop_column('computer', 'ethereum_address', schema=f'{get_inv()}')
op.drop_column('lot', 'receiver_address', schema=f'{get_inv()}')
op.add_column('lot', sa.Column('receiver_address', citext.CIText(),
sa.ForeignKey('common.user.email'), nullable=True),
schema=f'{get_inv()}')
op.drop_column('user', 'ethereum_address', schema='common')
op.drop_table('proof_function', schema=f'{get_inv()}')
op.drop_table('proof_data_wipe', schema=f'{get_inv()}')
op.drop_table('proof_transfer', schema=f'{get_inv()}')
op.drop_table('proof_reuse', schema=f'{get_inv()}')
op.drop_table('proof_recycling', schema=f'{get_inv()}')
op.drop_index(op.f('ix_proof_updated'), table_name='proof', schema=f'{get_inv()}')
op.drop_index(op.f('ix_proof_created'), table_name='proof', schema=f'{get_inv()}')
op.drop_table('proof', schema=f'{get_inv()}')
def downgrade():
op.add_column('deliverynote', sa.Column('ethereum_address', citext.CIText(), nullable=True), schema=f'{get_inv()}')
op.alter_column('deliverynote', 'amount', new_column_name='deposit', schema=f'{get_inv()}')
op.add_column('computer', sa.Column('deliverynote_address', citext.CIText(), nullable=True), schema=f'{get_inv()}')
op.add_column('lot', sa.Column('deliverynote_address', citext.CIText(), nullable=True), schema=f'{get_inv()}')
# =====
op.alter_column('computer', 'amount', new_column_name='deposit', schema=f'{get_inv()}')
op.alter_column('lot', 'amount', new_column_name='deposit', schema=f'{get_inv()}')
# =====
op.add_column('computer', sa.Column('ethereum_address', citext.CIText(), nullable=True), schema=f'{get_inv()}')
op.add_column('user', sa.Column('ethereum_address', citext.CIText(), unique=True, nullable=True), schema='common')
op.drop_column('lot', 'receiver_address', schema=f'{get_inv()}')
op.add_column('lot', sa.Column('receiver_address', citext.CIText(),
sa.ForeignKey('common.user.ethereum_address'), nullable=True),
schema=f'{get_inv()}')
# =====
op.create_table('proof',
sa.Column('updated', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'),
nullable=False,
comment='The last time Devicehub recorded a change for \n this thing.\n '),
sa.Column('created', sa.TIMESTAMP(timezone=True), server_default=sa.text('CURRENT_TIMESTAMP'),
nullable=False, comment='When Devicehub created this.'),
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('type', sa.Unicode(), nullable=False),
sa.Column('ethereum_hash', citext.CIText(), nullable=False),
sa.Column('device_id', sa.BigInteger(), nullable=False),
sa.ForeignKeyConstraint(['device_id'], [f'{get_inv()}.device.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)
op.create_index(op.f('ix_proof_created'), 'proof', ['created'], unique=False, schema=f'{get_inv()}')
op.create_index(op.f('ix_proof_updated'), 'proof', ['updated'], unique=False, schema=f'{get_inv()}')
op.create_table('proof_recycling',
sa.Column('collection_point', citext.CIText(), nullable=False),
sa.Column('date', sa.DateTime(), nullable=False),
sa.Column('contact', citext.CIText(), nullable=False),
sa.Column('ticket', citext.CIText(), nullable=False),
sa.Column('gps_location', citext.CIText(), nullable=False),
sa.Column('recycler_code', citext.CIText(), nullable=False),
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.proof.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)
# Proof reuse table
op.create_table('proof_reuse',
sa.Column('receiver_segment', citext.CIText(), nullable=False),
sa.Column('id_receipt', citext.CIText(), nullable=False),
sa.Column('supplier_id', postgresql.UUID(as_uuid=True), nullable=True),
sa.Column('receiver_id', postgresql.UUID(as_uuid=True), nullable=True),
sa.Column('price', sa.Integer(), nullable=True),
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.proof.id'], ),
sa.ForeignKeyConstraint(['receiver_id'], ['common.user.id'], ),
sa.ForeignKeyConstraint(['supplier_id'], ['common.user.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)
# Proof transfer table
op.create_table('proof_transfer',
sa.Column('supplier_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('receiver_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('deposit', sa.Integer(), nullable=True),
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.proof.id'], ),
sa.ForeignKeyConstraint(['receiver_id'], ['common.user.id'], ),
sa.ForeignKeyConstraint(['supplier_id'], ['common.user.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)
# ProofDataWipe table
op.create_table('proof_data_wipe',
sa.Column('date', sa.DateTime(), nullable=False),
sa.Column('result', sa.Boolean(), nullable=False, comment='Identifies proof datawipe as a result.'),
sa.Column('proof_author_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('erasure_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['erasure_id'], [f'{get_inv()}.erase_basic.id'], ),
sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.proof.id'], ),
sa.ForeignKeyConstraint(['proof_author_id'], ['common.user.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)
# PRoofFuntion
op.create_table('proof_function',
sa.Column('disk_usage', sa.Integer(), nullable=True),
sa.Column('proof_author_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('rate_id', postgresql.UUID(as_uuid=True), nullable=False),
sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False),
sa.ForeignKeyConstraint(['id'], [f'{get_inv()}.proof.id'], ),
sa.ForeignKeyConstraint(['proof_author_id'], ['common.user.id'], ),
sa.ForeignKeyConstraint(['rate_id'], [f'{get_inv()}.rate.id'], ),
sa.PrimaryKeyConstraint('id'),
schema=f'{get_inv()}'
)

View File

@ -36,7 +36,7 @@ class Deliverynote(Thing):
receiver = db.relationship(User, primaryjoin=lambda: Deliverynote.receiver_address == User.email)
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
date.comment = 'The date the DeliveryNote initiated'
deposit = db.Column(db.Integer, check_range('deposit', min=0, max=100), default=0)
amount = db.Column(db.Integer, check_range('amount', min=0, max=100), default=0)
# The following fields are supposed to be 0:N relationships
# to SnapshotDelivery entity.
# At this stage of implementation they will treated as a
@ -46,7 +46,6 @@ class Deliverynote(Thing):
transferred_devices = db.Column(db.ARRAY(db.Integer, dimensions=1), nullable=True)
transfer_state = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False)
transfer_state.comment = TransferState.__doc__
ethereum_address = db.Column(CIText(), unique=True, default=None)
lot_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(Lot.id),
nullable=False)
@ -55,14 +54,14 @@ class Deliverynote(Thing):
lazy=True,
primaryjoin=Lot.id == lot_id)
def __init__(self, document_id: str, deposit: str, date,
def __init__(self, document_id: str, amount: str, date,
supplier_email: str,
expected_devices: Iterable,
transfer_state: TransferState) -> None:
"""Initializes a delivery note
"""
super().__init__(id=uuid.uuid4(),
document_id=document_id, deposit=deposit, date=date,
document_id=document_id, amount=amount, date=date,
supplier_email=supplier_email,
expected_devices=expected_devices,
transfer_state=transfer_state)

View File

@ -24,13 +24,12 @@ class Lot(Thing):
description = ... # type: Column
all_devices = ... # type: relationship
parents = ... # type: relationship
deposit = ... # type: Column
amount = ... # type: Column
owner_address = ... # type: Column
owner = ... # type: relationship
transfer_state = ... # type: Column
receiver_address = ... # type: Column
receiver = ... # type: relationship
deliverynote_address = ... # type: Column
def __init__(self, name: str, closed: bool = closed.default.arg) -> None:
super().__init__()
@ -46,7 +45,6 @@ class Lot(Thing):
self.owner_address = ... # type: UUID
self.transfer_state = ...
self.receiver_address = ... # type: str
self.deliverynote_address = ... # type: str
def add_children(self, *children: Union[Lot, uuid.UUID]):
pass

View File

@ -19,9 +19,8 @@ class Deliverynote(Thing):
supplier = NestedOn(s_user.User, dump_only=True)
receiver = NestedOn(s_user.User, dump_only=True)
date = f.DateTime('iso', required=True)
deposit = f.Integer(validate=f.validate.Range(min=0, max=100),
description=m.Deliverynote.deposit.__doc__)
ethereum_address = f.String(description='User identifier address inside the Blockchain')
amount = f.Integer(validate=f.validate.Range(min=0, max=100),
description=m.Deliverynote.amount.__doc__)
expected_devices = f.List(f.Dict, required=True, data_key='expectedDevices')
transferred_devices = f.List(f.Integer(), required=False, data_key='transferredDevices')
transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment)

View File

@ -28,21 +28,13 @@ class DeliverynoteView(View):
return ret
def patch(self, id):
patch_schema = self.resource_def.SCHEMA(only=('transfer_state',
'ethereum_address'), partial=True)
patch_schema = self.resource_def.SCHEMA(only=('transfer_state'), partial=True)
d = request.get_json(schema=patch_schema)
dlvnote = Deliverynote.query.filter_by(id=id).one()
# device_fields = ['transfer_state', 'deliverynote_address']
# computers = [x for x in dlvnote.transferred_devices if isinstance(x, Computer)]
for key, value in d.items():
setattr(dlvnote, key, value)
# Transalate ethereum_address attribute
# devKey = key
# if key == 'ethereum_address':
# devKey = 'deliverynote_address'
# if devKey in device_fields:
# for dev in computers:
# setattr(dev, devKey, value)
db.session.commit()
return Response(status=204)

View File

@ -471,8 +471,7 @@ class Computer(Device):
It is a subset of the Linux definition of DMI / DMI decode.
"""
ethereum_address = Column(CIText(), unique=True, default=None)
deposit = Column(Integer, check_range('deposit', min=0, max=100), default=0)
amount = Column(Integer, check_range('amount', min=0, max=100), default=0)
owner_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False,
@ -484,7 +483,6 @@ class Computer(Device):
db.ForeignKey(User.id),
nullable=True)
receiver = db.relationship(User, primaryjoin=receiver_id == User.id)
deliverynote_address = db.Column(CIText(), nullable=True)
def __init__(self, *args, **kwargs) -> None:
if args:

View File

@ -141,11 +141,10 @@ class DisplayMixin:
class Computer(DisplayMixin, Device):
components = ... # type: Column
chassis = ... # type: Column
deposit = ... # type: Column
amount = ... # type: Column
owner_address = ... # type: Column
transfer_state = ... # type: Column
receiver_address = ... # type: Column
deliverynote_address = ... # type: Column
receiver_id = ... # uuid: Column
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
@ -155,7 +154,6 @@ class Computer(DisplayMixin, Device):
self.owner_address = ... # type: UUID
self.transfer_state = ...
self.receiver_address = ... # type: str
self.deliverynote_address = ... # type: str
@property
def actions(self) -> List:

View File

@ -123,14 +123,12 @@ class Computer(Device):
dump_only=True,
collection_class=set,
description=m.Computer.privacy.__doc__)
ethereum_address = SanitizedStr(validate=f.validate.Length(max=42))
deposit = Integer(validate=f.validate.Range(min=0, max=100),
description=m.Computer.deposit.__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')
owner_id = UUID(data_key='ownerID')
transfer_state = EnumField(enums.TransferState, description=m.Computer.transfer_state.comment)
receiver_id = UUID(data_key='receiverID')
deliverynote_address = SanitizedStr(validate=f.validate.Length(max=42))
class Desktop(Computer):

View File

@ -106,7 +106,7 @@ class DeviceView(View):
resource_def = app.resources['Computer']
# TODO check how to handle the 'actions_one'
patch_schema = resource_def.SCHEMA(
only=['ethereum_address', 'transfer_state', 'deliverynote_address', 'actions_one'], partial=True)
only=['transfer_state', 'actions_one'], partial=True)
json = request.get_json(schema=patch_schema)
# TODO check how to handle the 'actions_one'
json.pop('actions_one')

View File

@ -63,7 +63,7 @@ class Lot(Thing):
"""All devices, including components, inside this lot and its
descendants.
"""
deposit = db.Column(db.Integer, check_range('deposit', min=0, max=100), default=0)
amount = db.Column(db.Integer, check_range('amount', min=0, max=100), default=0)
owner_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False,
@ -72,10 +72,10 @@ class Lot(Thing):
transfer_state = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False)
transfer_state.comment = TransferState.__doc__
receiver_address = db.Column(CIText(),
db.ForeignKey(User.ethereum_address),
nullable=True)
receiver = db.relationship(User, primaryjoin=receiver_address == User.ethereum_address)
deliverynote_address = db.Column(CIText(), nullable=True)
db.ForeignKey(User.email),
nullable=False,
default=lambda: g.user.email)
receiver = db.relationship(User, primaryjoin=receiver_address == User.email)
def __init__(self, name: str, closed: bool = closed.default.arg,
description: str = None) -> None:

View File

@ -24,13 +24,12 @@ class Lot(Thing):
description = ... # type: Column
all_devices = ... # type: relationship
parents = ... # type: relationship
deposit = ... # type: Column
amount = ... # type: Column
owner_address = ... # type: Column
owner = ... # type: relationship
transfer_state = ... # type: Column
receiver_address = ... # type: Column
receiver = ... # type: relationship
deliverynote_address = ... # type: Column
def __init__(self, name: str, closed: bool = closed.default.arg) -> None:
super().__init__()
@ -46,7 +45,6 @@ class Lot(Thing):
self.owner_address = ... # type: UUID
self.transfer_state = ...
self.receiver_address = ... # type: str
self.deliverynote_address = ... # type: str
def add_children(self, *children: Union[Lot, uuid.UUID]):
pass

View File

@ -19,8 +19,8 @@ class Lot(Thing):
children = NestedOn('Lot', many=True, dump_only=True)
parents = NestedOn('Lot', many=True, dump_only=True)
url = URL(dump_only=True, description=m.Lot.url.__doc__)
deposit = f.Integer(validate=f.validate.Range(min=0, max=100),
description=m.Lot.deposit.__doc__)
amount = f.Integer(validate=f.validate.Range(min=0, max=100),
description=m.Lot.amount.__doc__)
# author_id = NestedOn(s_user.User,only_query='author_id')
owner_id = f.UUID(data_key='ownerID')
transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment)

View File

@ -41,11 +41,11 @@ class LotView(View):
def patch(self, id):
patch_schema = self.resource_def.SCHEMA(only=(
'name', 'description', 'transfer_state', 'receiver_address', 'deposit', 'deliverynote_address', 'devices',
'name', 'description', 'transfer_state', 'receiver_address', 'amount', 'devices',
'owner_address'), partial=True)
l = request.get_json(schema=patch_schema)
lot = Lot.query.filter_by(id=id).one()
device_fields = ['transfer_state', 'receiver_address', 'deposit', 'deliverynote_address', 'owner_address']
device_fields = ['transfer_state', 'receiver_address', 'amount', 'owner_address']
computers = [x for x in lot.all_devices if isinstance(x, Computer)]
for key, value in l.items():
setattr(lot, key, value)
@ -142,9 +142,9 @@ class LotView(View):
if path:
cls._p(node['nodes'], path)
def get_lot_deposit(self, l: Lot):
"""Return lot deposit value"""
return l.deposit
def get_lot_amount(self, l: Lot):
"""Return lot amount value"""
return l.amount
def change_state(self):
"""Change state of Lot"""

View File

@ -1,37 +0,0 @@
from teal.resource import Converters, Resource
from ereuse_devicehub.resources.proof import schemas
from ereuse_devicehub.resources.proof.views import ProofView
class ProofDef(Resource):
SCHEMA = schemas.Proof
VIEW = ProofView
# AUTH = True
AUTH = False
ID_CONVERTER = Converters.uuid
class ProofTransferDef(ProofDef):
VIEW = None
SCHEMA = schemas.ProofTransfer
class ProofDataWipeDef(ProofDef):
VIEW = None
SCHEMA = schemas.ProofDataWipe
class ProofFunction(ProofDef):
VIEW = None
SCHEMA = schemas.ProofFunction
class ProofReuse(ProofDef):
VIEW = None
SCHEMA = schemas.ProofReuse
class ProofRecycling(ProofDef):
VIEW = None
SCHEMA = schemas.ProofRecycling

View File

@ -1,149 +0,0 @@
"""This file contains all proofs related to actions
"""
from datetime import datetime
from uuid import uuid4
from boltons import urlutils
from citext import CIText
from flask import g
from sqlalchemy import BigInteger, Column, ForeignKey, Unicode
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm import backref, relationship
from teal.db import CASCADE_OWN, INHERIT_COND, POLYMORPHIC_ID, \
POLYMORPHIC_ON
from teal.resource import url_for_resource
from ereuse_devicehub.db import db
from ereuse_devicehub.resources.action.models import EraseBasic, Rate
from ereuse_devicehub.resources.device.models import Device
from ereuse_devicehub.resources.models import Thing
from ereuse_devicehub.resources.user import User
class JoinedTableMixin:
# noinspection PyMethodParameters
@declared_attr
def id(cls):
return Column(UUID(as_uuid=True), ForeignKey(Proof.id), primary_key=True)
class Proof(Thing):
"""Proof over an action.
"""
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
type = Column(Unicode, nullable=False)
ethereum_hash = Column(CIText(), default='', nullable=False)
device_id = db.Column(BigInteger,
db.ForeignKey(Device.id),
nullable=False)
device = db.relationship(Device,
backref=db.backref('proofs_device', uselist=True, lazy=True),
lazy=True,
primaryjoin=Device.id == device_id)
@property
def url(self) -> urlutils.URL:
"""The URL where to GET this proof."""
return urlutils.URL(url_for_resource(Proof, item_id=self.id))
# noinspection PyMethodParameters
@declared_attr
def __mapper_args__(cls):
"""Defines inheritance.
From `the guide <http://docs.sqlalchemy.org/en/latest/orm/
extensions/declarative/api.html
#sqlalchemy.ext.declarative.declared_attr>`_
"""
args = {POLYMORPHIC_ID: cls.t}
if cls.t == 'Proof':
args[POLYMORPHIC_ON] = cls.type
# noinspection PyUnresolvedReferences
if JoinedTableMixin in cls.mro():
args[INHERIT_COND] = cls.id == Proof.id
return args
def __init__(self, **kwargs) -> None:
# sortedset forces us to do this before calling our parent init
super().__init__(**kwargs)
def __repr__(self):
return '<{0.t} {0.id} >'.format(self)
class ProofTransfer(JoinedTableMixin, Proof):
supplier_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False,
default=lambda: g.user.id)
supplier = db.relationship(User, primaryjoin=lambda: ProofTransfer.supplier_id == User.id)
receiver_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False)
receiver = db.relationship(User, primaryjoin=lambda: ProofTransfer.receiver_id == User.id)
deposit = Column(db.Integer, default=0)
class ProofDataWipe(JoinedTableMixin, Proof):
# erasure_type = Column(CIText(), default='', nullable=False)
date = Column(db.DateTime, nullable=False, default=datetime.utcnow)
result = Column(db.Boolean, default=False, nullable=False)
result.comment = """Identifies proof datawipe as a result."""
proof_author_id = Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False,
default=lambda: g.user.id)
proof_author = relationship(User, primaryjoin=lambda: ProofDataWipe.proof_author_id == User.id)
erasure_id = Column(UUID(as_uuid=True), ForeignKey(EraseBasic.id), nullable=False)
erasure = relationship(EraseBasic,
backref=backref('proof_datawipe',
lazy=True,
uselist=False,
cascade=CASCADE_OWN),
primaryjoin=EraseBasic.id == erasure_id)
class ProofFunction(JoinedTableMixin, Proof):
disk_usage = Column(db.Integer, default=0)
proof_author_id = Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
nullable=False,
default=lambda: g.user.id)
proof_author = db.relationship(User, primaryjoin=lambda: ProofFunction.proof_author_id == User.id)
rate_id = Column(UUID(as_uuid=True), ForeignKey(Rate.id), nullable=False)
rate = relationship(Rate,
backref=backref('proof_function',
lazy=True,
uselist=False,
cascade=CASCADE_OWN),
primaryjoin=Rate.id == rate_id)
class ProofReuse(JoinedTableMixin, Proof):
receiver_segment = Column(CIText(), default='', nullable=False)
id_receipt = Column(CIText(), default='', nullable=False)
supplier_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
# nullable=False,
# default=lambda: g.user.id)
nullable=True)
supplier = db.relationship(User, primaryjoin=lambda: ProofReuse.supplier_id == User.id)
receiver_id = db.Column(UUID(as_uuid=True),
db.ForeignKey(User.id),
# nullable=False)
nullable=True)
receiver = db.relationship(User, primaryjoin=lambda: ProofReuse.receiver_id == User.id)
price = Column(db.Integer)
class ProofRecycling(JoinedTableMixin, Proof):
collection_point = Column(CIText(), default='', nullable=False)
date = Column(db.DateTime, nullable=False, default=datetime.utcnow)
contact = Column(CIText(), default='', nullable=False)
ticket = Column(CIText(), default='', nullable=False)
gps_location = Column(CIText(), default='', nullable=False)
recycler_code = Column(CIText(), default='', nullable=False)

View File

@ -1,70 +0,0 @@
from marshmallow import fields as f
from marshmallow import fields as f
from marshmallow.fields import Boolean, DateTime, Integer, String, UUID
from marshmallow.validate import Length
from teal.marshmallow import SanitizedStr, URL
from ereuse_devicehub.marshmallow import NestedOn
from ereuse_devicehub.resources.action import schemas as s_action
from ereuse_devicehub.resources.device import schemas as s_device
from ereuse_devicehub.resources.models import STR_BIG_SIZE, STR_SIZE
from ereuse_devicehub.resources.proof import models as m
from ereuse_devicehub.resources.schemas import Thing
from ereuse_devicehub.resources.user import schemas as s_user
class Proof(Thing):
__doc__ = m.Proof.__doc__
id = UUID(dump_only=True)
ethereum_hash = SanitizedStr(default='', validate=Length(max=STR_BIG_SIZE),
data_key="ethereumHash", required=True)
url = URL(dump_only=True, description=m.Proof.url.__doc__)
device_id = Integer(load_only=True, data_key='deviceID')
device = NestedOn(s_device.Device, dump_only=True)
class ProofTransfer(Proof):
__doc__ = m.ProofTransfer.__doc__
deposit = Integer(validate=f.validate.Range(min=0, max=100))
supplier_id = UUID(load_only=True, required=True, data_key='supplierID')
receiver_id = UUID(load_only=True, required=True, data_key='receiverID')
class ProofDataWipe(Proof):
__doc__ = m.ProofDataWipe.__doc__
# erasure_type = String(default='', data_key='erasureType')
date = DateTime('iso', required=True)
result = Boolean(required=True)
proof_author_id = SanitizedStr(validate=f.validate.Length(max=STR_SIZE),
load_only=True, required=True, data_key='proofAuthorID')
proof_author = NestedOn(s_user.User, dump_only=True)
erasure = NestedOn(s_action.EraseBasic, only_query='id', data_key='erasureID')
class ProofFunction(Proof):
__doc__ = m.ProofFunction.__doc__
disk_usage = Integer(validate=f.validate.Range(min=0, max=100), data_key='diskUsage')
proof_author_id = SanitizedStr(validate=f.validate.Length(max=STR_SIZE),
load_only=True, required=True, data_key='proofAuthorID')
proof_author = NestedOn(s_user.User, dump_only=True)
rate = NestedOn(s_action.Rate, required=True,
only_query='id', data_key='rateID')
class ProofReuse(Proof):
__doc__ = m.ProofReuse.__doc__
receiver_segment = String(default='', data_key='receiverSegment', required=True)
id_receipt = String(default='', data_key='idReceipt', required=True)
supplier_id = UUID(load_only=True, required=False, data_key='supplierID')
receiver_id = UUID(load_only=True, required=False, data_key='receiverID')
price = Integer(required=True)
class ProofRecycling(Proof):
__doc__ = m.ProofRecycling.__doc__
collection_point = SanitizedStr(default='', data_key='collectionPoint', required=True)
date = DateTime('iso', required=True)
contact = SanitizedStr(default='', required=True)
ticket = SanitizedStr(default='', required=True)
gps_location = SanitizedStr(default='', data_key='gpsLocation', required=True)
recycler_code = SanitizedStr(default='', data_key='recyclerCode', required=True)

View File

@ -1,36 +0,0 @@
from distutils.version import StrictVersion
from flask import current_app as app, request, jsonify
from teal.marshmallow import ValidationError
from teal.resource import View
from ereuse_devicehub.db import db
SUPPORTED_WORKBENCH = StrictVersion('11.0')
class ProofView(View):
def post(self):
"""Posts batches of proofs."""
json = request.get_json(validate=False)
if not json:
raise ValidationError('JSON is not correct.')
# todo there should be a way to better get subclassess resource
# defs
proofs = list()
if json['batch']:
for prf in json['proofs']:
resource_def = app.resources[prf['type']]
p = resource_def.schema.load(prf)
Model = db.Model._decl_class_registry.data[prf['type']]()
proof = Model(**p)
db.session.add(proof)
proofs.append(resource_def.schema.dump(proof))
db.session().final_flush()
db.session.commit()
response = jsonify({
'items': proofs,
'url': request.path
})
response.status_code = 201
return response

View File

@ -25,11 +25,10 @@ class User(Thing):
backref=db.backref('users', lazy=True, collection_class=set),
secondary=lambda: UserInventory.__table__,
collection_class=set)
ethereum_address = Column(CIText(), unique=True, default=None)
# todo set restriction that user has, at least, one active db
def __init__(self, email, password=None, ethereum_address=None, inventories=None) -> None:
def __init__(self, email, password=None, inventories=None) -> None:
"""Creates an user.
:param email:
:param password:
@ -38,7 +37,7 @@ class User(Thing):
inventory.
"""
inventories = inventories or {Inventory.current}
super().__init__(email=email, password=password, ethereum_address=ethereum_address, inventories=inventories)
super().__init__(email=email, password=password, inventories=inventories)
def __repr__(self) -> str:
return '<User {0.email}>'.format(self)
@ -52,11 +51,6 @@ class User(Thing):
"""The individual associated for this database, or None."""
return next(iter(self.individuals), None)
@property
def get_ethereum_address(self):
"""The ethereum address in Blockchain, or None."""
return next(iter(self.ethereum_address), None)
class UserInventory(db.Model):
"""Relationship between users and their inventories."""

View File

@ -17,7 +17,6 @@ class User(Thing):
password = ... # type: Column
token = ... # type: Column
inventories = ... # type: relationship
ethereum_address = ... # type: Column
def __init__(self, email: str, password: str = None,
inventories: Set[Inventory] = None) -> None:
@ -28,7 +27,6 @@ class User(Thing):
self.individuals = ... # type: Set[Individual]
self.token = ... # type: UUID
self.inventories = ... # type: Set[Inventory]
self.ethereum_address = ... # type: str
@property
def individual(self) -> Union[Individual, None]:

View File

@ -19,7 +19,6 @@ class User(Thing):
description='Use this token in an Authorization header to access the app.'
'The token can change overtime.')
inventories = NestedOn(Inventory, many=True, dump_only=True)
ethereum_address = String(description='User identifier address inside the Blockchain')
def __init__(self,
only=None,

View File

@ -15,7 +15,7 @@ class UserView(View):
def login():
# We use custom schema as we only want to parse a subset of user
user_s = g.resource_def.SCHEMA(only=('email', 'password', 'ethereum_address')) # type: UserS
user_s = g.resource_def.SCHEMA(only=('email', 'password')) # type: UserS
# noinspection PyArgumentList
u = request.get_json(schema=user_s)
user = User.query.filter_by(email=u['email']).one_or_none()

View File

@ -0,0 +1,10 @@
Box;;Nº Inventary;Type of device;Sub Type;Brand;Model;serial number
;;N006536;PC;;Acer;Veriton M480G;PSV75EZ0070170002C14j00
;;N006549;PC ;;Acer;Veriton M480G;PSV75EZ0070170003714j00
;;N006541;PC ;;Acer;Veriton M480G;
;;N006556;PC;;Acer;Veriton M480G;PSV75EZ0070170001D14j00
;;N006538;PC;;Acer;Veriton M480G;
;;N007465;PC;;Acer;Veriton M480G;PSV75EZ0070170003A14j00
;;;PC;;Acer;Veriton M480G;PSV75EZ007017000361800
;;N006537;PC;;Acer;Veriton M480G;PSV75EZ0070170002214j00
;;N006530;PC;;Acer;Veriton M480G;PSV75EZ0070170000314j00
1 Box Nº Inventary Type of device Sub Type Brand Model serial number
2 N006536 PC Acer Veriton M480G PSV75EZ0070170002C14j00
3 N006549 PC Acer Veriton M480G PSV75EZ0070170003714j00
4 N006541 PC Acer Veriton M480G
5 N006556 PC Acer Veriton M480G PSV75EZ0070170001D14j00
6 N006538 PC Acer Veriton M480G
7 N007465 PC Acer Veriton M480G PSV75EZ0070170003A14j00
8 PC Acer Veriton M480G PSV75EZ007017000361800
9 N006537 PC Acer Veriton M480G PSV75EZ0070170002214j00
10 N006530 PC Acer Veriton M480G PSV75EZ0070170000314j00

View File

@ -279,6 +279,8 @@ def test_live(user: UserClient, client: Client, app: Devicehub):
assert action_live[0].serial_number == 'wd-wx11a80w7430'
assert action_live[0].licence_version == '1.0'
assert str(action_live[0].snapshot_uuid) == acer['uuid']
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -303,6 +305,8 @@ def test_live_example(user: UserClient, client: Client, app: Devicehub):
action_live = [a for a in db_device.actions if a.type == 'Live']
assert len(action_live) == 1
assert str(action_live[0].snapshot_uuid) == acer['uuid']
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -330,6 +334,8 @@ def test_live_two_users(user: UserClient, user2: UserClient, client: Client, app
action_live = [a for a in db_device.actions if a.type == 'Live']
assert len(action_live) == 1
assert str(action_live[0].snapshot_uuid) == acer['uuid']
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -363,6 +369,8 @@ def test_live_two_allocated(user: UserClient, user2: UserClient, client: Client,
live, _ = client.post(acer, res=models.Live, status=422)
message = 'Expected only one Device but multiple where found'
assert live['message'] == message
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -394,6 +402,8 @@ def test_live_without_TestDataStorage(user: UserClient, client: Client, app: Dev
assert live['description'] == description
db_live = models.Live.query.filter_by(id=live['id']).one()
assert db_live.usage_time_hdd is None
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -421,6 +431,8 @@ def test_live_without_hdd_1(user: UserClient, client: Client, app: Devicehub):
acer['licence_version'] = '1.0.0'
response, _ = client.post(acer, res=models.Live, status=404)
assert "The There aren't any disk in this device" in response['message']
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -448,6 +460,8 @@ def test_live_without_hdd_2(user: UserClient, client: Client, app: Devicehub):
acer['licence_version'] = '1.0.0'
response, _ = client.post(acer, res=models.Live, status=404)
assert "The There aren't any disk in this device" in response['message']
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -482,6 +496,8 @@ def test_live_without_hdd_3(user: UserClient, client: Client, app: Devicehub):
db_live = models.Live.query.filter_by(id=live['id']).one()
assert str(db_live.usage_time_hdd) == '195 days, 12:00:00'
assert str(db_live.usage_time_allocate) == '0:00:00'
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -516,6 +532,8 @@ def test_live_with_hdd_with_old_time(user: UserClient, client: Client, app: Devi
db_live = models.Live.query.filter_by(id=live['id']).one()
assert str(db_live.usage_time_hdd) == '191 days, 8:00:00'
assert str(db_live.usage_time_allocate) == '0:00:00'
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -546,6 +564,8 @@ def test_live_search_last_allocate(user: UserClient, client: Client, app: Device
acer['components'][7]['actions'] = actions
live, _ = client.post(acer, res=models.Live)
assert live['usageTimeAllocate'] == 1000
tmp_snapshots = app.config['TMP_LIVES']
shutil.rmtree(tmp_snapshots)
@pytest.mark.mvp
@ -580,7 +600,7 @@ def test_save_live_json(app: Devicehub, user: UserClient, client: Client):
snapshot = {'debug': ''}
if files:
path_snapshot = os.path.join(path_dir_base, files[0])
path_snapshot = os.path.join(path_dir_base, files[-1])
with open(path_snapshot) as file_snapshot:
snapshot = json.loads(file_snapshot.read())

View File

@ -80,7 +80,6 @@ def test_api_docs(client: Client):
'/pack-of-screwdrivers/{dev1_id}/merge/{dev2_id}',
'/printers/{dev1_id}/merge/{dev2_id}',
'/processors/{dev1_id}/merge/{dev2_id}',
'/proofs/',
'/rackets/{dev1_id}/merge/{dev2_id}',
'/ram-modules/{dev1_id}/merge/{dev2_id}',
'/recreations/{dev1_id}/merge/{dev2_id}',
@ -119,4 +118,4 @@ def test_api_docs(client: Client):
'scheme': 'basic',
'name': 'Authorization'
}
assert len(docs['definitions']) == 123
assert len(docs['definitions']) == 117

View File

@ -0,0 +1,38 @@
import os
import ipaddress
import json
import shutil
import copy
import pytest
from datetime import datetime
from dateutil.tz import tzutc
from ereuse_devicehub.client import UserClient
from ereuse_devicehub.devicehub import Devicehub
from ereuse_devicehub.resources.deliverynote.models import Deliverynote
from tests import conftest
@pytest.mark.mvp
@pytest.mark.usefixtures(conftest.app_context.__name__)
def test_simple_deliverynote(user: UserClient, app: Devicehub):
"""
This test create only one deliverinote with the expected Devices
"""
inventory = [{'n_inventory': 'N006536',
'type': 'PC',
'brand': 'Acer',
'model': 'Veriton M480G',
'serial_number': 'PSV75EZ0070170002C14j00'
}]
note = {'date': datetime(2020, 2, 14, 23, 0, tzinfo=tzutc()),
'documentID': 'DocBBE001',
'amount': 0,
'transfer_state': "Initial",
'expectedDevices': inventory,
'supplierEmail': user.user['email']}
deliverynote, _ = user.post(note, res=Deliverynote)
db_note = Deliverynote.query.filter_by(id=deliverynote['id']).one()
assert deliverynote['documentID'] == note['documentID']
assert user.user['email'] in db_note.lot.name

View File

@ -125,9 +125,7 @@ def test_physical_properties():
}
assert pc.physical_properties == {
'chassis': ComputerChassis.Tower,
'deliverynote_address': None,
'deposit': 0,
'ethereum_address': None,
'amount': 0,
'manufacturer': 'bar',
'model': 'foo',
'receiver_id': None,
@ -252,7 +250,7 @@ def test_sync_execute_register_desktop_existing_no_tag():
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object
# 1: device exists on DB
db_pc = Sync().execute_register(pc)
pc.deposit = 0
pc.amount = 0
pc.owner_id = db_pc.owner_id
pc.transfer_state = TransferState.Initial
assert pc.physical_properties == db_pc.physical_properties