resolve conflict
This commit is contained in:
commit
0535a1f310
|
@ -18,6 +18,8 @@ ml).
|
||||||
- [addend] #102 adding endpoint for download metrics
|
- [addend] #102 adding endpoint for download metrics
|
||||||
- [bugfix] #100 fixing bug of scheme live
|
- [bugfix] #100 fixing bug of scheme live
|
||||||
- [bugfix] #101 fixing bug when 2 users have one device and launch one 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]
|
## [1.0.3-beta]
|
||||||
- [addend] #85 add mac of network adapter to device hid
|
- [addend] #85 add mac of network adapter to device hid
|
||||||
|
|
|
@ -9,7 +9,7 @@ from teal.enums import Currency
|
||||||
from teal.utils import import_resource
|
from teal.utils import import_resource
|
||||||
|
|
||||||
from ereuse_devicehub.resources import action, agent, deliverynote, inventory, \
|
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.device import definitions
|
||||||
from ereuse_devicehub.resources.documents import documents
|
from ereuse_devicehub.resources.documents import documents
|
||||||
from ereuse_devicehub.resources.enums import PriceSoftware
|
from ereuse_devicehub.resources.enums import PriceSoftware
|
||||||
|
@ -26,7 +26,6 @@ class DevicehubConfig(Config):
|
||||||
import_resource(agent),
|
import_resource(agent),
|
||||||
import_resource(lot),
|
import_resource(lot),
|
||||||
import_resource(deliverynote),
|
import_resource(deliverynote),
|
||||||
import_resource(proof),
|
|
||||||
import_resource(documents),
|
import_resource(documents),
|
||||||
import_resource(inventory),
|
import_resource(inventory),
|
||||||
import_resource(versions),
|
import_resource(versions),
|
||||||
|
|
|
@ -65,10 +65,10 @@ class Dummy:
|
||||||
with click_spinner.spinner():
|
with click_spinner.spinner():
|
||||||
out = runner.invoke('org', 'add', *self.ORG).output
|
out = runner.invoke('org', 'add', *self.ORG).output
|
||||||
org_id = json.loads(out)['id']
|
org_id = json.loads(out)['id']
|
||||||
user1 = self.user_client('user@dhub.com', '1234', 'user1', '0xC79F7fE80B5676fe38D8187b79d55F7A61e702b2')
|
user1 = self.user_client('user@dhub.com', '1234', 'user1')
|
||||||
user2 = self.user_client('user2@dhub.com', '1234', 'user2', '0x56EbFdbAA98f52027A9776456e4fcD5d91090818')
|
user2 = self.user_client('user2@dhub.com', '1234', 'user2')
|
||||||
user3 = self.user_client('user3@dhub.com', '1234', 'user3', '0xF88618956696aB7e56Cb7bc87d9848E921C4FDaA')
|
user3 = self.user_client('user3@dhub.com', '1234', 'user3')
|
||||||
user4 = self.user_client('user4@dhub.com', '1234', 'user4', '0x37be35ae7eced44ca25e4683e98425fc7830a8a5')
|
user4 = self.user_client('user4@dhub.com', '1234', 'user4')
|
||||||
|
|
||||||
# todo put user's agent into Org
|
# todo put user's agent into Org
|
||||||
for id in self.TAGS:
|
for id in self.TAGS:
|
||||||
|
@ -188,8 +188,8 @@ class Dummy:
|
||||||
# For netbook: to preapre -> torepair -> to dispose -> disposed
|
# For netbook: to preapre -> torepair -> to dispose -> disposed
|
||||||
print('⭐ Done.')
|
print('⭐ Done.')
|
||||||
|
|
||||||
def user_client(self, email: str, password: str, name: str, ethereum_address: str):
|
def user_client(self, email: str, password: str, name: str):
|
||||||
user = User(email=email, password=password, ethereum_address=ethereum_address)
|
user = User(email=email, password=password)
|
||||||
|
|
||||||
user.individuals.add(Person(name=name))
|
user.individuals.add(Person(name=name))
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
|
|
|
@ -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()}'
|
||||||
|
)
|
|
@ -36,7 +36,7 @@ class Deliverynote(Thing):
|
||||||
receiver = db.relationship(User, primaryjoin=lambda: Deliverynote.receiver_address == User.email)
|
receiver = db.relationship(User, primaryjoin=lambda: Deliverynote.receiver_address == User.email)
|
||||||
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
||||||
date.comment = 'The date the DeliveryNote initiated'
|
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
|
# The following fields are supposed to be 0:N relationships
|
||||||
# to SnapshotDelivery entity.
|
# to SnapshotDelivery entity.
|
||||||
# At this stage of implementation they will treated as a
|
# 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)
|
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 = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False)
|
||||||
transfer_state.comment = TransferState.__doc__
|
transfer_state.comment = TransferState.__doc__
|
||||||
ethereum_address = db.Column(CIText(), unique=True, default=None)
|
|
||||||
lot_id = db.Column(UUID(as_uuid=True),
|
lot_id = db.Column(UUID(as_uuid=True),
|
||||||
db.ForeignKey(Lot.id),
|
db.ForeignKey(Lot.id),
|
||||||
nullable=False)
|
nullable=False)
|
||||||
|
@ -55,14 +54,14 @@ class Deliverynote(Thing):
|
||||||
lazy=True,
|
lazy=True,
|
||||||
primaryjoin=Lot.id == lot_id)
|
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,
|
supplier_email: str,
|
||||||
expected_devices: Iterable,
|
expected_devices: Iterable,
|
||||||
transfer_state: TransferState) -> None:
|
transfer_state: TransferState) -> None:
|
||||||
"""Initializes a delivery note
|
"""Initializes a delivery note
|
||||||
"""
|
"""
|
||||||
super().__init__(id=uuid.uuid4(),
|
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,
|
supplier_email=supplier_email,
|
||||||
expected_devices=expected_devices,
|
expected_devices=expected_devices,
|
||||||
transfer_state=transfer_state)
|
transfer_state=transfer_state)
|
||||||
|
|
|
@ -24,13 +24,12 @@ class Lot(Thing):
|
||||||
description = ... # type: Column
|
description = ... # type: Column
|
||||||
all_devices = ... # type: relationship
|
all_devices = ... # type: relationship
|
||||||
parents = ... # type: relationship
|
parents = ... # type: relationship
|
||||||
deposit = ... # type: Column
|
amount = ... # type: Column
|
||||||
owner_address = ... # type: Column
|
owner_address = ... # type: Column
|
||||||
owner = ... # type: relationship
|
owner = ... # type: relationship
|
||||||
transfer_state = ... # type: Column
|
transfer_state = ... # type: Column
|
||||||
receiver_address = ... # type: Column
|
receiver_address = ... # type: Column
|
||||||
receiver = ... # type: relationship
|
receiver = ... # type: relationship
|
||||||
deliverynote_address = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, name: str, closed: bool = closed.default.arg) -> None:
|
def __init__(self, name: str, closed: bool = closed.default.arg) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -46,7 +45,6 @@ class Lot(Thing):
|
||||||
self.owner_address = ... # type: UUID
|
self.owner_address = ... # type: UUID
|
||||||
self.transfer_state = ...
|
self.transfer_state = ...
|
||||||
self.receiver_address = ... # type: str
|
self.receiver_address = ... # type: str
|
||||||
self.deliverynote_address = ... # type: str
|
|
||||||
|
|
||||||
def add_children(self, *children: Union[Lot, uuid.UUID]):
|
def add_children(self, *children: Union[Lot, uuid.UUID]):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -19,9 +19,8 @@ class Deliverynote(Thing):
|
||||||
supplier = NestedOn(s_user.User, dump_only=True)
|
supplier = NestedOn(s_user.User, dump_only=True)
|
||||||
receiver = NestedOn(s_user.User, dump_only=True)
|
receiver = NestedOn(s_user.User, dump_only=True)
|
||||||
date = f.DateTime('iso', required=True)
|
date = f.DateTime('iso', required=True)
|
||||||
deposit = f.Integer(validate=f.validate.Range(min=0, max=100),
|
amount = f.Integer(validate=f.validate.Range(min=0, max=100),
|
||||||
description=m.Deliverynote.deposit.__doc__)
|
description=m.Deliverynote.amount.__doc__)
|
||||||
ethereum_address = f.String(description='User identifier address inside the Blockchain')
|
|
||||||
expected_devices = f.List(f.Dict, required=True, data_key='expectedDevices')
|
expected_devices = f.List(f.Dict, required=True, data_key='expectedDevices')
|
||||||
transferred_devices = f.List(f.Integer(), required=False, data_key='transferredDevices')
|
transferred_devices = f.List(f.Integer(), required=False, data_key='transferredDevices')
|
||||||
transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment)
|
transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment)
|
||||||
|
|
|
@ -28,21 +28,13 @@ class DeliverynoteView(View):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def patch(self, id):
|
def patch(self, id):
|
||||||
patch_schema = self.resource_def.SCHEMA(only=('transfer_state',
|
patch_schema = self.resource_def.SCHEMA(only=('transfer_state'), partial=True)
|
||||||
'ethereum_address'), partial=True)
|
|
||||||
d = request.get_json(schema=patch_schema)
|
d = request.get_json(schema=patch_schema)
|
||||||
dlvnote = Deliverynote.query.filter_by(id=id).one()
|
dlvnote = Deliverynote.query.filter_by(id=id).one()
|
||||||
# device_fields = ['transfer_state', 'deliverynote_address']
|
# device_fields = ['transfer_state', 'deliverynote_address']
|
||||||
# computers = [x for x in dlvnote.transferred_devices if isinstance(x, Computer)]
|
# computers = [x for x in dlvnote.transferred_devices if isinstance(x, Computer)]
|
||||||
for key, value in d.items():
|
for key, value in d.items():
|
||||||
setattr(dlvnote, key, value)
|
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()
|
db.session.commit()
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
|
|
|
@ -471,8 +471,7 @@ class Computer(Device):
|
||||||
|
|
||||||
It is a subset of the Linux definition of DMI / DMI decode.
|
It is a subset of the Linux definition of DMI / DMI decode.
|
||||||
"""
|
"""
|
||||||
ethereum_address = Column(CIText(), unique=True, default=None)
|
amount = Column(Integer, check_range('amount', min=0, max=100), default=0)
|
||||||
deposit = Column(Integer, check_range('deposit', min=0, max=100), default=0)
|
|
||||||
owner_id = db.Column(UUID(as_uuid=True),
|
owner_id = db.Column(UUID(as_uuid=True),
|
||||||
db.ForeignKey(User.id),
|
db.ForeignKey(User.id),
|
||||||
nullable=False,
|
nullable=False,
|
||||||
|
@ -484,7 +483,6 @@ class Computer(Device):
|
||||||
db.ForeignKey(User.id),
|
db.ForeignKey(User.id),
|
||||||
nullable=True)
|
nullable=True)
|
||||||
receiver = db.relationship(User, primaryjoin=receiver_id == User.id)
|
receiver = db.relationship(User, primaryjoin=receiver_id == User.id)
|
||||||
deliverynote_address = db.Column(CIText(), nullable=True)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
if args:
|
if args:
|
||||||
|
|
|
@ -141,11 +141,10 @@ class DisplayMixin:
|
||||||
class Computer(DisplayMixin, Device):
|
class Computer(DisplayMixin, Device):
|
||||||
components = ... # type: Column
|
components = ... # type: Column
|
||||||
chassis = ... # type: Column
|
chassis = ... # type: Column
|
||||||
deposit = ... # type: Column
|
amount = ... # type: Column
|
||||||
owner_address = ... # type: Column
|
owner_address = ... # type: Column
|
||||||
transfer_state = ... # type: Column
|
transfer_state = ... # type: Column
|
||||||
receiver_address = ... # type: Column
|
receiver_id = ... # uuid: Column
|
||||||
deliverynote_address = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
def __init__(self, **kwargs) -> None:
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
@ -155,7 +154,6 @@ class Computer(DisplayMixin, Device):
|
||||||
self.owner_address = ... # type: UUID
|
self.owner_address = ... # type: UUID
|
||||||
self.transfer_state = ...
|
self.transfer_state = ...
|
||||||
self.receiver_address = ... # type: str
|
self.receiver_address = ... # type: str
|
||||||
self.deliverynote_address = ... # type: str
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def actions(self) -> List:
|
def actions(self) -> List:
|
||||||
|
|
|
@ -123,14 +123,12 @@ class Computer(Device):
|
||||||
dump_only=True,
|
dump_only=True,
|
||||||
collection_class=set,
|
collection_class=set,
|
||||||
description=m.Computer.privacy.__doc__)
|
description=m.Computer.privacy.__doc__)
|
||||||
ethereum_address = SanitizedStr(validate=f.validate.Length(max=42))
|
amount = Integer(validate=f.validate.Range(min=0, max=100),
|
||||||
deposit = Integer(validate=f.validate.Range(min=0, max=100),
|
description=m.Computer.amount.__doc__)
|
||||||
description=m.Computer.deposit.__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')
|
owner_id = UUID(data_key='ownerID')
|
||||||
transfer_state = EnumField(enums.TransferState, description=m.Computer.transfer_state.comment)
|
transfer_state = EnumField(enums.TransferState, description=m.Computer.transfer_state.comment)
|
||||||
receiver_id = UUID(data_key='receiverID')
|
receiver_id = UUID(data_key='receiverID')
|
||||||
deliverynote_address = SanitizedStr(validate=f.validate.Length(max=42))
|
|
||||||
|
|
||||||
|
|
||||||
class Desktop(Computer):
|
class Desktop(Computer):
|
||||||
|
|
|
@ -106,7 +106,7 @@ class DeviceView(View):
|
||||||
resource_def = app.resources['Computer']
|
resource_def = app.resources['Computer']
|
||||||
# TODO check how to handle the 'actions_one'
|
# TODO check how to handle the 'actions_one'
|
||||||
patch_schema = resource_def.SCHEMA(
|
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)
|
json = request.get_json(schema=patch_schema)
|
||||||
# TODO check how to handle the 'actions_one'
|
# TODO check how to handle the 'actions_one'
|
||||||
json.pop('actions_one')
|
json.pop('actions_one')
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Lot(Thing):
|
||||||
"""All devices, including components, inside this lot and its
|
"""All devices, including components, inside this lot and its
|
||||||
descendants.
|
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),
|
owner_id = db.Column(UUID(as_uuid=True),
|
||||||
db.ForeignKey(User.id),
|
db.ForeignKey(User.id),
|
||||||
nullable=False,
|
nullable=False,
|
||||||
|
@ -72,10 +72,10 @@ class Lot(Thing):
|
||||||
transfer_state = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False)
|
transfer_state = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False)
|
||||||
transfer_state.comment = TransferState.__doc__
|
transfer_state.comment = TransferState.__doc__
|
||||||
receiver_address = db.Column(CIText(),
|
receiver_address = db.Column(CIText(),
|
||||||
db.ForeignKey(User.ethereum_address),
|
db.ForeignKey(User.email),
|
||||||
nullable=True)
|
nullable=False,
|
||||||
receiver = db.relationship(User, primaryjoin=receiver_address == User.ethereum_address)
|
default=lambda: g.user.email)
|
||||||
deliverynote_address = db.Column(CIText(), nullable=True)
|
receiver = db.relationship(User, primaryjoin=receiver_address == User.email)
|
||||||
|
|
||||||
def __init__(self, name: str, closed: bool = closed.default.arg,
|
def __init__(self, name: str, closed: bool = closed.default.arg,
|
||||||
description: str = None) -> None:
|
description: str = None) -> None:
|
||||||
|
|
|
@ -24,13 +24,12 @@ class Lot(Thing):
|
||||||
description = ... # type: Column
|
description = ... # type: Column
|
||||||
all_devices = ... # type: relationship
|
all_devices = ... # type: relationship
|
||||||
parents = ... # type: relationship
|
parents = ... # type: relationship
|
||||||
deposit = ... # type: Column
|
amount = ... # type: Column
|
||||||
owner_address = ... # type: Column
|
owner_address = ... # type: Column
|
||||||
owner = ... # type: relationship
|
owner = ... # type: relationship
|
||||||
transfer_state = ... # type: Column
|
transfer_state = ... # type: Column
|
||||||
receiver_address = ... # type: Column
|
receiver_address = ... # type: Column
|
||||||
receiver = ... # type: relationship
|
receiver = ... # type: relationship
|
||||||
deliverynote_address = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, name: str, closed: bool = closed.default.arg) -> None:
|
def __init__(self, name: str, closed: bool = closed.default.arg) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -46,7 +45,6 @@ class Lot(Thing):
|
||||||
self.owner_address = ... # type: UUID
|
self.owner_address = ... # type: UUID
|
||||||
self.transfer_state = ...
|
self.transfer_state = ...
|
||||||
self.receiver_address = ... # type: str
|
self.receiver_address = ... # type: str
|
||||||
self.deliverynote_address = ... # type: str
|
|
||||||
|
|
||||||
def add_children(self, *children: Union[Lot, uuid.UUID]):
|
def add_children(self, *children: Union[Lot, uuid.UUID]):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -19,8 +19,8 @@ class Lot(Thing):
|
||||||
children = NestedOn('Lot', many=True, dump_only=True)
|
children = NestedOn('Lot', many=True, dump_only=True)
|
||||||
parents = 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__)
|
url = URL(dump_only=True, description=m.Lot.url.__doc__)
|
||||||
deposit = f.Integer(validate=f.validate.Range(min=0, max=100),
|
amount = f.Integer(validate=f.validate.Range(min=0, max=100),
|
||||||
description=m.Lot.deposit.__doc__)
|
description=m.Lot.amount.__doc__)
|
||||||
# author_id = NestedOn(s_user.User,only_query='author_id')
|
# author_id = NestedOn(s_user.User,only_query='author_id')
|
||||||
owner_id = f.UUID(data_key='ownerID')
|
owner_id = f.UUID(data_key='ownerID')
|
||||||
transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment)
|
transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment)
|
||||||
|
|
|
@ -41,11 +41,11 @@ class LotView(View):
|
||||||
|
|
||||||
def patch(self, id):
|
def patch(self, id):
|
||||||
patch_schema = self.resource_def.SCHEMA(only=(
|
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)
|
'owner_address'), partial=True)
|
||||||
l = request.get_json(schema=patch_schema)
|
l = request.get_json(schema=patch_schema)
|
||||||
lot = Lot.query.filter_by(id=id).one()
|
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)]
|
computers = [x for x in lot.all_devices if isinstance(x, Computer)]
|
||||||
for key, value in l.items():
|
for key, value in l.items():
|
||||||
setattr(lot, key, value)
|
setattr(lot, key, value)
|
||||||
|
@ -142,9 +142,9 @@ class LotView(View):
|
||||||
if path:
|
if path:
|
||||||
cls._p(node['nodes'], path)
|
cls._p(node['nodes'], path)
|
||||||
|
|
||||||
def get_lot_deposit(self, l: Lot):
|
def get_lot_amount(self, l: Lot):
|
||||||
"""Return lot deposit value"""
|
"""Return lot amount value"""
|
||||||
return l.deposit
|
return l.amount
|
||||||
|
|
||||||
def change_state(self):
|
def change_state(self):
|
||||||
"""Change state of Lot"""
|
"""Change state of Lot"""
|
||||||
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -25,11 +25,10 @@ class User(Thing):
|
||||||
backref=db.backref('users', lazy=True, collection_class=set),
|
backref=db.backref('users', lazy=True, collection_class=set),
|
||||||
secondary=lambda: UserInventory.__table__,
|
secondary=lambda: UserInventory.__table__,
|
||||||
collection_class=set)
|
collection_class=set)
|
||||||
ethereum_address = Column(CIText(), unique=True, default=None)
|
|
||||||
|
|
||||||
# todo set restriction that user has, at least, one active db
|
# 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.
|
"""Creates an user.
|
||||||
:param email:
|
:param email:
|
||||||
:param password:
|
:param password:
|
||||||
|
@ -38,7 +37,7 @@ class User(Thing):
|
||||||
inventory.
|
inventory.
|
||||||
"""
|
"""
|
||||||
inventories = inventories or {Inventory.current}
|
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:
|
def __repr__(self) -> str:
|
||||||
return '<User {0.email}>'.format(self)
|
return '<User {0.email}>'.format(self)
|
||||||
|
@ -52,11 +51,6 @@ class User(Thing):
|
||||||
"""The individual associated for this database, or None."""
|
"""The individual associated for this database, or None."""
|
||||||
return next(iter(self.individuals), 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):
|
class UserInventory(db.Model):
|
||||||
"""Relationship between users and their inventories."""
|
"""Relationship between users and their inventories."""
|
||||||
|
|
|
@ -17,7 +17,6 @@ class User(Thing):
|
||||||
password = ... # type: Column
|
password = ... # type: Column
|
||||||
token = ... # type: Column
|
token = ... # type: Column
|
||||||
inventories = ... # type: relationship
|
inventories = ... # type: relationship
|
||||||
ethereum_address = ... # type: Column
|
|
||||||
|
|
||||||
def __init__(self, email: str, password: str = None,
|
def __init__(self, email: str, password: str = None,
|
||||||
inventories: Set[Inventory] = None) -> None:
|
inventories: Set[Inventory] = None) -> None:
|
||||||
|
@ -28,7 +27,6 @@ class User(Thing):
|
||||||
self.individuals = ... # type: Set[Individual]
|
self.individuals = ... # type: Set[Individual]
|
||||||
self.token = ... # type: UUID
|
self.token = ... # type: UUID
|
||||||
self.inventories = ... # type: Set[Inventory]
|
self.inventories = ... # type: Set[Inventory]
|
||||||
self.ethereum_address = ... # type: str
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def individual(self) -> Union[Individual, None]:
|
def individual(self) -> Union[Individual, None]:
|
||||||
|
|
|
@ -19,7 +19,6 @@ class User(Thing):
|
||||||
description='Use this token in an Authorization header to access the app.'
|
description='Use this token in an Authorization header to access the app.'
|
||||||
'The token can change overtime.')
|
'The token can change overtime.')
|
||||||
inventories = NestedOn(Inventory, many=True, dump_only=True)
|
inventories = NestedOn(Inventory, many=True, dump_only=True)
|
||||||
ethereum_address = String(description='User identifier address inside the Blockchain')
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
only=None,
|
only=None,
|
||||||
|
|
|
@ -15,7 +15,7 @@ class UserView(View):
|
||||||
|
|
||||||
def login():
|
def login():
|
||||||
# We use custom schema as we only want to parse a subset of user
|
# 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
|
# noinspection PyArgumentList
|
||||||
u = request.get_json(schema=user_s)
|
u = request.get_json(schema=user_s)
|
||||||
user = User.query.filter_by(email=u['email']).one_or_none()
|
user = User.query.filter_by(email=u['email']).one_or_none()
|
||||||
|
|
|
@ -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
|
|
|
@ -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].serial_number == 'wd-wx11a80w7430'
|
||||||
assert action_live[0].licence_version == '1.0'
|
assert action_live[0].licence_version == '1.0'
|
||||||
assert str(action_live[0].snapshot_uuid) == acer['uuid']
|
assert str(action_live[0].snapshot_uuid) == acer['uuid']
|
||||||
|
tmp_snapshots = app.config['TMP_LIVES']
|
||||||
|
shutil.rmtree(tmp_snapshots)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@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']
|
action_live = [a for a in db_device.actions if a.type == 'Live']
|
||||||
assert len(action_live) == 1
|
assert len(action_live) == 1
|
||||||
assert str(action_live[0].snapshot_uuid) == acer['uuid']
|
assert str(action_live[0].snapshot_uuid) == acer['uuid']
|
||||||
|
tmp_snapshots = app.config['TMP_LIVES']
|
||||||
|
shutil.rmtree(tmp_snapshots)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@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']
|
action_live = [a for a in db_device.actions if a.type == 'Live']
|
||||||
assert len(action_live) == 1
|
assert len(action_live) == 1
|
||||||
assert str(action_live[0].snapshot_uuid) == acer['uuid']
|
assert str(action_live[0].snapshot_uuid) == acer['uuid']
|
||||||
|
tmp_snapshots = app.config['TMP_LIVES']
|
||||||
|
shutil.rmtree(tmp_snapshots)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@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)
|
live, _ = client.post(acer, res=models.Live, status=422)
|
||||||
message = 'Expected only one Device but multiple where found'
|
message = 'Expected only one Device but multiple where found'
|
||||||
assert live['message'] == message
|
assert live['message'] == message
|
||||||
|
tmp_snapshots = app.config['TMP_LIVES']
|
||||||
|
shutil.rmtree(tmp_snapshots)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
|
@ -394,6 +402,8 @@ def test_live_without_TestDataStorage(user: UserClient, client: Client, app: Dev
|
||||||
assert live['description'] == description
|
assert live['description'] == description
|
||||||
db_live = models.Live.query.filter_by(id=live['id']).one()
|
db_live = models.Live.query.filter_by(id=live['id']).one()
|
||||||
assert db_live.usage_time_hdd is None
|
assert db_live.usage_time_hdd is None
|
||||||
|
tmp_snapshots = app.config['TMP_LIVES']
|
||||||
|
shutil.rmtree(tmp_snapshots)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@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'
|
acer['licence_version'] = '1.0.0'
|
||||||
response, _ = client.post(acer, res=models.Live, status=404)
|
response, _ = client.post(acer, res=models.Live, status=404)
|
||||||
assert "The There aren't any disk in this device" in response['message']
|
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
|
@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'
|
acer['licence_version'] = '1.0.0'
|
||||||
response, _ = client.post(acer, res=models.Live, status=404)
|
response, _ = client.post(acer, res=models.Live, status=404)
|
||||||
assert "The There aren't any disk in this device" in response['message']
|
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
|
@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()
|
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_hdd) == '195 days, 12:00:00'
|
||||||
assert str(db_live.usage_time_allocate) == '0: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
|
@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()
|
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_hdd) == '191 days, 8:00:00'
|
||||||
assert str(db_live.usage_time_allocate) == '0: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
|
@pytest.mark.mvp
|
||||||
|
@ -546,6 +564,8 @@ def test_live_search_last_allocate(user: UserClient, client: Client, app: Device
|
||||||
acer['components'][7]['actions'] = actions
|
acer['components'][7]['actions'] = actions
|
||||||
live, _ = client.post(acer, res=models.Live)
|
live, _ = client.post(acer, res=models.Live)
|
||||||
assert live['usageTimeAllocate'] == 1000
|
assert live['usageTimeAllocate'] == 1000
|
||||||
|
tmp_snapshots = app.config['TMP_LIVES']
|
||||||
|
shutil.rmtree(tmp_snapshots)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.mvp
|
@pytest.mark.mvp
|
||||||
|
@ -580,7 +600,7 @@ def test_save_live_json(app: Devicehub, user: UserClient, client: Client):
|
||||||
|
|
||||||
snapshot = {'debug': ''}
|
snapshot = {'debug': ''}
|
||||||
if files:
|
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:
|
with open(path_snapshot) as file_snapshot:
|
||||||
snapshot = json.loads(file_snapshot.read())
|
snapshot = json.loads(file_snapshot.read())
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,6 @@ def test_api_docs(client: Client):
|
||||||
'/pack-of-screwdrivers/{dev1_id}/merge/{dev2_id}',
|
'/pack-of-screwdrivers/{dev1_id}/merge/{dev2_id}',
|
||||||
'/printers/{dev1_id}/merge/{dev2_id}',
|
'/printers/{dev1_id}/merge/{dev2_id}',
|
||||||
'/processors/{dev1_id}/merge/{dev2_id}',
|
'/processors/{dev1_id}/merge/{dev2_id}',
|
||||||
'/proofs/',
|
|
||||||
'/rackets/{dev1_id}/merge/{dev2_id}',
|
'/rackets/{dev1_id}/merge/{dev2_id}',
|
||||||
'/ram-modules/{dev1_id}/merge/{dev2_id}',
|
'/ram-modules/{dev1_id}/merge/{dev2_id}',
|
||||||
'/recreations/{dev1_id}/merge/{dev2_id}',
|
'/recreations/{dev1_id}/merge/{dev2_id}',
|
||||||
|
@ -119,4 +118,4 @@ def test_api_docs(client: Client):
|
||||||
'scheme': 'basic',
|
'scheme': 'basic',
|
||||||
'name': 'Authorization'
|
'name': 'Authorization'
|
||||||
}
|
}
|
||||||
assert len(docs['definitions']) == 123
|
assert len(docs['definitions']) == 117
|
||||||
|
|
|
@ -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
|
|
@ -125,9 +125,7 @@ def test_physical_properties():
|
||||||
}
|
}
|
||||||
assert pc.physical_properties == {
|
assert pc.physical_properties == {
|
||||||
'chassis': ComputerChassis.Tower,
|
'chassis': ComputerChassis.Tower,
|
||||||
'deliverynote_address': None,
|
'amount': 0,
|
||||||
'deposit': 0,
|
|
||||||
'ethereum_address': None,
|
|
||||||
'manufacturer': 'bar',
|
'manufacturer': 'bar',
|
||||||
'model': 'foo',
|
'model': 'foo',
|
||||||
'receiver_id': None,
|
'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
|
**conftest.file('pc-components.db')['device']) # Create a new transient non-db object
|
||||||
# 1: device exists on DB
|
# 1: device exists on DB
|
||||||
db_pc = Sync().execute_register(pc)
|
db_pc = Sync().execute_register(pc)
|
||||||
pc.deposit = 0
|
pc.amount = 0
|
||||||
pc.owner_id = db_pc.owner_id
|
pc.owner_id = db_pc.owner_id
|
||||||
pc.transfer_state = TransferState.Initial
|
pc.transfer_state = TransferState.Initial
|
||||||
assert pc.physical_properties == db_pc.physical_properties
|
assert pc.physical_properties == db_pc.physical_properties
|
||||||
|
|
Reference in New Issue