Small bugfixes
This commit is contained in:
parent
5fb1471d9b
commit
b1aa79fd0a
|
@ -106,7 +106,7 @@ class Client(TealClient):
|
||||||
def login(self, email: str, password: str):
|
def login(self, email: str, password: str):
|
||||||
assert isinstance(email, str)
|
assert isinstance(email, str)
|
||||||
assert isinstance(password, str)
|
assert isinstance(password, str)
|
||||||
return self.post({'email': email, 'password': password}, '/users/login', status=200)
|
return self.post({'email': email, 'password': password}, '/users/login/', status=200)
|
||||||
|
|
||||||
def get_many(self,
|
def get_many(self,
|
||||||
res: ResourceLike,
|
res: ResourceLike,
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for erasure in erasures %}
|
{% for erasure in erasures %}
|
||||||
<tr>
|
<tr>
|
||||||
|
{% if erasure.parent.serial_number %}
|
||||||
<td>
|
<td>
|
||||||
{{ erasure.parent.serial_number.upper() }}
|
{{ erasure.parent.serial_number.upper() }}
|
||||||
</td>
|
</td>
|
||||||
|
{% endif %}
|
||||||
<td>
|
<td>
|
||||||
{{ erasure.parent.tags }}
|
{{ erasure.parent.tags }}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -4,6 +4,7 @@ from uuid import UUID
|
||||||
|
|
||||||
from flask import current_app as app, request
|
from flask import current_app as app, request
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
|
from teal.marshmallow import ValidationError
|
||||||
from teal.resource import View
|
from teal.resource import View
|
||||||
|
|
||||||
from ereuse_devicehub.db import db
|
from ereuse_devicehub.db import db
|
||||||
|
@ -16,6 +17,8 @@ class EventView(View):
|
||||||
def post(self):
|
def post(self):
|
||||||
"""Posts an event."""
|
"""Posts an event."""
|
||||||
json = request.get_json(validate=False)
|
json = request.get_json(validate=False)
|
||||||
|
if 'type' not in json:
|
||||||
|
raise ValidationError('Resource needs a type.')
|
||||||
e = app.resources[json['type']].schema.load(json)
|
e = app.resources[json['type']].schema.load(json)
|
||||||
Model = db.Model._decl_class_registry.data[json['type']]()
|
Model = db.Model._decl_class_registry.data[json['type']]()
|
||||||
event = Model(**e)
|
event = Model(**e)
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Set
|
from typing import Set
|
||||||
|
|
||||||
|
from boltons import urlutils
|
||||||
from sqlalchemy import BigInteger, Column, ForeignKey, Unicode, UniqueConstraint
|
from sqlalchemy import BigInteger, Column, ForeignKey, Unicode, UniqueConstraint
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import backref, relationship, validates
|
from sqlalchemy.orm import backref, relationship, validates
|
||||||
from teal.db import DB_CASCADE_SET_NULL, Query, URL, check_lower
|
from teal.db import DB_CASCADE_SET_NULL, Query, URL, check_lower
|
||||||
from teal.marshmallow import ValidationError
|
from teal.marshmallow import ValidationError
|
||||||
|
from teal.resource import url_for_resource
|
||||||
|
|
||||||
from ereuse_devicehub.resources.agent.models import Organization
|
from ereuse_devicehub.resources.agent.models import Organization
|
||||||
from ereuse_devicehub.resources.device.models import Device
|
from ereuse_devicehub.resources.device.models import Device
|
||||||
|
@ -93,6 +95,21 @@ class Tag(Thing):
|
||||||
def type(self) -> str:
|
def type(self) -> str:
|
||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self) -> urlutils.URL:
|
||||||
|
"""The URL where to GET this device."""
|
||||||
|
# todo this url only works for printable internal tags
|
||||||
|
return urlutils.URL(url_for_resource(Tag, item_id=self.id))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def printable(self) -> bool:
|
||||||
|
"""Can the tag be printed by the user?
|
||||||
|
|
||||||
|
Only tags that are from the default organization can be
|
||||||
|
printed by the user.
|
||||||
|
"""
|
||||||
|
return Organization.get_default_org_id == self.org_id
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return '<Tag {0.id} org:{0.org_id} device:{0.device_id}>'.format(self)
|
return '<Tag {0.id} org:{0.org_id} device:{0.device_id}>'.format(self)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
from boltons import urlutils
|
||||||
from boltons.urlutils import URL
|
from boltons.urlutils import URL
|
||||||
from sqlalchemy import Column
|
from sqlalchemy import Column
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
@ -39,3 +40,11 @@ class Tag(Thing):
|
||||||
|
|
||||||
def like_etag(self) -> bool:
|
def like_etag(self) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def printable(self) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self) -> urlutils.URL:
|
||||||
|
pass
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from sqlalchemy.util import OrderedSet
|
from sqlalchemy.util import OrderedSet
|
||||||
|
from marshmallow.fields import Boolean
|
||||||
from teal.marshmallow import SanitizedStr, URL
|
from teal.marshmallow import SanitizedStr, URL
|
||||||
|
|
||||||
from ereuse_devicehub.marshmallow import NestedOn
|
from ereuse_devicehub.marshmallow import NestedOn
|
||||||
|
@ -23,3 +24,5 @@ class Tag(Thing):
|
||||||
device = NestedOn(Device, dump_only=True)
|
device = NestedOn(Device, dump_only=True)
|
||||||
org = NestedOn(Organization, collection_class=OrderedSet, only_query='id')
|
org = NestedOn(Organization, collection_class=OrderedSet, only_query='id')
|
||||||
secondary = SanitizedStr(lower=True, description=m.Tag.secondary.comment)
|
secondary = SanitizedStr(lower=True, description=m.Tag.secondary.comment)
|
||||||
|
printable = Boolean(dump_only=True, decsription=m.Tag.printable.__doc__)
|
||||||
|
url = URL(dump_only=True, description=m.Tag.url.__doc__)
|
||||||
|
|
|
@ -20,7 +20,7 @@ class UserDef(Resource):
|
||||||
cli_commands = ((self.create_user, 'create-user'),)
|
cli_commands = ((self.create_user, 'create-user'),)
|
||||||
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
|
super().__init__(app, import_name, static_folder, static_url_path, template_folder,
|
||||||
url_prefix, subdomain, url_defaults, root_path, cli_commands)
|
url_prefix, subdomain, url_defaults, root_path, cli_commands)
|
||||||
self.add_url_rule('/login', view_func=login, methods={'POST'})
|
self.add_url_rule('/login/', view_func=login, methods={'POST'})
|
||||||
|
|
||||||
@argument('email')
|
@argument('email')
|
||||||
@option('-a', '--agent', help='The name of an agent to create with the user.')
|
@option('-a', '--agent', help='The name of an agent to create with the user.')
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -12,7 +12,7 @@ test_requires = [
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='ereuse-devicehub',
|
name='ereuse-devicehub',
|
||||||
version='0.2.0b2',
|
version='0.2.0b3',
|
||||||
url='https://github.com/ereuse/devicehub-teal',
|
url='https://github.com/ereuse/devicehub-teal',
|
||||||
project_urls=OrderedDict((
|
project_urls=OrderedDict((
|
||||||
('Documentation', 'http://devicheub.ereuse.org'),
|
('Documentation', 'http://devicheub.ereuse.org'),
|
||||||
|
|
|
@ -22,7 +22,7 @@ def test_api_docs(client: Client):
|
||||||
'/devices/',
|
'/devices/',
|
||||||
'/tags/',
|
'/tags/',
|
||||||
'/snapshots/',
|
'/snapshots/',
|
||||||
'/users/login',
|
'/users/login/',
|
||||||
'/events/',
|
'/events/',
|
||||||
'/lots/',
|
'/lots/',
|
||||||
'/manufacturers/',
|
'/manufacturers/',
|
||||||
|
|
|
@ -74,7 +74,7 @@ def test_login_success(client: Client, app: Devicehub):
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
create_user()
|
create_user()
|
||||||
user, _ = client.post({'email': 'foo@foo.com', 'password': 'foo'},
|
user, _ = client.post({'email': 'foo@foo.com', 'password': 'foo'},
|
||||||
uri='/users/login',
|
uri='/users/login/',
|
||||||
status=200)
|
status=200)
|
||||||
assert user['email'] == 'foo@foo.com'
|
assert user['email'] == 'foo@foo.com'
|
||||||
assert UUID(b64decode(user['token'].encode()).decode()[:-1])
|
assert UUID(b64decode(user['token'].encode()).decode()[:-1])
|
||||||
|
@ -90,12 +90,12 @@ def test_login_failure(client: Client, app: Devicehub):
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
create_user()
|
create_user()
|
||||||
client.post({'email': 'foo@foo.com', 'password': 'wrong pass'},
|
client.post({'email': 'foo@foo.com', 'password': 'wrong pass'},
|
||||||
uri='/users/login',
|
uri='/users/login/',
|
||||||
status=WrongCredentials)
|
status=WrongCredentials)
|
||||||
# Wrong URI
|
# Wrong URI
|
||||||
client.post({}, uri='/wrong-uri', status=NotFound)
|
client.post({}, uri='/wrong-uri', status=NotFound)
|
||||||
# Malformed data
|
# Malformed data
|
||||||
client.post({}, uri='/users/login', status=ValidationError)
|
client.post({}, uri='/users/login/', status=ValidationError)
|
||||||
client.post({'email': 'this is not an email', 'password': 'nope'},
|
client.post({'email': 'this is not an email', 'password': 'nope'},
|
||||||
uri='/users/login',
|
uri='/users/login/',
|
||||||
status=ValidationError)
|
status=ValidationError)
|
||||||
|
|
Reference in a new issue