From b1aa79fd0a30d33d1236a6e054fed4ee072d696f Mon Sep 17 00:00:00 2001 From: Xavier Bustamante Talavera Date: Wed, 16 Jan 2019 20:40:27 +0100 Subject: [PATCH] Small bugfixes --- ereuse_devicehub/client.py | 2 +- .../documents/templates/documents/erasure.html | 8 +++++--- ereuse_devicehub/resources/event/views.py | 3 +++ ereuse_devicehub/resources/tag/model.py | 17 +++++++++++++++++ ereuse_devicehub/resources/tag/model.pyi | 9 +++++++++ ereuse_devicehub/resources/tag/schema.py | 3 +++ ereuse_devicehub/resources/user/__init__.py | 2 +- setup.py | 2 +- tests/test_basic.py | 2 +- tests/test_user.py | 8 ++++---- 10 files changed, 45 insertions(+), 11 deletions(-) diff --git a/ereuse_devicehub/client.py b/ereuse_devicehub/client.py index b5304ed9..b7b38da1 100644 --- a/ereuse_devicehub/client.py +++ b/ereuse_devicehub/client.py @@ -106,7 +106,7 @@ class Client(TealClient): def login(self, email: str, password: str): assert isinstance(email, 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, res: ResourceLike, diff --git a/ereuse_devicehub/resources/documents/templates/documents/erasure.html b/ereuse_devicehub/resources/documents/templates/documents/erasure.html index 908bdbe8..29e1d138 100644 --- a/ereuse_devicehub/resources/documents/templates/documents/erasure.html +++ b/ereuse_devicehub/resources/documents/templates/documents/erasure.html @@ -16,9 +16,11 @@ {% for erasure in erasures %} - - {{ erasure.parent.serial_number.upper() }} - + {% if erasure.parent.serial_number %} + + {{ erasure.parent.serial_number.upper() }} + + {% endif %} {{ erasure.parent.tags }} diff --git a/ereuse_devicehub/resources/event/views.py b/ereuse_devicehub/resources/event/views.py index 30f75a0a..570a4062 100644 --- a/ereuse_devicehub/resources/event/views.py +++ b/ereuse_devicehub/resources/event/views.py @@ -4,6 +4,7 @@ from uuid import UUID from flask import current_app as app, request from sqlalchemy.util import OrderedSet +from teal.marshmallow import ValidationError from teal.resource import View from ereuse_devicehub.db import db @@ -16,6 +17,8 @@ class EventView(View): def post(self): """Posts an event.""" 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) Model = db.Model._decl_class_registry.data[json['type']]() event = Model(**e) diff --git a/ereuse_devicehub/resources/tag/model.py b/ereuse_devicehub/resources/tag/model.py index 85b7d68e..5238d846 100644 --- a/ereuse_devicehub/resources/tag/model.py +++ b/ereuse_devicehub/resources/tag/model.py @@ -1,11 +1,13 @@ from contextlib import suppress from typing import Set +from boltons import urlutils from sqlalchemy import BigInteger, Column, ForeignKey, Unicode, UniqueConstraint from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import backref, relationship, validates from teal.db import DB_CASCADE_SET_NULL, Query, URL, check_lower from teal.marshmallow import ValidationError +from teal.resource import url_for_resource from ereuse_devicehub.resources.agent.models import Organization from ereuse_devicehub.resources.device.models import Device @@ -93,6 +95,21 @@ class Tag(Thing): def type(self) -> str: 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: return ''.format(self) diff --git a/ereuse_devicehub/resources/tag/model.pyi b/ereuse_devicehub/resources/tag/model.pyi index 96082341..8e365551 100644 --- a/ereuse_devicehub/resources/tag/model.pyi +++ b/ereuse_devicehub/resources/tag/model.pyi @@ -1,5 +1,6 @@ from uuid import UUID +from boltons import urlutils from boltons.urlutils import URL from sqlalchemy import Column from sqlalchemy.orm import relationship @@ -39,3 +40,11 @@ class Tag(Thing): def like_etag(self) -> bool: pass + + @property + def printable(self) -> bool: + pass + + @property + def url(self) -> urlutils.URL: + pass diff --git a/ereuse_devicehub/resources/tag/schema.py b/ereuse_devicehub/resources/tag/schema.py index f41532df..22a492d5 100644 --- a/ereuse_devicehub/resources/tag/schema.py +++ b/ereuse_devicehub/resources/tag/schema.py @@ -1,4 +1,5 @@ from sqlalchemy.util import OrderedSet +from marshmallow.fields import Boolean from teal.marshmallow import SanitizedStr, URL from ereuse_devicehub.marshmallow import NestedOn @@ -23,3 +24,5 @@ class Tag(Thing): device = NestedOn(Device, dump_only=True) org = NestedOn(Organization, collection_class=OrderedSet, only_query='id') 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__) diff --git a/ereuse_devicehub/resources/user/__init__.py b/ereuse_devicehub/resources/user/__init__.py index 77ad9677..f3c4b61f 100644 --- a/ereuse_devicehub/resources/user/__init__.py +++ b/ereuse_devicehub/resources/user/__init__.py @@ -20,7 +20,7 @@ class UserDef(Resource): cli_commands = ((self.create_user, 'create-user'),) super().__init__(app, import_name, static_folder, static_url_path, template_folder, 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') @option('-a', '--agent', help='The name of an agent to create with the user.') diff --git a/setup.py b/setup.py index 8f6c261b..70e82c27 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ test_requires = [ setup( name='ereuse-devicehub', - version='0.2.0b2', + version='0.2.0b3', url='https://github.com/ereuse/devicehub-teal', project_urls=OrderedDict(( ('Documentation', 'http://devicheub.ereuse.org'), diff --git a/tests/test_basic.py b/tests/test_basic.py index debb4c64..7fc1a29c 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -22,7 +22,7 @@ def test_api_docs(client: Client): '/devices/', '/tags/', '/snapshots/', - '/users/login', + '/users/login/', '/events/', '/lots/', '/manufacturers/', diff --git a/tests/test_user.py b/tests/test_user.py index 7a8410b5..aab20746 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -74,7 +74,7 @@ def test_login_success(client: Client, app: Devicehub): with app.app_context(): create_user() user, _ = client.post({'email': 'foo@foo.com', 'password': 'foo'}, - uri='/users/login', + uri='/users/login/', status=200) assert user['email'] == 'foo@foo.com' assert UUID(b64decode(user['token'].encode()).decode()[:-1]) @@ -90,12 +90,12 @@ def test_login_failure(client: Client, app: Devicehub): with app.app_context(): create_user() client.post({'email': 'foo@foo.com', 'password': 'wrong pass'}, - uri='/users/login', + uri='/users/login/', status=WrongCredentials) # Wrong URI client.post({}, uri='/wrong-uri', status=NotFound) # 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'}, - uri='/users/login', + uri='/users/login/', status=ValidationError)