diff --git a/ereuse_devicehub/config.py b/ereuse_devicehub/config.py index a77fc614..029ca1c2 100644 --- a/ereuse_devicehub/config.py +++ b/ereuse_devicehub/config.py @@ -2,6 +2,7 @@ from distutils.version import StrictVersion from itertools import chain from typing import Set +import boltons.urlutils from teal.auth import TokenAuth from teal.config import Config from teal.enums import Currency @@ -59,8 +60,14 @@ class DevicehubConfig(Config): """ Official versions """ + TAG_BASE_URL = None + TAG_TOKEN = None + """Access to the tag provider.""" def __init__(self, db: str = None) -> None: if not self.ORGANIZATION_NAME or not self.ORGANIZATION_TAX_ID: raise ValueError('You need to set the main organization parameters.') + if not self.TAG_BASE_URL or not self.TAG_TOKEN: + raise ValueError('You need a tag service.') + self.TAG_BASE_URL = boltons.urlutils.URL(self.TAG_BASE_URL) super().__init__(db) diff --git a/ereuse_devicehub/devicehub.py b/ereuse_devicehub/devicehub.py index aa6ee8be..43e93648 100644 --- a/ereuse_devicehub/devicehub.py +++ b/ereuse_devicehub/devicehub.py @@ -1,5 +1,6 @@ from typing import Type +from ereuse_utils.session import DevicehubClient from flask_sqlalchemy import SQLAlchemy from sqlalchemy import event from teal.config import Config as ConfigClass @@ -33,6 +34,7 @@ class Devicehub(Teal): super().__init__(config, db, import_name, static_url_path, static_folder, static_host, host_matching, subdomain_matching, template_folder, instance_path, instance_relative_config, root_path, Auth) + self.tag_provider = DevicehubClient(**self.config.get_namespace('TAG_')) self.dummy = Dummy(self) self.before_request(self.register_db_events_listeners) self.cli.command('regenerate-search')(self.regenerate_search) diff --git a/ereuse_devicehub/resources/tag/model.py b/ereuse_devicehub/resources/tag/model.py index 5238d846..850e09e6 100644 --- a/ereuse_devicehub/resources/tag/model.py +++ b/ereuse_devicehub/resources/tag/model.py @@ -108,7 +108,7 @@ class Tag(Thing): Only tags that are from the default organization can be printed by the user. """ - return Organization.get_default_org_id == self.org_id + return Organization.get_default_org_id() == self.org_id def __repr__(self) -> str: return ''.format(self) diff --git a/ereuse_devicehub/resources/tag/view.py b/ereuse_devicehub/resources/tag/view.py index 4d756aeb..6fae8e88 100644 --- a/ereuse_devicehub/resources/tag/view.py +++ b/ereuse_devicehub/resources/tag/view.py @@ -1,4 +1,5 @@ -from flask import Response, current_app as app, redirect, request +from ereuse_utils.session import DevicehubClient +from flask import Response, current_app, current_app as app, jsonify, redirect, request from teal.marshmallow import ValidationError from teal.resource import View, url_for_resource @@ -10,6 +11,25 @@ from ereuse_devicehub.resources.tag import Tag class TagView(View): def post(self): """Creates a tag.""" + num = request.args.get('num', type=int) + if num: + res = self._create_many_regular_tags(num) + else: + res = self._post_one() + return res + + def _create_many_regular_tags(self, num: int): + tag_provider = current_app.tag_provider # type: DevicehubClient + tags_id, _ = tag_provider.post('/', {}, query=[('num', num)]) + tags = [Tag(id=tag_id, provider=current_app.config['TAG_BASE_URL']) for tag_id in tags_id] + db.session.add_all(tags) + db.session.commit() + response = jsonify(items=self.schema.dump(tags, many=True, nested=1)) # type: Response + response.status_code = 201 + return response + + def _post_one(self): + # todo do we use this? t = request.get_json() tag = Tag(**t) if tag.like_etag(): diff --git a/ereuse_devicehub/resources/user/schemas.py b/ereuse_devicehub/resources/user/schemas.py index e60ff1f8..db6497af 100644 --- a/ereuse_devicehub/resources/user/schemas.py +++ b/ereuse_devicehub/resources/user/schemas.py @@ -1,9 +1,8 @@ -from base64 import b64encode - from marshmallow import post_dump from marshmallow.fields import Email, String, UUID from teal.marshmallow import SanitizedStr +from ereuse_devicehub import auth from ereuse_devicehub.marshmallow import NestedOn from ereuse_devicehub.resources.agent.schemas import Individual from ereuse_devicehub.resources.schemas import Thing @@ -42,5 +41,5 @@ class User(Thing): if 'token' in data: # In many cases we don't dump the token (ex. relationships) # Framework needs ':' at the end - data['token'] = b64encode(str.encode(str(data['token']) + ':')).decode() + data['token'] = auth.Auth.encode(data['token']) return data diff --git a/setup.py b/setup.py index 70e82c27..0e941894 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ setup( 'teal>=0.2.0a32', # teal always first 'click', 'click-spinner', - 'ereuse-utils[Naming]>=0.4b13', + 'ereuse-utils[Naming]>=0.4b14', 'hashids', 'marshmallow_enum', 'psycopg2-binary', diff --git a/tests/conftest.py b/tests/conftest.py index 5fdfe479..d4ec0e36 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,6 +31,8 @@ class TestConfig(DevicehubConfig): ORGANIZATION_NAME = 'FooOrg' ORGANIZATION_TAX_ID = 'foo-org-id' SERVER_NAME = 'localhost' + TAG_BASE_URL = 'https://example.com' + TAG_TOKEN = 'tagToken' @pytest.fixture(scope='session') diff --git a/tests/test_tag.py b/tests/test_tag.py index 476cdd18..faf525e4 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -1,6 +1,7 @@ import pathlib import pytest +import requests_mock from boltons.urlutils import URL from pytest import raises from teal.db import MultipleResourcesFound, ResourceNotFound, UniqueViolation @@ -232,3 +233,20 @@ def test_tag_multiple_secondary_org(user: UserClient): """Ensures two secondary ids cannot be part of the same Org.""" user.post({'id': 'foo', 'secondary': 'bar'}, res=Tag) user.post({'id': 'foo1', 'secondary': 'bar'}, res=Tag, status=UniqueViolation) + + +def test_crate_num_regular_tags(user: UserClient, requests_mock: requests_mock.mocker.Mocker): + """Create regular tags. This is done using a tag provider that + returns IDs. These tags are printable. + """ + requests_mock.post('https://example.com/', + # request + request_headers={'Authorization': 'Basic tagToken'}, + # response + json=['tag1id', 'tag2id'], + status_code=201) + data, _ = user.post({}, res=Tag, query=[('num', 2)]) + assert data['items'][0]['id'] == 'tag1id' + assert data['items'][0]['printable'], 'Tags made this way are printable' + assert data['items'][1]['id'] == 'tag2id' + assert data['items'][1]['printable'] diff --git a/tests/test_user.py b/tests/test_user.py index aab20746..a92ecd70 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,4 +1,3 @@ -from base64 import b64decode from uuid import UUID import pytest @@ -7,6 +6,7 @@ from teal.enums import Country from teal.marshmallow import ValidationError from werkzeug.exceptions import NotFound +from ereuse_devicehub import auth from ereuse_devicehub.client import Client from ereuse_devicehub.db import db from ereuse_devicehub.devicehub import Devicehub @@ -77,7 +77,7 @@ def test_login_success(client: Client, app: Devicehub): uri='/users/login/', status=200) assert user['email'] == 'foo@foo.com' - assert UUID(b64decode(user['token'].encode()).decode()[:-1]) + assert UUID(auth.Auth.decode(user['token'])) assert 'password' not in user assert user['individuals'][0]['name'] == 'Timmy' assert user['individuals'][0]['type'] == 'Person'