diff --git a/ereuse_devicehub/dummy/dummy.py b/ereuse_devicehub/dummy/dummy.py index 89d39893..3528e40a 100644 --- a/ereuse_devicehub/dummy/dummy.py +++ b/ereuse_devicehub/dummy/dummy.py @@ -65,10 +65,11 @@ class Dummy: with click_spinner.spinner(): out = runner.invoke('org', 'add', *self.ORG).output org_id = json.loads(out)['id'] - user = self.user_client('user@dhub.com', '1234') + user1 = self.user_client('user@dhub.com', '1234', 'user1', '0xC79F7fE80B5676fe38D8187b79d55F7A61e702b2') + # todo put user's agent into Org for id in self.TAGS: - user.post({'id': id}, res=Tag) + user1.post({'id': id}, res=Tag) for id, sec in self.ET: runner.invoke('tag', 'add', id, '-p', 'https://t.devicetag.io', @@ -86,7 +87,7 @@ class Dummy: for path in bar: with path.open() as f: snapshot = yaml.load(f) - s, _ = user.post(res=m.Snapshot, data=snapshot) + s, _ = user1.post(res=m.Snapshot, data=snapshot) if s.get('uuid', None) == 'ec23c11b-80b6-42cd-ac5c-73ba7acddbc4': sample_pc = s['device']['id'] else: @@ -94,70 +95,70 @@ class Dummy: if s.get('uuid', None) == 'de4f495e-c58b-40e1-a33e-46ab5e84767e': # oreo # Make one hdd ErasePhysical hdd = next(hdd for hdd in s['components'] if hdd['type'] == 'HardDrive') - user.post({'type': 'ErasePhysical', 'method': 'Shred', 'device': hdd['id']}, + user1.post({'type': 'ErasePhysical', 'method': 'Shred', 'device': hdd['id']}, res=m.Action) assert sample_pc print('PC sample is', sample_pc) # Link tags and eTags for tag, pc in zip((self.TAGS[1], self.TAGS[2], self.ET[0][0], self.ET[1][1]), pcs): - user.put({}, res=Tag, item='{}/device/{}'.format(tag, pc), status=204) + user1.put({}, res=Tag, item='{}/device/{}'.format(tag, pc), status=204) # Perform generic actions for pc, model in zip(pcs, {m.ToRepair, m.Repair, m.ToPrepare, m.Ready, m.ToPrepare, m.Prepare}): - user.post({'type': model.t, 'devices': [pc]}, res=m.Action) + user1.post({'type': model.t, 'devices': [pc]}, res=m.Action) # Perform a Sell to several devices - user.post( + user1.post( { 'type': m.Sell.t, - 'to': user.user['individuals'][0]['id'], + 'to': user1.user['individuals'][0]['id'], 'devices': list(itertools.islice(pcs, len(pcs) // 2)) }, res=m.Action) - parent, _ = user.post(({'name': 'Parent'}), res=Lot) - child, _ = user.post(({'name': 'Child'}), res=Lot) - parent, _ = user.post({}, + parent, _ = user1.post(({'name': 'Parent'}), res=Lot) + child, _ = user1.post(({'name': 'Child'}), res=Lot) + parent, _ = user1.post({}, res=Lot, item='{}/children'.format(parent['id']), query=[('id', child['id'])]) - lot, _ = user.post({}, + lot, _ = user1.post({}, res=Lot, item='{}/devices'.format(child['id']), query=[('id', pc) for pc in itertools.islice(pcs, len(pcs) // 3)]) assert len(lot['devices']) # Keep this at the bottom - inventory, _ = user.get(res=Device) + inventory, _ = user1.get(res=Device) assert len(inventory['items']) - i, _ = user.get(res=Device, query=[('search', 'intel')]) + i, _ = user1.get(res=Device, query=[('search', 'intel')]) assert 12 == len(i['items']) - i, _ = user.get(res=Device, query=[('search', 'pc')]) + i, _ = user1.get(res=Device, query=[('search', 'pc')]) assert 14 == len(i['items']) # Let's create a set of actions for the pc device # Make device Ready - user.post({'type': m.ToPrepare.t, 'devices': [sample_pc]}, res=m.Action) - user.post({'type': m.Prepare.t, 'devices': [sample_pc]}, res=m.Action) - user.post({'type': m.Ready.t, 'devices': [sample_pc]}, res=m.Action) - user.post({'type': m.Price.t, 'device': sample_pc, 'currency': 'EUR', 'price': 85}, + user1.post({'type': m.ToPrepare.t, 'devices': [sample_pc]}, res=m.Action) + user1.post({'type': m.Prepare.t, 'devices': [sample_pc]}, res=m.Action) + user1.post({'type': m.Ready.t, 'devices': [sample_pc]}, res=m.Action) + user1.post({'type': m.Price.t, 'device': sample_pc, 'currency': 'EUR', 'price': 85}, res=m.Action) # todo test reserve - user.post( # Sell device + user1.post( # Sell device { 'type': m.Sell.t, - 'to': user.user['individuals'][0]['id'], + 'to': user1.user['individuals'][0]['id'], 'devices': [sample_pc] }, res=m.Action) # todo Receive - user.get(res=Device, item=sample_pc) # Test + user1.get(res=Device, item=sample_pc) # Test anonymous = self.app.test_client() html, _ = anonymous.get(res=Device, item=sample_pc, accept=ANY) assert 'intel core2 duo cpu' in html @@ -165,12 +166,19 @@ class Dummy: # For netbook: to preapre -> torepair -> to dispose -> disposed print('⭐ Done.') - def user_client(self, email: str, password: str): - user = User(email=email, password=password) - user.individuals.add(Person(name='Timmy')) - db.session.add(user) + def user_client(self, email: str, password: str, name: str, ethereum_address: str): + user1 = User(email=email, password=password, ethereum_address=ethereum_address) + + user2 = User(email='user2@test.com', password='1234', ethereum_address='0x56EbFdbAA98f52027A9776456e4fcD5d91090818') + user3 = User(email='user3@test.com', password='1234', ethereum_address='0xF88618956696aB7e56Cb7bc87d9848E921C4FDaA') + + user1.individuals.add(Person(name=name)) + db.session.add(user1) + db.session.add(user2) + db.session.add(user3) + db.session.commit() - client = UserClient(self.app, user.email, password, + client = UserClient(self.app, user1.email, password, response_wrapper=self.app.response_class) client.login() return client diff --git a/ereuse_devicehub/resources/enums.py b/ereuse_devicehub/resources/enums.py index 956ead04..91502d09 100644 --- a/ereuse_devicehub/resources/enums.py +++ b/ereuse_devicehub/resources/enums.py @@ -370,7 +370,7 @@ class ErasureStandards(Enum): return standards @unique -class TransferState(Enum): +class TransferState(IntEnum): """State of transfer for a given Lot of devices. """ diff --git a/ereuse_devicehub/resources/lot/models.py b/ereuse_devicehub/resources/lot/models.py index ea9ff4d4..4f4862e2 100644 --- a/ereuse_devicehub/resources/lot/models.py +++ b/ereuse_devicehub/resources/lot/models.py @@ -62,7 +62,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) + deposit = db.Column(db.Integer, check_range('deposit', min=0, max=100), default=0) author_id = db.Column(UUID(as_uuid=True), db.ForeignKey(User.id), nullable=False, @@ -70,7 +70,7 @@ class Lot(Thing): author = db.relationship(User, primaryjoin=author_id == User.id) transfer_state = db.Column(IntEnum(TransferState), default=TransferState.Initial, nullable=False) transfer_state.comment = TransferState.__doc__ - receiver_id = db.Column(UUID(as_uuid=False), + receiver_id = db.Column(CIText(), db.ForeignKey(User.ethereum_address), nullable=True, default=lambda: g.user.ethereum_address) diff --git a/ereuse_devicehub/resources/lot/models.pyi b/ereuse_devicehub/resources/lot/models.pyi index 29915d87..872278ef 100644 --- a/ereuse_devicehub/resources/lot/models.pyi +++ b/ereuse_devicehub/resources/lot/models.pyi @@ -44,7 +44,7 @@ class Lot(Thing): self.children = ... # type: Set[Lot] self.author_id = ... # type: UUID self.transfer_state = ... - self.receiver = ... # type: str + self.receiver_id = ... # type: str def add_children(self, *children: Union[Lot, uuid.UUID]): pass diff --git a/ereuse_devicehub/resources/lot/schemas.py b/ereuse_devicehub/resources/lot/schemas.py index 6155313e..95d4190d 100644 --- a/ereuse_devicehub/resources/lot/schemas.py +++ b/ereuse_devicehub/resources/lot/schemas.py @@ -24,4 +24,4 @@ class Lot(Thing): # author_id = NestedOn(s_user.User,only_query='author_id') author_id = f.UUID(dump_only=True) transfer_state = EnumField(TransferState, description=m.Lot.transfer_state.comment) - receiver_id = SanitizedStr(validate=f.validate.Length(max=42)) \ No newline at end of file + receiver_id = SanitizedStr(validate=f.validate.Length(max=42)) diff --git a/ereuse_devicehub/resources/user/models.py b/ereuse_devicehub/resources/user/models.py index a254aaf0..52d32349 100644 --- a/ereuse_devicehub/resources/user/models.py +++ b/ereuse_devicehub/resources/user/models.py @@ -4,6 +4,7 @@ from flask import current_app as app from sqlalchemy import Column from sqlalchemy.dialects.postgresql import UUID from sqlalchemy_utils import EmailType, PasswordType +from citext import CIText from ereuse_devicehub.db import db from ereuse_devicehub.resources.inventory.model import Inventory @@ -24,11 +25,11 @@ class User(Thing): backref=db.backref('users', lazy=True, collection_class=set), secondary=lambda: UserInventory.__table__, collection_class=set) - ethereum_address = Column(UUID(as_uuid=False), unique=True) + 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, inventories=None) -> None: + def __init__(self, email, password=None, ethereum_address=None, inventories=None) -> None: """Creates an user. :param email: :param password: @@ -37,7 +38,7 @@ class User(Thing): inventory. """ inventories = inventories or {Inventory.current} - super().__init__(email=email, password=password, inventories=inventories) + super().__init__(email=email, password=password, ethereum_address=ethereum_address, inventories=inventories) def __repr__(self) -> str: return ''.format(self) @@ -51,6 +52,11 @@ 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.""" diff --git a/ereuse_devicehub/resources/user/models.pyi b/ereuse_devicehub/resources/user/models.pyi index 1cacb052..b3454055 100644 --- a/ereuse_devicehub/resources/user/models.pyi +++ b/ereuse_devicehub/resources/user/models.pyi @@ -28,6 +28,7 @@ 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]: diff --git a/ereuse_devicehub/resources/user/views.py b/ereuse_devicehub/resources/user/views.py index 7053eea7..19624b80 100644 --- a/ereuse_devicehub/resources/user/views.py +++ b/ereuse_devicehub/resources/user/views.py @@ -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')) # type: UserS + user_s = g.resource_def.SCHEMA(only=('email', 'password', 'ethereum_address')) # type: UserS # noinspection PyArgumentList u = request.get_json(schema=user_s) user = User.query.filter_by(email=u['email']).one_or_none()